首页 > 其他分享 >stm32的USB从设备串口驱动设计

stm32的USB从设备串口驱动设计

时间:2023-11-17 09:47:29浏览次数:28  
标签:CODE USB OTG stm32 USER 串口 Device

一、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;      else     break;   }   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;//数据标志位清0   memset(USB_RX_BUF,0,sizeof(USB_RX_BUF));//USB串口数据寄存器清0   HAL_Delay(10);//等待   }     /* USER CODE END WHILE */ 四、编译及下载         编译下载,该开发板原理框图,需要将跳线帽重新插拔设置,相当于原理的USB-ST-LINK连接到USB_MCU上,即原理lpusart通信及ST-LINK下载的USB接口改为连接到USB_MCU的DM/DP引脚上实现通信。              更改调线帽后,打开串口工具,发送数据,顺利在点(10,42)位置绘制输入文字,LED1等会切换状态。    

标签:CODE,USB,OTG,stm32,USER,串口,Device
From: https://www.cnblogs.com/kn-zheng/p/17837889.html

相关文章

  • 基于stm32H730的解决方案开发之点亮第一个LED灯
    一概述STM32H730超值系列内含Arm®Cortex®-M7内核(具有双精度浮点单元),工作频率可达550MHz。内嵌的128KB闪存使意法半导体能够为开发人员提供一种经济划算的解决方案。凭借着高主频,高性能以及低成本。这颗料注定会成为一个网红产品。笔者最近有几款产品用到了该芯片,借此机会......
  • 使用python开发了一个自动摇摆机械臂 Micropython+ESP332+舵机+USB发热贴
    前言:在测试不同区域的红外、毫米波和激光雷达等传感器时,需要人工招手和移动进行测试。尽管这种测试是必要的,但却难以保证测试的一致性,因为人的动作很难做到完全一致。解决方案:为了提高测试的一致性,我们测试考虑开发一种可摇摆且能发热的测试工具。这样的工具可以模拟不同......
  • 如何用gcc+makefile改造STM32Keil项目
    1、环境配置,本地需要安装gcc+make环境,将w64devkit中的bin路径放入环境变量D:\download\storage\arm_gcc\w64devkit然后再cmd中输入gcc-v和make-v测试gcc和make环境是否可以正常运行,如果有下面这种显示就说明gcc和make环境配置好了2、获取芯片的启动文件文件和链接文件,stm32......
  • 具有mDNS功能的串口服务器
    1.概述:通过mDNS协议可以获得设备的ID、mac、IP、port等信息,方便计算机在同一个局域网内连接到具有该服务的模块。支持产品有串口服务器、串口转以太网模块、RS485串口转网口芯片等。  图1mDNS网络结构图当具有mDNS的服务的设备接入网络的时候,首先设备每隔1秒发送一个询......
  • NDK生成so文件,进行Android端串口通信
    开篇说明1、NDK构建工具的安装2、ndk-build所需构建文件Android.mk、Application.mk(官方链接:ndk-build脚本 | AndroidNDK | AndroidDevelopers(google.cn))3、java定义动态调用接口、生成头文件4、C++串口通信5、Java提供相关接口,生成jar包......
  • 嵌入式Linux adbd实现概要梳理(基于STM32MP157D+Buildroot)
    关键词:USBGadget、dwc2、configfs、functionfs、adbd等等。基于STM32MP157D简单记录ADB实现的过程,涉及到USB、Gadget、configfs、functionfs、adbd、ADB协议等等。基于Buildroot2020.02.6编译adbd运行于设备,和PCWindows交互的简要框图:1Linux下USBGadget1.1Linux内核Gad......
  • 【WCH蓝牙系列芯片】-基于CH32V208开发板—串口USART_FLAG_TXE & USART_FLAG_TC
    -------------------------------------------------------------------------------------------------------------------------------------USART模块支持多种中断源,这里说明一下USART_FLAG_TXE和USART_FLAG_TC对应的关系。USART_FLAG_TXE--------------发送数据寄存器空表......
  • 学无止境--linux串口编程(RS485)
    备注:学习记录所用,若有高手不吝赐教,万分感谢!一、概括  linux将串口都映射成了TTY终端,所以在串口编程时,找到并使能平台的TTY,然后操作TTY终端即可。  例如对于Nuclei平台的轩辕91030M芯片设备树: uart0:serial@10013000{ compatible="sifive,uart0"; reg=<0x00x100......
  • 关于如何判断电脑的USB接口版本
    今天想在U盘里装Linux系统,那么U盘接口的通信速度就很重要了,于是想到一个问题:要怎么判断USB接口是2.0还是3.0还是更高版本呢?我在网上找了一些识别方法,在这里总结一下,以后如果又发现了新的方法,也会在这里更新的。 方法一:看颜色方法来源:怎么查看自己电脑的USB接口类型啊?_百度知......
  • 零基础快速上手STM32开发(手把手保姆级教程)
    零基础快速上手STM32开发(手把手保姆级教程)1.前言作为一名嵌入式工程师,STM32是必须要学习的一款单片机,同时这款单片机资料足够多,而且比较简单,非常适合初学者入门。STM32是一款由STMicroelectronics公司开发的32位微控制器,由于其强大的处理能力和广泛的应用领域,如嵌入式系......