STM32CubeMX系列教程25:USB Device

2023-11-01 164浏览
百检网是一家专业的第三方检测平台,汇聚众多拥有权威资质的第三方检测机构为你提供一站式的检测服务,做检测就上百检网。百检网让检测从此检测,一份报告全国通用,专业值得信赖。

本章不打算详细讲解USB的协议,本章只是介绍如何通过STM32CubeMX软件生成应用程序。

在看本教程之前建议先看ST官方关于USB的培训视频,示例

http://www.stmcu.com.cn/videos.html

一、USB简介

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的电路图:

USB只要由USB_DM和USB_DP两根线差分传输。OTG_ID线用来判断为主设备或时从设备的,作为OTG设备的时候使用。MIC2025/75为USB电源管理芯片,当作为设备是,从外部取电源,VBUSEN(PE2)要设置为高。当作为主机时,要拉低,USB口输出电压给从设备。

二、USB CDC

这一节介绍usb作为通讯设备类(Communication Device Class),通过USB虚拟串口通信。程序在LCD滚动显示字符工程的基础上修改,复制工程修改文件夹名。打开STM32cubeMX的工程文件重新配置,USB_OTG_FS选择设备。

配置系统时钟为216MHz,USB的时钟频率为48MHz.

开启USB中间件,选择虚拟串口。

USB参数配置中 VBUS sensing 选择失能,其他为默认设置。

中间件USB设备配置也不用修改,默认的配置。

设备描述符设置也不需修改,为默认设置。

软件会默认开启USB中断,此处也为默认优先级,不作修改。

生成报告以及初始化代码,编译程序。工程中多出如下文件,其中*后四个为USB设备的库文件。

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文件,找到虚拟串口接收函数。1staticint8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)2{3/* USER CODE BEGIN 6 */4USBD_CDC_SetRxBuffer(hUsbDevice_0, &Buf[0]);5USBD_CDC_ReceivePacket(hUsbDevice_0);6return(USBD_OK);7/* USER CODE END 6 */8}

修改接收处理函数,接收到的字符打印输出在LCD屏幕上。

1staticint8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)2{3/* USER CODE BEGIN 6 */4uint8_t result = USBD_OK;5uint8_t msg[Len[0]+1];6uint32_t i;7result = USBD_CDC_ReceivePacket(&hUsbDeviceFS);8for(i=0;i

如下为发送函数,程序中先设置发送字符,然后发送包。这里注意一点,Cube软件初始化的USB结构体是hUsbDeviceFS,这里操作的结构体是hUsbDevice_0。故这个函数不能直接调用,必须先CDC_Init_FS()函数初始化才能用这个函数,初始化中包含有这个语句hUsbDevice_0=&hUsbDeviceFS。

1uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)2{3uint8_t result = USBD_OK;4/* USER CODE BEGIN 7 */5USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len);6result = USBD_CDC_TransmitPacket(hUsbDevice_0);7/* USER CODE END 7 */8returnresult;9}

本教程不调用这个发送函数。在main函数中while循环中添加语法每秒发送一次字符串。

01/* USER CODE BEGIN WHILE */02while(1)03{04/* USER CODE END WHILE */0506/* USER CODE BEGIN 3 */07USBD_CDC_SetTxBuffer(&hUsbDeviceFS, (uint8_t*)&UserTxBuffer,sizeof(UserTxBuffer));08USBD_CDC_TransmitPacket(&hUsbDeviceFS);0910HAL_Delay(1000);11}12/* USER CODE END 3 */

在前面声明发送字符串。1/* USER CODE BEGIN 1 */2uint8_t UserTxBuffer[] ="WaveShare Open7XXI-C Board STM32 Virtual COM Port Driver rn";3/* USER CODE END 1 */

在main函数中,while循环前面添加程式初始化LCD。01/* USER CODE BEGIN 2 */02/* Initialize the SDRAM */03BSP_SDRAM_Init();04/* Initialize the LCD */05BSP_LCD_Init();0607BSP_LCD_SetLayerVisible(1, DISABLE);08BSP_LCD_SelectLayer(0);0910/* Initialize LCD Log module */11LCD_LOG_Init();1213/* Show Header and Footer texts */14LCD_LOG_SetHeader((uint8_t *)"Waveshare Electronics");15LCD_LOG_SetFooter((uint8_t *)"WaveShare Open7XXI-C board");16/* USER CODE END 2 */

