cubeIDE开发, stm32的USB从设备串口驱动设计

news/2024/5/13 21:35:05/文章来源:https://blog.csdn.net/py8105/article/details/128235340

一、USB_OTG简介

        USB_OTG(OTG,ON THE GO)是一款双角色设备(DRD) 控制器,同时支持从机(USB DEVICE)功能和主机(USB HOST)功能。在主机模式下,OTG 支持全速(OTG_FS,12 Mb/s)和低速(OTG_LS,1.5 Mb/s)收发器,而从机模式下则仅支持全速(FS,12 Mb/s)收发器。主机模式下需要的唯一外部设备是提供VBUS的电荷泵。在驱动实现层面,USB OTG是USB Device和USB Host 的基础。在实际使用,USB OTG是USB Device和USB Host 的底层驱动。

        stm32芯片的通常USB物理接口管理两个引脚:

            DP/DM:内置上下拉,由控制器来设置不同类型的需求

        OTG实现时,额外配置ID引脚:
            ID:检测插入的线是B端还是A端,用于区分A类和B类设备,

        USB Host 模式下,需加配置Vbus引脚:
            Vbus:内置检测器,用于测试UBUS的有效性

        额外地需要支持SOF和NOF时,需要加配置SOF和NOF引脚。

        例如本文采用的STM32L496VGT3芯片,其配置支持到的引脚如下:

USB协议栈的层次划分

    一个Host可能有一个或者多个Device
    一个Device可能有一个或者多个Interface
    一个Interface可能有一个或者多个Endpoint

        Host(主机)连的是Device(设备),这一层是走物理连接的,也就是信号线实际连接两台设备。

        Device(设备)下可能有多个Interfece(接口),从这开始是逻辑概念,一个Interface,就是一个独立的功能接口,每个Interface模拟一个设备功能,比如集成了键盘和鼠标的USB设备,里面就是两个interface,一个是键盘,另一个是鼠标。Interface之间通常是隔离的,互相不干扰。
        每个Interface(接口)下面有一个或者多个Endpoint(端点),这也是逻辑概念,例如控制信号端口、数据信号端口等。端点是USB设备通信的基本单位,所有通信几乎都是从端点发起的。

二、创建工程及USB_Device配置

        本博文基于STM32L496VGTX3芯片实现,参考本专栏的博文:

cubeIDE开发, stm32的OLED点亮及字符显示设计(基于SPI通信)_py_free的博客-CSDN博客_stm32 hal spi oled

        基于该工程的(.ioc)文件创建了新工程stm32L496VGTx_USB,并移植了相关源码,实现了lpusart通信以及lcd显示字体。

        现打开工程的(.ioc)配置文件,进入cubeMX配置界面,开启USB_OTG_FS的USB Device功能,参数保持默认配置。

        确保USB_OTG_FS的中断功能已经开启。

         开启USB_OTG_FS的USB Device选项后,Middleware栏目可以去配置USB_Device信息,本文MCU作为USB_Device与笔记本电脑USB_HOST相连接,实现串口通信收发数据,因此选择通信类型虚拟串口功能,如下图所示,参数保持默认。

         设备描述符按默认设置:

         由于USB驱动引入了中间件代码,并比较复杂,需要更多缓存支持,现进入工程配置页面,调整min heap size和min stack size为合适的值,防止因数值较少而出现无法编译、编译异常、运行错误等情况出现。

         点击保存输出生成代码,关于USB_Device驱动相关代码如下,其中usb_cdc_if.h/c源码是用户可修改源文件:

 三、USB_Device驱动实现设计

        【1】在usb_cdc_if.h中,添加USB相关全局变量(接收缓存数组、最大长度、接收标记及长度)

/* USER CODE BEGIN INCLUDE */
#define USB_REC_LEN   256//定义USB串口最大接收字节数
extern uint8_t USB_RX_BUF[USB_REC_LEN];//接收缓冲,最大USB_REC_LEN个字节.末字节为换行符
extern uint16_t USB_RX_STA;//接收状态标记(接收到的有效字节数量)
/* USER CODE END INCLUDE */

        【2】在usb_cdc_if.h中,添加USB打印输出函数USB_printf声明

