匿名
未登录
登录
丢石头百科
搜索
查看“STM32CubeMX系列教程25:USB Device”的源代码
来自丢石头百科
名字空间
页面
讨论
更多
更多
页面选项
查看
查看源代码
历史
←
STM32CubeMX系列教程25:USB Device
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看与复制此页面的源代码。
本章不打算详细讲解USB的协议,本章只是介绍如何通过STM32CubeMX软件生成应用程序。 在看本教程之前建议先看ST官方关于USB的培训视频,示例 http://www.stmcu.com.cn/videos.html <b>一、USB简介</b> stm32F746系列芯片有USB_OTG_FS和USB_OTG_HS两种接口,FS为全速,速度12M Bit/s,HS为高速,最高速度为480M Bit/s,此时需要外接USB HS PHY,例如USB3300。HS接口也可以作为FS接口使用。由于FS和HS接口使用是相同的USB设备库,只是初始化时配置的引脚不一样,本章以FS接口为例讲解USB设备库的使用。以下为USB OTG FS的电路图: [[File:171401zu4pad64d446f8fo.png]] USB只要由USB_DM和USB_DP两根线差分传输。OTG_ID线用来判断为主设备或时从设备的,作为OTG设备的时候使用。MIC2025/75为USB电源管理芯片,当作为设备是,从外部取电源,VBUSEN(PE2)要设置为高。当作为主机时,要拉低,USB口输出电压给从设备。 <b>二、USB CDC</b> 这一节介绍usb作为通讯设备类(Communication Device Class),通过USB虚拟串口通信。程序在LCD滚动显示字符工程的基础上修改,<b style="font-size: 14.4px; line-height: 1.5;"><b style="font-size: 14px;">复制工程修改文件夹名。<b><b style="font-size: 14px;">打开</b></b></b></b><b style="font-size: 14.4px; line-height: 1.5;"><b style="font-size: 14px;"><b><b style="font-size: 14px;">STM32cubeMX</b></b></b></b><b style="font-size: 14.4px; line-height: 1.5;"><b style="font-size: 14px;"><b><b style="font-size: 14px;">的工程文件重新配置,USB_OTG_FS选择设备。</b></b></b></b> [[File:171402a8r6z0tcuus1l8ut.png]] 配置系统时钟为216MHz,USB的时钟频率为48MHz. [[File:171402z3tcdw2yii66z6ux.png]] 开启USB中间件,选择虚拟串口。 [[File:171402t13upcg1ygmwryp1.png]] USB参数配置中 VBUS sensing 选择失能,其他为默认设置。 [[File:171402bicfkkixxmklcnci.png]] 中间件USB设备配置也不用修改,默认的配置。 [[File:171403vq06038q3vm0iqns.png]] 设备描述符设置也不需修改,为默认设置。 [[File:171403j3q3r2ic8zm2zagn.png]] 软件会默认开启USB中断,此处也为默认优先级,不作修改。 [[File:171403phhhyd8kmtmymfmt.png]] <b style="font-family: 微软雅黑; font-size: 14px;"><b style="font-size: 14px;">生成报告以及初始化代码,编译程序。工程中多出如下文件,其中最后四个为USB设备的库文件。</b></b> [[File:171404xd22akf4fc4f44x2.png]] usb_device.c里面仅包含一个USB设备函数初始化函数 MX_USB_DEVICE_Init(),在程序开始时调用。 usbd_cdc_if.c为USB的CDC类应用层文件,里面包含虚拟串口的接收,发送和控制等函数。 usb_desc.c包含USB的描述符,以及USB枚举处理等函数。 usb_conf.com为USB管脚配置文件,包含引USB引脚初始化以及参数设置,中断回调函数等。 打开usbd_cdc_if.c文件,找到虚拟串口接收函数。 <syntaxhighlight lang="python"> static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) { /* USER CODE BEGIN 6 */ USBD_CDC_SetRxBuffer(hUsbDevice_0, &Buf[0]); USBD_CDC_ReceivePacket(hUsbDevice_0); return (USBD_OK); /* USER CODE END 6 */ }</syntaxhighlight> 修改接收处理函数,接收到的字符打印输出在LCD屏幕上。 <syntaxhighlight lang="python"> </syntaxhighlight> <syntaxhighlight lang="python"> <syntaxhighlight lang="python"> static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) { /* USER CODE BEGIN 6 */ uint8_t result = USBD_OK; uint8_t msg[Len[0]+1]; uint32_t i; result = USBD_CDC_ReceivePacket(&hUsbDeviceFS); for(i=0;i<len buf="" code="" end="" msg="" pre="" printf="" result="" return="" user=""></len></syntaxhighlight> </syntaxhighlight> 如下为发送函数,程序中先设置发送字符,然后发送包。这里注意一点,Cube软件初始化的USB结构体是hUsbDeviceFS,这里操作的结构体是hUsbDevice_0。故这个函数不能直接调用,必须先CDC_Init_FS()函数初始化才能用这个函数,初始化中包含有这个语句hUsbDevice_0 = &hUsbDeviceFS。 <syntaxhighlight lang="python"> <syntaxhighlight lang="python"> uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) { uint8_t result = USBD_OK; /* USER CODE BEGIN 7 */ USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len); result = USBD_CDC_TransmitPacket(hUsbDevice_0); /* USER CODE END 7 */ return result; }</syntaxhighlight> </syntaxhighlight> 本教程不调用这个发送函数。在main函数中while循环中添加语法每秒发送一次字符串。 <syntaxhighlight lang="python"> /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ USBD_CDC_SetTxBuffer(&hUsbDeviceFS, (uint8_t*)&UserTxBuffer, sizeof(UserTxBuffer)); USBD_CDC_TransmitPacket(&hUsbDeviceFS); HAL_Delay(1000); } /* USER CODE END 3 */</syntaxhighlight> 在前面声明发送字符串。 <syntaxhighlight lang="python"> /* USER CODE BEGIN 1 */ uint8_t UserTxBuffer[] = "WaveShare Open7XXI-C Board STM32 Virtual COM Port Driver \r\n"; /* USER CODE END 1 */</syntaxhighlight> 在main函数中,while循环前面添加程式初始化LCD。 <syntaxhighlight lang="python"> /* USER CODE BEGIN 2 */ /* Initialize the SDRAM */ BSP_SDRAM_Init(); /* Initialize the LCD */ BSP_LCD_Init(); BSP_LCD_SetLayerVisible(1, DISABLE); BSP_LCD_SelectLayer(0); /* Initialize LCD Log module */ LCD_LOG_Init(); /* Show Header and Footer texts */ LCD_LOG_SetHeader((uint8_t *)"Waveshare Electronics"); LCD_LOG_SetFooter((uint8_t *)"WaveShare Open7XXI-C board"); /* USER CODE END 2 */</syntaxhighlight> 最后添加usbd_cdc.h头文件。 <syntaxhighlight lang="python"> /* USER CODE BEGIN Includes */ #include "stm32746g_sdram.h" #include "stm32746g_LCD.h" #include "lcd_log.h" #include "usbd_cdc.h" /* USER CODE END Includes */ </syntaxhighlight> 最后编译程序,并下载到开发板,电脑usb线接到Open746I-C的核心板的USB接口中。打开串口助手会接到开发板发送的字符串,串口助手发送的字符会在LCD上显示。设置的串口传输格式是无效的,程序中没有设置串口传输格式,可以修改usbd_cdc_if.c文件的CDC_Control_FS()函数设置。 注:电脑要安装ST虚拟串口驱动才能设别虚拟串口。如下为虚拟串口驱动: <a class="attach" href="portal.php?mod=attachment&id=613" target="_blank">stsw.zip <b>三、USB HID</b> 本节介绍USB作为人机接口设备(Human Interface Device),开发板模拟鼠标设备。 复制上一节的工程文件,<b style="font-family: 微软雅黑; font-size: 14.4px;"><b style="font-size: 14px;">修改文件夹名。<b><b style="font-size: 14px;">打开</b></b></b></b><b style="font-family: 微软雅黑; font-size: 14.4px;"><b style="font-size: 14px;"><b><b style="font-size: 14px;">STM32cubeMX</b></b></b></b><b style="font-family: 微软雅黑; font-size: 14.4px;"><b style="font-size: 14px;"><b><b style="font-size: 14px;">的工程文件重新配置,USB_OTG_FS选择设备,USB设备选择Human Interface Device。</b></b></b></b> [[File:171404rds53sv5d6wg8p8s.png]] <b> </b> [[File:171404kcsmaasb19sbt15r.png]] USB参数配置中 VBUS sensing 选择失能,其他为默认设置。 [[File:171404w2bgec13cib1h3dj.png]] USB设备中间层不需要修改,为默认设置。 [[File:171405lfz52fp1kop475p4.png]] [[File:171405sq5cfd5hsidc5qvz.png]] <b style="font-family: 微软雅黑; font-size: 14px;"><b style="font-size: 14px;">生成报告以及初始化代码,编译程序。工程中多出如下文件,其中最后四个为USB设备的库文件。</b></b> <b style="font-family: 微软雅黑; font-size: 14px;"><b style="font-size: 14px;"> </b></b> [[File:171405h11ef22152leahd2.png]] 和前面的CDC对比一下,发现USB设备库文件中,usbd_cdc.c替换为usbd_hid.c文件。usbd_cdc_if.c为CDC应用层文件也去掉了。 删掉原来的应用程序,重新编写应用程序。在main.c文件最后面添加应用程序。程序GetPointerData()为读取五向摇杆按键状态更新坐标,CURSOR_STEP为每次移动的步长,输入参数为当前的坐标位置。 <syntaxhighlight lang="python"> /* USER CODE BEGIN 4 */ /** * @brief Gets Pointer Data. * @param pbuf: Pointer to report * @retval None */ static void GetPointerData(uint8_t *pbuf) { int8_t x = 0, y = 0 ; switch(BSP_JOY_GetState()) { case JOY_LEFT: x -= CURSOR_STEP; break; case JOY_RIGHT: x += CURSOR_STEP; break; case JOY_UP: y -= CURSOR_STEP; break; case JOY_DOWN: y += CURSOR_STEP; break; default: break; } pbuf[0] = 0; pbuf[1] = x; pbuf[2] = y; pbuf[3] = 0; } /** * @brief SYSTICK callback. * @retval None */ void HAL_SYSTICK_Callback(void) { /* NOTE : This function Should not be modified, when the callback is needed, the HAL_SYSTICK_Callback could be implemented in the user file */ static __IO uint32_t counter=0; /* check Joystick state every polling interval (10ms) */ if (counter++ == USBD_HID_GetPollingInterval(&hUsbDeviceFS)) { GetPointerData(HID_Buffer); /* send data though IN endpoint*/ if((HID_Buffer[1] != 0) || (HID_Buffer[2] != 0)) { USBD_HID_SendReport(&hUsbDeviceFS, HID_Buffer, 4); } counter =0; } BSP_LED_Toggle(LED1); } /* USER CODE END 4 */</syntaxhighlight> HAL_SYSTICK_Callback()为SysTick定时器中断回调函数,时间为1ms。程序中先调用USBD_HID_GetPollingInterval函数读取HID轮询间隔。每隔10MS根据五向摇杆按键更新坐标,并通过USB发到电脑。 添加变量声明 <syntaxhighlight lang="python"> /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ #define CURSOR_STEP 5 uint8_t HID_Buffer[4]; /* USER CODE END PV */</syntaxhighlight> <syntaxhighlight lang="python"> </syntaxhighlight> <syntaxhighlight lang="python"> </syntaxhighlight>添加usbd_hid.h头文件 <syntaxhighlight lang="python"> </syntaxhighlight> <syntaxhighlight lang="python"> <syntaxhighlight lang="python"> /* USER CODE BEGIN Includes */ #include "stm32746g_sdram.h" #include "stm32746g_LCD.h" #include "lcd_log.h" #include "usbd_hid.h" /* USER CODE END Includes */</syntaxhighlight> </syntaxhighlight> <syntaxhighlight lang="python"> </syntaxhighlight> <syntaxhighlight lang="python"> 编译程序,并下载到开发板,电脑usb线接到Open746I-C的核心板的USB接口中。按五向遥控按键电脑上的鼠标会移动。 <b style="color: rgb(0, 0, 0); font-family: 微软雅黑; font-size: medium;">三、USB MSC</b> </syntaxhighlight> <b style="color: rgb(0, 0, 0); font-family: 微软雅黑;"> </b> <b style="color: rgb(0, 0, 0); font-family: 微软雅黑;"> </b>本节介绍USB大容量存储设备类(Mass Storage Class),开<b style="color: rgb(0, 0, 0); font-family: 微软雅黑;"> 发板作为U盘,用SDMMC接SD卡存储数据。</b><b style="color: rgb(0, 0, 0); font-family: 微软雅黑; font-size: medium;"> 复制上一节CDC的工程文件,<b style="font-size: 14.4px;"><b style="font-size: 14px;">修改文件夹名。<b><b style="font-size: 14px;">打开</b></b></b></b><b style="font-size: 14.4px;"><b style="font-size: 14px;"><b><b style="font-size: 14px;">STM32cubeMX</b></b></b></b><b style="font-size: 14.4px;"><b style="font-size: 14px;"><b><b style="font-size: 14px;">的工程文件重新配置,USB_OTG_FS选择设备,USB设备选择Mass Storage Class。</b></b></b></b></b> [[File:171406gragc6iligcsrrr1.png]] 选择SDMMC接口为4线。 [[File:171406wqo3129b0df9a21b.png]] 配置系统时钟频率为216MHZ,USB,SDMMC频率均为48MHz。 [[File:171406fpl63gbbb00sxgmf.png]] SDMMC添加收发DMA,其他为默认不作修改。 [[File:171407u131u9la45ll8h4o.png]] 开启SDMMC中断,注意必须开启SDMMC中断,SDMMC的DMA才能正常工作,而且SDMMC中断优先级要比DMA中断要高,且比USB中断高。 [[File:171410a0kzykilyiyjkjxt.png]] 增大堆栈空间的大小,否则会程序会触发硬件错误中断(HardFault)。 [[File:171411wucuw3hh0hvqr3j5.png]] <b style="font-family: 微软雅黑; font-size: 14px;"><b style="font-size: 14px;">生成报告以及初始化代码,编译程序。工程中多出如下文件,其中最后七个为USB设备的库文件。</b></b> [[File:171411oxd4k3k04bs9130x.png]] 其中usbd_storage_if为应用层文件,里面为USB大容量存储设备类底层操作,包括获取存储器容量,块读写等操作。实际上usbd_storage_if里面这些操作都是空的,需要我们移植底层。由于SD的操作是由电脑同过USB镜像操作的,故开发板程序是不需要移植文件系统的,我们只需在usbd_storage_if文件中添加SD卡的底层操作既可。 打开usbd_storage_if文件,我们只需修改三个函数既可,第一个是获取存储器容量大小函数,返回块大小,已经块数目。 <syntaxhighlight lang="python"> /******************************************************************************* * Function Name : STORAGE_GetCapacity_FS * Description : * Input : None. * Output : None. * Return : None. *******************************************************************************/ int8_t STORAGE_GetCapacity_FS (uint8_t lun, uint32_t *block_num, uint16_t *block_size) { /* USER CODE BEGIN 3 */ HAL_SD_CardInfoTypedef info; int8_t ret = USBD_FAIL; // if(BSP_SD_IsDetected() != SD_NOT_PRESENT) { HAL_SD_Get_CardInfo(&hsd1, &info); *block_num = (info.CardCapacity)/STORAGE_BLK_SIZ - 1; *block_size = info.CardBlockSize; ret = USBD_OK; } return ret; /* USER CODE END 3 */ }</syntaxhighlight> 第二个是块读取函数,SD卡是通过DMA传输数据。 <syntaxhighlight lang="python"> /******************************************************************************* * Function Name : STORAGE_Read_FS * Description : * Input : None. * Output : None. * Return : None. *******************************************************************************/ int8_t STORAGE_Read_FS (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { /* USER CODE BEGIN 6 */ int8_t ret = USBD_FAIL; // if(BSP_SD_IsDetected() != SD_NOT_PRESENT) { /* Read block(s) in DMA transfer mode */ if(HAL_SD_ReadBlocks_DMA(&hsd1,(uint32_t *)buf, blk_addr * STORAGE_BLK_SIZ, STORAGE_BLK_SIZ, blk_len) == SD_OK) { ret = USBD_OK; } /* Wait until transfer is complete */ if(ret == USBD_OK) { if(HAL_SD_CheckReadOperation(&hsd1, (uint32_t)100000000) != SD_OK) { ret = USBD_FAIL; } else { ret = USBD_OK; } } ret = USBD_OK; } return ret; /* USER CODE END 6 */ } </syntaxhighlight> <syntaxhighlight lang="python"> 第三个是写操作函数</syntaxhighlight> <syntaxhighlight lang="python"> <syntaxhighlight lang="python"> /******************************************************************************* * Function Name : STORAGE_Write_FS * Description : * Input : None. * Output : None. * Return : None. *******************************************************************************/ int8_t STORAGE_Write_FS (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { /* USER CODE BEGIN 7 */ int8_t ret = USBD_FAIL; // if(BSP_SD_IsDetected() != SD_NOT_PRESENT) { /* Write block(s) in DMA transfer mode */ if(HAL_SD_WriteBlocks_DMA(&hsd1, (uint32_t *)buf, blk_addr * STORAGE_BLK_SIZ, STORAGE_BLK_SIZ, blk_len) == SD_OK) { ret = USBD_OK; } /* Wait until transfer is complete */ if(ret == USBD_OK) { if(HAL_SD_CheckWriteOperation(&hsd1, (uint32_t)100000000) != SD_OK) { ret = USBD_FAIL; } else { ret = USBD_OK; } } } return ret; /* USER CODE END 7 */ }</syntaxhighlight> </syntaxhighlight> <syntaxhighlight lang="python"> </syntaxhighlight> 注意:Open746I-C中可以通过PC13管脚判断SD卡是否插入到卡槽中,这里为了方便没有用到这个功能。所以上面程序中注释掉了检测SD卡是否准备好这一步。 [[File:171411yjwcq6dww6jwl7pw.png]] 编译程序,并下载到开发板,电脑usb线接到Open746I-C的核心板的USB接口中。电脑会提示有U盘插入。
返回至
STM32CubeMX系列教程25:USB Device
。
导航
导航
首页
最近更改
随机页面
MediaWiki帮助
首页
首页
树莓派
主机
配件包
外壳
键鼠
电源
扩展板
显示屏
墨水屏
摄像模块
通信模块
继电器
电机驱动板
游戏机
产品分类
树莓派
Arduino
micro:bit
STM32
Espressif
WiFi模块
蓝牙模块
无线模块
LoRa模块
4G模块
GSM
GPRS
以太网
导航模块
北斗卫星
GPS
LCD
墨水屏
OLED
摄像头
USB模块
串口模块
RS232
RS485
CAN
传感器
温度模块
湿度模块
气压模块
继电器
电机模块
指纹模块
电平转换
音频模块
编程器
Wiki工具
Wiki工具
特殊页面
页面工具
页面工具
用户页面工具
更多
链入页面
相关更改
页面信息
页面日志