*后添加usbd_cdc.h头文件。

1/* USER CODE BEGIN Includes */2#include "stm32746g_sdram.h"3#include "stm32746g_LCD.h"4#include "lcd_log.h"5#include "usbd_cdc.h"6/* USER CODE END Includes */

*后编译程序,并下载到开发板,电脑usb线接到Open746I-C的核心板的USB接口中。打开串口助手会接到开发板发送的字符串,串口助手发送的字符会在LCD上显示。设置的串口传输格式是无效的,程序中没有设置串口传输格式,可以修改usbd_cdc_if.c文件的CDC_Control_FS()函数设置。

注:电脑要安装ST虚拟串口驱动才能设别虚拟串口。

三、USB HID

本节介绍USB作为人机接口设备(Human Interface Device),开发板模拟鼠标设备。

复制上一节的工程文件,修改文件夹名。打开STM32cubeMX的工程文件重新配置,USB_OTG_FS选择设备,USB设备选择Human Interface Device。

USB参数配置中 VBUS sensing 选择失能,其他为默认设置。

USB设备中间层不需要修改,为默认设置。

生成报告以及初始化代码,编译程序。工程中多出如下文件,其中*后四个为USB设备的库文件。

和前面的CDC对比一下,发现USB设备库文件中,usbd_cdc.c替换为usbd_hid.c文件。usbd_cdc_if.c为CDC应用层文件也去掉了。

删掉原来的应用程序,重新编写应用程序。在main.c文件*后面添加应用程序。程序GetPointerData()为读取五向摇杆按键状态更新坐标,CURSOR_STEP为每次移动的步长,输入参数为当前的坐标位置。

01/* USER CODE BEGIN 4 */02/**03* @brief Gets Pointer Data.04* @param pbuf: Pointer to report05* @retval None06*/07staticvoidGetPointerData(uint8_t *pbuf)08{09int8_t x = 0, y = 0 ;1011switch(BSP_JOY_GetState())12{13caseJOY_LEFT:14x -= CURSOR_STEP;15break;1617caseJOY_RIGHT:18x += CURSOR_STEP;19break;2021caseJOY_UP:22y -= CURSOR_STEP;23break;2425caseJOY_DOWN:26y += CURSOR_STEP;27break;2829default:30break;31}32pbuf[0] = 0;33pbuf[1] = x;34pbuf[2] = y;35pbuf[3] = 0;36}3738/**39* @brief SYSTICK callback.40* @retval None41*/42voidHAL_SYSTICK_Callback(void)43{44/* NOTE : This function Should not be modified, when the callback is needed,45the HAL_SYSTICK_Callback could be implemented in the user file46*/47static__IO uint32_t counter=0;48/* check Joystick state every polling interval (10ms) */49if(counter++ == USBD_HID_GetPollingInterval(&hUsbDeviceFS))50{51GetPointerData(HID_Buffer);5253/* send data though IN endpoint*/54if((HID_Buffer[1] != 0) || (HID_Buffer[2] != 0))55{56USBD_HID_SendReport(&hUsbDeviceFS, HID_Buffer, 4);57}58counter =0;59}60BSP_LED_Toggle(LED1);61}62/* USER CODE END 4 */

HAL_SYSTICK_Callback()为SysTick定时器中断回调函数,时间为1ms。程序中先调用USBD_HID_GetPollingInterval函数读取HID轮询间隔。每隔10MS根据五向摇杆按键更新坐标,并通过USB发到电脑。

添加变量声明

1/* USER CODE BEGIN PV */2/* Private variables ---------------------------------------------------------*/3#define CURSOR_STEP 54uint8_t HID_Buffer[4];5/* USER CODE END PV */

添加usbd_hid.h头文件