/* USER CODE BEGIN EXPORTED_VARIABLES */
void USB_printf(const char *format,  ...);//USB模拟串口的打印函数
/* USER CODE END EXPORTED_VARIABLES */

        【3】在usb_cdc_if.c中,调整USB接收函数

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{/* USER CODE BEGIN 6 *///新增代码开始处if(*Len<USB_REC_LEN)//判断收到数据量是否小于寄存器上限{uint16_t i;USB_RX_STA = *Len;//将数据量值放入标志位for(i=0;i<*Len;i++)//循环(循环次数=数据数量)USB_RX_BUF[i] = Buf[i];//将数据内容放入数据寄存器}//新增代码结束处USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);USBD_CDC_ReceivePacket(&hUsbDeviceFS);return (USBD_OK);/* USER CODE END 6 */
}

        【4】在usb_cdc_if.c中,调整USB发送函数

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{uint8_t result = USBD_OK;/* USER CODE BEGIN 7 *///注释旧代码
//  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
//  if (hcdc->TxState != 0){
//    return USBD_BUSY;
//  }
//  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
//  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);//新增新代码uint32_t TimeStart = HAL_GetTick();USBD_CDC_HandleTypeDef *hcdc =  (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;while(hcdc->TxState){if(HAL_GetTick()-TimeStart > 10)return USBD_BUSY;elsebreak;}USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf,  Len);result =  USBD_CDC_TransmitPacket(&hUsbDeviceFS);TimeStart = HAL_GetTick();while(hcdc->TxState){if(HAL_GetTick()-TimeStart > 10)return USBD_BUSY;}/* USER CODE END 7 */return result;
}

        【5】在usb_cdc_if.c中,实现USB打印输出函数USB_printf定义

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
#include <stdarg.h>
void USB_printf(const char *format, ...)//USB模拟串口的打印函数
{va_list args;uint32_t length;va_start(args, format);length = vsnprintf((char  *)UserTxBufferFS, APP_TX_DATA_SIZE, (char  *)format, args);va_end(args);CDC_Transmit_FS(UserTxBufferFS, length);
}
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

        【6】在main.c文件中,添加USB驱动头文件支持

