如何让CDC类USB设备批量接收64字节以上数据
很多STM32开发者在实现CDC类虚拟串口与PC主机通信过程中,有时会遇到点麻烦而不得其解。那就是当主机端单次发送的数据不超过64字节时,接收正常。一旦发送数据量大于64字节时就接收失败,总是出现丢包现象,似乎只能接收64字节以内的数据。网上有人干脆建议主机每次发送不要超过64字节,当然,也有人提及要作分包处理但没具体实现代码可以参考。
作为CDC类的USB设备,到底能不能正确接收来自主机64字节以上的批量数据呢?
其实是可以的,只是当我们一次传输的数据大于当前端点所支持的最大包长时【这里端点使用BULK传输,一般最大包长默认设置为64字节】,USB模块会做分包传输,将一批数据传输分成多个处理[或称事务],即多个transaction来完成,每个Transaction里的数据包传输的最大数据量为64字节。
原理性的东西,这里不多啰嗦了,网上有成堆的介绍资料【当然,或许有点乱】。当我们弄清整个原理后,就可以自行组织接收处理代码了。下面我利用HAL库,基于STM32F429芯片演示实现过程,重点在接收处理代码。我使用STM32F429 Discovery开发板,使用HS USB模块并令其工作在FS MODE,这样我们就可以方便地使用片内USB FS PHY。
我使用STM32CubeMx工具进行配置,生成基于STM32 HAL库的工程。使用ST提供的STM32CubeIDE进行编译调试。有关配置就不截图了。
另外,我还配置了1个按键并开启相应外部中断。每发生按键事件时,F429 USB设备向PC主机发送一段打招呼的字符串,并通过串口助手显示出来。如下图所示:
我在main.c文件里额外定义了下面几个变量:
其中,Flag_KeyPressed和Flag_DataReceived分别表示按键操作和收到从主机发过来的数据的情况。Rx_buffer【】数组用来存放接收来自主机的全部数据,这里的定义长度为512字节【你具体使用时按需设置】。下图是Main.c里的主循环代码截图:
主循环里检查按键标志和收到数据的标志,如有按键发生,则向主机发送前面提到的打招呼的字符串;如有收到来自主机的数据,则向主机回送过去。
今天的重点是讨论USB设备如何从主机接收64字节以上的数据。基于现有HAL库,对于USB设备的接收,我们只需关注一个USB中断接收回调函数,那就是CDC_Receive_HS()函数。该函数在usbd_cdc_if.c文件里。我具体编写的函数代码如下面两幅截图所示。
代码很简单。 我在库代码的基础上增加了橙色方框内的代码。基本功能就是,先读取当前收到的数据长度【SinglePackLength】,分整包和非整包两种情况鉴别后再处理。若是接收的整包数据,继续等待接收下一包;若是非整包,视为此次传输结束,并设置收到标志Flag_DataReceived为非0值,然后在主循环里将收到的数据回送给主机。
其中,Max_Pack_Size是当前CDC类BULK传输端点的最大传输包长,这里为64字节。
Num_Rx_Data表示接收到数据个数,Num_Out_Pack表示接收到的数据包个数,Num_Packet跟Num_Out_Pack内容一样,不过,Num_Packet等于0还表示准备开始新一轮传输的接收。这里多定义Num_Out_Pack,一个重要目的是便于调试时查看结果。
基于上面的接收处理代码,我们来验证结果:
借助PC端的串口助手向STM32F429 USB设备发送了5个字符,我们通过STM32CubeIDE调试环境可以清晰地从上图看到设备收到的数据个数为5,数据包个数为1。显然没问题。那个Rx_buffer数组是我用来存放接收数据的,若在调试窗口打开,数据较多列表显示会很长,这里就没打开了。事实上接收的数据内容也是没问题的。
下图是借助PC端的串口助手向STM32F429 USB设备发送了305个字符的接收情况:
显然,对于305个字符,PC主机端要分成5包才能发送完毕,即4整包【每包64字节】再加1个非完整包。所以USB设备接收结果也正好是5包,即上图中Num_Out_pack的数据,接收到的数据量为305,即上图中Num_Rx_Data的数据。同样,结果OK。
下图是PC端刚好发送一个完整包64字节数据的USB设备接收情况,也一切正常。
也就是说,使用我上面编写的接收处理代码,对主机发送的数据的个数不再局限于64字节以内了。当然,具体应用时我们还可以根据主机端单次传输数据的大小情况及提取数据的方式适当调整这里的Rx_buffer[]数组大小。【注:上面测试时我临时关闭了设备端的数据回送功能,是为了避免截图里的数据混乱,让人分不清原数据和回显数据】
有人可能在上面的接收代码里看到了一个变量Wait_Rx_Dly。刚开始,代码里是没有这个变量的。后来我在测试主机发送64字节整包数据时,发现了一个小问题【最终到底算不算问题,或许要视具体应用场景而定,我这里稍作了点处理】。
问题是这样的:
主机每发送1包64字节数据时,设备端接收没有问题,但只要主机端每次发送64字节完整数据包过来,不论相隔时间多久,设备端依然接收,且总在前次结果上累加,除非主机端发一个非64字节数据包过来,设备接收就总是视为同一次传输。比方像下面截图所示:
上图就是PC主机端借助串口助手分四次且每次发送64字节数据时USB设备的接收情况。从图上不难看出,4次数据都汇集在一起了,关键还没完,还在等待后续数据过来。我是希望一次传输做一次处理,于是我让设备每收到一个完整数据包,就重新给定一个延时,比方3~5ms,用变量Wait_Rx_Dly来记录延时值,在某毫秒定时中断里对该变量做减1操作。若延时到了还没有收到数据或延时过程中收到非完整包则视为本次传输结束,然后去处理刚才收到的数据。
我顺便使用了HAL库里自带的systick中断函数来做这个延时管理。当接收处理代码加上这个延时管理后,就不会出现不同传输批次的数据挤在一块了。问题得以解决。
另外,我上面分享的接收处理代码也有很好的通用性,并不局限于Bulk传输。我们知道,不同传输类型的端点的最大包长往往并不一样,如果使用上面的参考代码,我们只需调整那个最大包长参数【Max_Pack_Size】,并适当调整Rx_buffer[]数组的大小就可以使用了。数据个数、传输包个数这些变量都可以保留使用。
那段接收处理代码很简单,看懂了都可以自行组织编写。顺便说下,我使用的STM32F4系列的Cube库版本为STM32F4xx HAL V1.8.1。好,今天的话题就分享到这里,希望帮到有需要的人。祝君好运!
往期话题阅读链接【点击即可阅读】:
1、话说STM32外设复位
2、CubeMx初始配置顺序与DMA传输异常
3、远程修改STM32 TIMER占空比的方案续1
4、两份基于STM32 FDCAN开发的资料
5、定时器输出指定个数脉冲的几种方式
如何让CDC类USB设备批量接收64字节以上数据相关推荐
- Ubuntu/Windows下利用“HIDAPI”库函数实现与Hid类USB设备通信
转自https://www.cnblogs.com/ChYQ/p/5383828.html 一.背景: 最近在做的一个项目需要使用USB传递数据,对USB理解不是很深,USB的系统驱动编写则更 ...
- ESP32-S2应用开发——USB通信(CDC类)
ESP32S2应用开发--USB通信(CDC类) 目录 ESP32S2应用开发--USB通信(CDC类) 前言 1 硬件介绍 1.1 硬件连接 2 软件开发 2.1 安装开发板 2.2 安装库 2.3 ...
- 在进行USB CDC类开发时,无法发送64整数倍的数据
1 前言 本文将基于STM32F4DISCOVERY板,介绍如何使用USB的CDC类进行开发,以及在开发过程中碰到发送64整数倍数据时会失败的问题分析及解决方案. 2 硬件介绍 在创建工程之前,我们首 ...
- libusb linux 异步传输,使用libusb异步批量传输,设备停止接收,如果我们空闲
我正在写一个Linux程序(使用Qt 4.8和libusb 1.0),它将与自定义USB设备(当前正在由同事编程)进行通信.使用libusb异步批量传输,设备停止接收,如果我们空闲 第1步是让&quo ...
- 如何使用 WinUSB 与 USB 设备 (USBDevice) 通信
选择 USB 设备的驱动程序模型 https://github.com/libusbx/libusbx/wiki/Windows-Backend WinUSB does not support Win ...
- Android 连接USB设备(主机模式)
Android 连接USB设备(主机模式) Android 连接USB设备(配件模式) 两种模式(主机.配件) 首先,要了解Android 连接USB设备主要通过两种模式, USB 配件模式. USB ...
- 在Java 应用程序中访问USB设备
Java 平台一直都以其平台无关性自豪.虽然这种无关性有许多好处,但是它也使得编写与硬件交互的 Java 应用程序的过程变得相当复杂.在本文中,研究科学家蒋清野讨论了两个项目,它们通过提供使Java ...
- USB设备的插入检测
又被坑了,总算解决了,要睡了长话短说.首先,着重强调 Device Class GUID, Device Interface Class GUID, Interface GUID是有区别的,另外奉上两 ...
- USB驱动程序之一(USB介绍、USB数据传输、USB设备枚举)
文章目录 USB简介 USB系统架构 USB系统拓扑结构 USB主控制器 USB HUB USB设备 USB设备逻辑结构 USB描述符 设备描述符 配置描述符 接口描述符 端点描述符 USB数据传输 ...
最新文章
- jquery拼接后css样式不生效_JQuery常用选择器以及操作属性和样式的方法介绍
- dirver时区_JDBD连接MySQL中的驱动与时区问题
- 【模型开发】构建风控评分卡模型介绍(WOE/KS/ROC)
- python导入模块找不到什么原因_找不到Python导入模块错误
- if you miss it, you can hope for future
- GDCM:gdcm::Scanner的测试程序
- 【转】节点预测与边预测任务实践
- Win7下如何更改时间日期
- 剑指offer——最小的K个数和数组中第K大的元素
- 《Python Cookbook 3rd》笔记(2.12):审查清理文本字符串
- 不超过20位的小数正则_盘点贵州省的GDP增长:跃居全国20位,超过了两个难以超越的省份...
- 鸿蒙系统和你,鸿蒙系统面世,但与您所想的不一样
- 掌业宝服务器维护升级,奇游联机宝APP焕新升级 主机加速多设备各享最优区服...
- some ubuntu shell commands
- [转]什么是lib文件,lib和dll的关系如何
- django中url 和 path 的区别
- SUFFER软件测试工程师,Ubuntu9.0.4下FreeSurfer的安装(转)
- python调用通达信函数大全_通达信dll开发实例,使用python在通达信里面选股
- PHP判断手机横向,如何用css和js移动端分别判断手机横竖屏的状态
- Java实现tiff图片转化为jpg格式