1/* USER CODE BEGIN Includes */2#include "stm32746g_sdram.h"3#include "stm32746g_LCD.h"4#include "lcd_log.h"5#include "usbd_hid.h"6/* USER CODE END Includes */

编译程序,并下载到开发板,电脑usb线接到Open746I-C的核心板的USB接口中。按五向遥控按键电脑上的鼠标会移动。

三、USB MSC

本节介绍USB大容量存储设备类(Mass Storage Class),开

发板作为U盘,用SDMMC接SD卡存储数据。

复制上一节CDC的工程文件,修改文件夹名。打开STM32cubeMX的工程文件重新配置,USB_OTG_FS选择设备,USB设备选择Mass Storage Class。

选择SDMMC接口为4线。

配置系统时钟频率为216MHZ,USB,SDMMC频率均为48MHz。

SDMMC添加收发DMA,其他为默认不作修改。

开启SDMMC中断,注意必须开启SDMMC中断,SDMMC的DMA才能正常工作,而且SDMMC中断优先级要比DMA中断要高,且比USB中断高。

增大堆栈空间的大小,否则会程序会触发硬件错误中断(HardFault)。

生成报告以及初始化代码,编译程序。工程中多出如下文件,其中*后七个为USB设备的库文件。

其中usbd_storage_if为应用层文件,里面为USB大容量存储设备类底层操作,包括获取存储器容量,块读写等操作。实际上usbd_storage_if里面这些操作都是空的,需要我们移植底层。由于SD的操作是由电脑同过USB镜像操作的,故开发板程序是不需要移植文件系统的,我们只需在usbd_storage_if文件中添加SD卡的底层操作既可。

打开usbd_storage_if文件,我们只需修改三个函数既可,**个是获取存储器容量大小函数,返回块大小,已经块数目。

01/*******************************************************************************02* Function Name : STORAGE_GetCapacity_FS03* Description :04* Input : None.05* Output : None.06* Return : None.07*******************************************************************************/08int8_t STORAGE_GetCapacity_FS (uint8_t lun, uint32_t *block_num, uint16_t *block_size)09{10/* USER CODE BEGIN 3 */11HAL_SD_CardInfoTypedef info;12int8_t ret = USBD_FAIL;1314// if(BSP_SD_IsDetected() != SD_NOT_PRESENT)15{1617HAL_SD_Get_CardInfo(&hsd1, &info);18*block_num = (info.CardCapacity)/STORAGE_BLK_SIZ - 1;19*block_size = info.CardBlockSize;20ret = USBD_OK;21}22returnret;23/* USER CODE END 3 */24}

第二个是块读取函数,SD卡是通过DMA传输数据。

01/*******************************************************************************02* Function Name : STORAGE_Read_FS03* Description :04* Input : None.05* Output : None.06* Return : None.07*******************************************************************************/08int8_t STORAGE_Read_FS (uint8_t lun,09uint8_t *buf,10uint32_t blk_addr,11uint16_t blk_len)12{13/* USER CODE BEGIN 6 */14int8_t ret = USBD_FAIL;1516// if(BSP_SD_IsDetected() != SD_NOT_PRESENT)17{18/* Read block(s) in DMA transfer mode */19if(HAL_SD_ReadBlocks_DMA(&hsd1,(uint32_t *)buf, blk_addr * STORAGE_BLK_SIZ, STORAGE_BLK_SIZ, blk_len) == SD_OK)20{21ret = USBD_OK;22}2324/* Wait until transfer is complete */25if(ret == USBD_OK)26{27if(HAL_SD_CheckReadOperation(&hsd1, (uint32_t)100000000) != SD_OK)28{29ret = USBD_FAIL;30}31else32{33ret = USBD_OK;34}35}36ret = USBD_OK;37}38returnret;39/* USER CODE END 6 */40}


百检网秉承“客户至上,服务为先,精诚合作,以人为本”的经营理念,始终站在用户的角度解决问题,为客户提供“一站购物式”的新奇检测体验,打开网站,像挑选商品一样简单,方便。打破行业信息壁垒,建构消费和检测机构之间高效的沟通平台