/* USER CODE BEGIN Includes */
#include "../../ICore/led/led.h"
#include "../../ICore/oled/oled.h"
#include "../../USB_DEVICE/App/usbd_cdc_if.h"
/* USER CODE END Includes */

        【7】在main主函数初始化处

  /* USER CODE BEGIN 2 */OLED_init();//设置OLED蓝色背景显示BSP_LCD_Clear_DMA(LCD_DISP_BLUE);printf("OLED_Clear_DMA\r\n");/* USER CODE END 2 */

         【8】在main主函数循环体内实现

  /* USER CODE BEGIN WHILE */while (1){//USB模拟串口的查寻接收处理(其编程原理与USART1串口收发相同)if(USB_RX_STA!=0)//判断是否有数据{OLED_printf(10,42,"%.*s",USB_RX_STA, USB_RX_BUF);Toggle_led1();USB_RX_STA=0;//数据标志位清0memset(USB_RX_BUF,0,sizeof(USB_RX_BUF));//USB串口数据寄存器清0HAL_Delay(10);//等待}/* USER CODE END WHILE */

四、编译及下载

        编译下载,该开发板原理框图,需要将跳线帽重新插拔设置,相当于原理的USB-ST-LINK连接到USB_MCU上,即原理lpusart通信及ST-LINK下载的USB接口改为连接到USB_MCU的DM/DP引脚上实现通信。

         更改调线帽后,打开串口工具,发送数据,顺利在点(10,42)位置绘制输入文字,LED1等会切换状态。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_232521.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Springboot 替换/写入 word文档里面的文字、图片,1秒钟实现

前言 图片加水印&#xff1a;Springboot 图片需要添加水印&#xff0c;怎么办&#xff1f; 1秒就实现 那么word文档替换文字、插入图片&#xff0c;当然也是1秒钟了&#xff08;jar包引入&#xff0c;工具类代码复制粘贴&#xff0c;调试&#xff0c;完事&#xff09;。 事不…

[附源码]Python计算机毕业设计Djang基于vuejs的文创产品销售平台app

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

2022年国际工程行业研究报告

第一章 行业概况 国际工程是指一个工程项目从咨询、投资、招投标、承包(包括分包)、设备采购、培训到监理各个阶段的参与者来自不止一个国家&#xff0c;并且按照国际工程项目管理模式进行管理的工程。国际工程是一种综合性的国际经济合作方式&#xff0c;是国际技术贸易的一种…

2023年湖北监理工程师报考时间是什么时候?

2023年湖北监理工程师报考时间是什么时候&#xff1f; 监理工程师考试时间虽说是全国统一的&#xff0c;但是监理工程师报名时间不统一&#xff0c;每个省份自行安排报名时间&#xff0c;监理工程师报名时间基本都是在2.3月份开始报名&#xff0c;具体关注每个省人事考试院网站…

【爬虫5年保更新专栏】异步协程典型案例,一篇掌握~

最近收到 C 友反馈&#xff0c;说 《听说过 python 协程没&#xff1f;听说过 asyncio 库没&#xff1f;都在这一篇博客了》 这篇博客的目标图片站&#xff0c;已经不能使用了&#xff0c;橡皮擦查阅之后&#xff0c;发现是对方网站已经不运营了&#xff0c;所以更新一下案例。…

寻找适配网红很迷茫?最全秘笈来了

根据《2022年全球数字概览》报告显示&#xff0c;全球社交媒体用户超过46.2亿&#xff0c;相当于全球总人口的58.4%。全球用户每天在社交媒体上平均花费近2.5个小时&#xff0c;并且每天以2分钟的速度增长。 社交媒体成为全球网民生活中不可或缺的一部分&#xff0c;而对于跨境…

2022全年度冰箱十大热门品牌销量榜单

自2022年年初以来&#xff0c;各地纷纷部署支持包括冰箱在内的家电大宗消费政策措施&#xff0c;其中家电补贴政策是刺激家电消费的主旋律。宏观经济政策环境改善&#xff0c;利好冰箱行业的长期发展。 根据鲸参谋数据统计&#xff0c;今年京东平台冰箱的年度累计销量达到1400多…

有趣且重要的css知识合集(6)动态控制css伪元素【var()】

在vue里&#xff0c;js和css的属性可以随意控制&#xff0c;比如:class和:style&#xff0c;但是我们想要动态控制伪元素的属性该怎么做呢&#xff1f; 比如下图&#xff0c;右下角小圆圈就是通过伪元素定义上去的&#xff0c;那我们想要自由实现伪元素的显示和隐藏该怎么做呢…

研究一段WPF 3D 机械臂代码

网上下一段代码&#xff0c;运行如下&#xff1b;显示了一个3D机械臂&#xff1b; xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"&#xff0c;这是WPF命名空间&#xff0c;一般写在xaml头部&#xff0c;它的是这样的&#xff0c;<Viewport3D…

浅学Linux内核MMU

1 MMU基本知识 1.1 什么是MMU MMU是 MemoryManagementUnit 的缩写即&#xff0c;内存管理单元. 针对各种CPU, MMU是个可选的配件. MMU负责的是虚拟地址与物理地址的转换. 提供硬件机制的内存访问授权.&#xff08;现代 CPU 的应用中&#xff0c;基本上都选择了使用 MMU&#…

Kafka 为什么那么快?

有人说&#xff1a;他曾在一台配置较好的机子上对 Kafka 进行性能压测&#xff0c;压测结果是 Kafka 单个节点的极限处理能力接近每秒 2000万 条消息&#xff0c;吞吐量达到每秒 600MB。 那 Kafka 为什么这么快&#xff1f;如何做到这个高的性能&#xff1f; 本篇文章主要从这…

面试官:MySQL 中 varchar(n) 中 n 最大取值为多少?

前置知识 要回答这个问题&#xff0c;首先我们得先知道 MySQL 存储一条记录的格式长什么样子。 以 Compact 行格式作为例子&#xff0c;它长这样&#xff1a; 可以看到&#xff0c;一条完整的记录分为「记录的额外信息」和「记录的真实数据」两个部分。 这里重点讲讲记录的…

安卓APP源码和设计报告——健身系统

一、设计背景 1.需求分析 对于很多人来说拥有一副好身材能让自己增添不少魅力;对于爱吃而又担心自己发胖的人来说适当的运动健身是最好的选择。移动互联网时代&#xff0c;市场上“约跑”“约健身”健身APP软件成为新时代闺蜜朋友的互动模式&#xff0c;健身热潮的来临&#…

MySQL分区详解

目录 一、定义 1.1 概述 1.2 分区的优势 二、分区的类型 2.1 检查MySQL是否支持分区 2.2 类型 2.3 分区的其他操作 一、定义 1.1 概述 数据库分区是一种物理数据库设计技术。虽然分区技术可以实现很多效果&#xff0c;但其主要目的是为了在特定的SQL操作中减少数据读写…

第17章 事件和概率空间

第17章 事件和概率空间 17.1 做个交易吧 假设你有三扇门可供选择。其中一扇门背后是一辆汽车&#xff0c;另外两扇门背后是一只山羊。你选择了一扇门&#xff0c;比如1号门。然后知道门后面有什么的主持人&#xff0c;开启了另一扇后面有山羊的门&#xff0c;假设是3号门。现…

The reference to entity “useSSL“ must end with the ‘;‘ delimiter.

The reference to entity "useSSL" must end with the ; delimiter.& 替换为 &amp; < 替换为 < > 替换为 > " 替换为 &quot;替换为 &apos; jdbc:mysql://127.0.0.1:3306/dbname?characterEncodingutf8&amp;useSSLfalse&am…

Redis vs MongoDB

Redis vs MongoDB 通常情况下&#xff0c;应用系统的技术选型&#xff0c;对于如何选择非关系型数据库&#xff0c;是一个不小的挑战。这不仅考验架构师在技术上的广度和深度&#xff0c;同时也考究对业务细节了解和熟悉程度。只有将业务场景、业务特点、数据特征跟具体的技术…

Qt 多线程之QtConcurrent::map(处理序列容器)

QtConcurrent::map()、QtConcurrent::mapped() 和 QtConcurrent::mappedReduced() 函数对一个序列中&#xff08;例如&#xff1a;QList、QVector&#xff09;的项目并行地进行计算。 1、map函数 map函数的功能是在其他线程运行指定的函数&#xff0c;map函数有两个参数 第一…

玩好.NET高级调试,你也要会写点汇编

一&#xff1a;背景 1. 简介 .NET 高级调试要想玩的好&#xff0c;看懂汇编是基本功&#xff0c;但看懂汇编和能写点汇编又完全是两回事&#xff0c;所以有时候看的多&#xff0c;总手痒痒想写一点&#xff0c;在 Windows 平台上搭建汇编环境不是那么容易&#xff0c;大多还是…

web课程设计:HTML非遗文化网页设计题材【京剧文化】HTML+CSS+JavaScript

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…