在STM32中如何自定义HID设备,用cubemx怎么生成代码并配置?
生成USB HID工程
可以看到,勾选usb device的功能后,右侧的芯片引脚已经设置好了,DP和DM两根线就是usb通信的差分线。
再配置USB的软件中间件,选择usb device,Custom Interface Device Class,这个选项生成的就是自定义的HID设备。
然后需要修改三个参数:
CUSTOM_HID_FS_BINTERVAL,这个设置的是HID设备的通信时间间隔,单位为ms,最快可以为1ms间隔;
USBD_CUSTOM_HID_REPORT_DESC_SIZE,设置的是报告描述符的长度,设为34(后面会提到为什么是这个值);
USBD_CUSTOMHID_OUTREPORT_BUF_SIZE,比较好理解,设置的是发送缓冲区的大小,HID一次最多可以发送64个字节,我们设置为最大值。
在另一个选项卡中,我们可以看到下面几个参数:VID、PID,以及设备标识,这里我们都不修改。
其他的配置都不用改,就可以生成工程代码了。
2)代码编写
打开生成的keil工程,可以看到已经生成了usb相关的源文件。
我们一步步添加需要的代码。
首先添加报告描述符,如下图,在usbd_custom_hid_if.c文件中,CUSTOM_HID_ReportDesc_FS定义数组内部添加:
/** Usb HID report descriptor. */
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
/* USER CODE BEGIN 0 */
// 0x00,
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x95, 0x08, // REPORT_COUNT (64字节)
0x75, 0x08, // REPORT_SIZE (8位)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x95, 0x08, // REPORT_COUNT (64)
0x75, 0x08, // REPORT_SIZE (8)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
};
描述符定义了usb传输数据的格式。
这里的数组长度USBD_CUSTOM_HID_REPORT_DESC_SIZE就是在cubemx中定义的34,与描述符数组的长度必须一样。
然后,在usbd_customhid.c文件中,找到USBD_CUSTOM_HID_CfgHSDesc数组,修改里面的参数:
标记的四个参数,分别是:接收的长度、延时,发送的长度、延时;这里我们可以跳转到它们的宏定义处修改;长度都修改为0x40;延时可以默认,也可以修改到1,也就是1ms周期,可以加快通信的最快速率。
接着,修改接收函数,如下图,在usbd_custom_hid_if.c文件中,添加语句如下:
这个函数在usb接收到数据时会自动调用,这里我们在函数中,把接收到的数据用strncpy这个函数拷贝到usb_rx_data数组中,然后设置usb_rx_flag标志位。
到主函数中循环查询标志位,查询到则可以处理usb_rx_data中接收到的数据。
需要发送数据时,直接调用HAL库生成的发送函数即可,函数原型如下:
uint8_t USBD_CUSTOM_HID_SendReport(USBD_HandleTypeDef *pdev,
uint8_t *report,
uint16_t len)
{
USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassData;
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
if (hhid->state == CUSTOM_HID_IDLE)
{
hhid->state = CUSTOM_HID_BUSY;
USBD_LL_Transmit(pdev, CUSTOM_HID_EPIN_ADDR, report, len);
}
else
{
return USBD_BUSY;
}
}
return USBD_OK;
}
主函数中主要添加的是:初始时将USB端口复位,以及主循环中的接收和发送数据。
USB_IO_rest();这个函数主要是用在初始时把usb接口引脚拉低一下,让计算机知道有新设备插入(以前的文章讲过,也可以参考源代码,很容易理解);
主循环中检测接收标志位,如果收到数据,则把数据更新到usb_tx_data中,每隔1s检测一下;每隔1s把usb_tx_data中的数据发送出去。
看看具体的额效果,端点2接受和发送