STM32模拟USB键盘:如何判断主机读取端点缓冲区数据及bInterval设置
针对STM32 HID键盘与自定义主机通信的问题解答
我之前做STM32 HID设备开发时,也碰到过类似的自定义主机读取不及时的情况,结合实际经验给你拆解解决方案:
1. 如何判断主机已读取EP缓冲区的数据?
STM32 USB Device Library提供了两种可靠的方式来检测:
- 利用库自带的回调函数:在HID类的实现中,当主机完成对IN端点的数据读取后,会触发
USBD_HID_EPInCallback(不同版本的库可能命名略有差异,比如部分版本是USBD_HID_DataInStage后的事件回调)。你可以在这个回调里设置一个标志位,比如uint8_t hid_report_sent = 0;,当回调触发时把这个标志位设为1,之后每次调用USBD_HID_SendReport()前先检查这个标志位,确保上一次的数据已经被主机取走再发送新的。 - 主动查询端点状态:使用库函数
USBD_GetEPState()来获取IN端点的状态,示例代码如下:
当端点状态为if(USBD_GetEPState(&hUsbDeviceFS, HID_EPIN_ADDR) == USBD_EP_STAT_TX_EMPTY) { // 主机已经读取了之前的缓冲区数据,可以发送新报告 USBD_HID_SendReport(&hUsbDeviceFS, report_data, report_len); }USBD_EP_STAT_TX_EMPTY时,说明缓冲区的数据已经被主机读取完毕。
2. 是否需要修改端点描述符中的bInterval?
这取决于你的自定义主机的轮询机制。如果自定义主机对HID设备的轮询间隔比当前设置的bInterval大,调大bInterval可以减少不必要的端点状态查询;但你现在遇到的核心问题是连续发送时新数据覆盖了缓冲区中未被读取的旧数据,所以更关键的是确保每次发送新报告前,等待上一次的报告被主机读取(也就是上面说的标志位或状态查询),而不是盲目修改bInterval。
3. 标准HID键盘的bInterval是多少?
全速USB下的标准HID键盘,端点描述符中的bInterval值为10(对应10ms的轮询间隔,因为全速USB每帧是1ms,bInterval的单位是帧)。这个值是HID规范中针对键盘类设备推荐的标准值,电脑主机也是按照这个间隔来轮询的,所以你给电脑发送时不会出现读取不及时的问题。
总结一下,你现在最需要做的是:在每次调用USBD_HID_SendReport()前,通过回调标志或端点状态查询,确认上一次的报告已经被自定义主机读取,再发送下一次数据。如果自定义主机的轮询间隔确实大于10ms,可以适当调大bInterval,但核心还是要避免缓冲区数据被覆盖。
内容的提问来源于stack exchange,提问作者Mangesh Pawar
相关产品推荐
相关产品推荐

