基于STM32CubeMX生成HID双向通讯工程的说明
时间:09-21
来源:互联网
点击:
客户在做USB通讯的时候,基本的需求就是发送某些数据到USB host端,同时接收一些数据从USB Host端,那么如何快速的建立一个工程并验证数据是否正确呢?下边我们就结合STM32F072的评估板(其他的STM32xx系列的实现方式都是类似的)来快速实现一个简单的数据收发实验。
下面是具体操作和一些基本的解说。
USBHost软件的准备
PC端软件使用ST免费提供的Usb Hid Demonstrator。这个软件可以在ST官网上免费下载到。连接地址:STSW-STM32084,此软件调用的是windows标准的HID类驱动,所以无需安装任何驱动程序及可运行。
下载安装完这个软件之后,我们就可以开始开发STM32的USB从机程序了。
首先,打开STM32CubeMX">STM32CubeMX,新建工程,选择STM32F072B-DISCOVERY开发板。
其次,在Pinout选项中,开打USB的device功能。
并在Middleware中选择开启class for IP中的 custom Human Interface Device(HID)
点击“保存”后直接生成工程。我们这里以生成IAR工程为例,项目名叫做HID。
这样我们的工程就基本成功了,但是还缺少最最关键的一步,就是USB主机和从机的通讯“协议”,这个协议在那里实现呢?因为我们Host端软件已经是Usb Hid Demonstrator,那么这边的协议就已经固定了(其实在实际的开发中大多是主机端和从机相互沟通后,软件自行修改的),从机只需要对应这套协议即可。
将如下代码复制,替换掉usbd_custom_hid_if.c文件中的同名数组。
__ALIGN_BEGIN static uint8_tCUSTOM_HID_ReportDesc_FS [USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0xFF, 0x00, /* USAGE_PAGE(Vendor Page: 0xFF00) */
0x09, 0x01, /* USAGE (Demo Kit) */
0xa1, 0x01, /* COLLECTION(Application) */
/* 6 */
/* LED1 */
0x85, LED1_REPORT_ID, /* REPORT_ID(1) */
0x09, 0x01, /* USAGE (LED 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, LED1_REPORT_COUNT, /*REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x85, LED1_REPORT_ID, /* REPORT_ID(1) */
0x09, 0x01, /* USAGE (LED 1) */
0x91, 0x82, /* OUTPUT(Data,Var,Abs,Vol) */
/* 26 */
/* LED2 */
0x85, LED2_REPORT_ID, /* REPORT_ID 2*/
0x09, 0x02, /* USAGE (LED 2) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, LED2_REPORT_COUNT, /*REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x85, LED2_REPORT_ID, /* REPORT_ID(2) */
0x09, 0x02, /* USAGE (LED 2) */
0x91, 0x82, /* OUTPUT(Data,Var,Abs,Vol) */
/* 46 */
/* LED3 */
0x85, LED3_REPORT_ID, /* REPORT_ID(3) */
0x09, 0x03, /* USAGE (LED 3) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, LED3_REPORT_COUNT, /*REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x85, LED3_REPORT_ID, /* REPORT_ID(3) */
0x09, 0x03, /* USAGE (LED 3) */
0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
/* 66 */
/* LED4 */
0x85, LED4_REPORT_ID, /* REPORT_ID4) */
0x09, 0x04, /* USAGE (LED 4) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, LED4_REPORT_COUNT, /*REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x85, LED4_REPORT_ID, /* REPORT_ID(4) */
0x09, 0x04, /* USAGE (LED 4) */
0x91, 0x82, /* OUTPUT(Data,Var,Abs,Vol) */
/* 86 */
/* key Push Button */
0x85, KEY_REPORT_ID, /* REPORT_ID(5) */
0x09, 0x05, /* USAGE (Push Button)*/
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x82, /* INPUT(Data,Var,Abs,Vol) */
0x09, 0x05, /* USAGE (Push Button)*/
0x75, 0x01, /* REPORT_SIZE (1) */
0xb1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x75, 0x07, /* REPORT_SIZE (7) */
0x81, 0x83, /* INPUT(Cnst,Var,Abs,Vol) */
0x85, KEY_REPORT_ID, /* REPORT_ID(2) */
0x75, 0x07, /* REPORT_SIZE (7) */
0xb1, 0x83, /* FEATURE (Cnst,Var,Abs,Vol)*/
/* 114 */
/* Tamper Push Button */
0x85, TAMPER_REPORT_ID,/* REPORT_ID(6) */
0x09, 0x06, /* USAGE (Tamper PushButton) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x82, /* INPUT(Data,Var,Abs,Vol) */
0x09, 0x06, /* USAGE (Tamper PushButton) */
0x75, 0x01, /* REPORT_SIZE (1) */
0xb1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x75, 0x07, /* REPORT_SIZE (7) */
0x81, 0x83, /* INPUT (Cnst,Var,Abs,Vol)*/
0x85, TAMPER_REPORT_ID,/* REPORT_ID(6) */
0x75, 0x07, /* REPORT_SIZE (7) */
0xb1, 0x83, /* FEATURE(Cnst,Var,Abs,Vol) */
/* 142 */
/* ADC IN */
0x85, ADC_REPORT_ID, /* REPORT_ID */
0x09, 0x07, /* USAGE (ADC IN) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM(255) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x81, 0x82, /* INPUT(Data,Var,Abs,Vol) */
0x85, ADC_REPORT_ID, /* REPORT_ID(7) */
0x09, 0x07, /* USAGE (ADC in) */
0xb1, 0x82, /* FEATURE (Data,Var,Abs,Vol)*/
/* 161 */
0xc0 /* END_COLLECTION */
};
注意:这里一定要覆盖“同名”数组,千万不要覆盖错了。
之后将如下代码复制到usbd_custom_hid_if_if.h中。
#define LED1_REPORT_ID 0x01
#define LED1_REPORT_COUNT 0x01
#define LED2_REPORT_ID 0x02
#define LED2_REPORT_COUNT 0x01
#define LED3_REPORT_ID 0x03
#define LED3_REPORT_COUNT 0x01
#define LED4_REPORT_ID 0x04
#define LED4_REPORT_COUNT 0x01
#define KEY_REPORT_ID 0x05
#define TAMPER_REPORT_ID 0x06
#define ADC_REPORT_ID 0x07
最后在usbd_conf.h文件中将USBD_CUSTOM_HID_REPORT_DESC_SIZE的定义值修改
为163(默认值是2)
#defineUSBD_CUSTOM_HID_REPORT_DESC_SIZE 163 //2
为什么这样修改呢? 简单说一下其中关键值的含义。
这个HID 的报文描述符其实定义了8个部分(条目)的功能定义,分为LED1,LED2,LED3,
LED4,按键输入,篡改按键输入和ADC输入。每部分的基本格式都是固定的。以LED1为例(其他条目可自行对照文档解析):
0x85, LED1_REPORT_ID, 含义是这个功能的ID号是LED1_REPORT_ID(宏定义为0x01)
这个ID号是每次报文发送的时候最先被发送出去的(USB都是LSB)字节,之后跟着的才是我们实际有效的数据/指令,到底是数据还是指令,就看你的应用程序如何去解析这个数据了。
0x09, 0x01, 这个功能序号为1,后边的序号依次递加。
0x15, 0x00, 这个是规定逻辑最小值为0 。
0x25, 0x01, 这个是规定逻辑最大值为1 。
上边的这两条语句规定了跟在报文ID后边的数据范围,最大值是1,最小值是0.(因为我们的LED也就只有灭和亮两种状态)
0x75, 0x08, 这个是报文的大小为8,只要别写错就行了。
0x95, LED1_REPORT_COUNT, 这个是说下边有LED1_REPORT_COUNT (宏定义为1)个项目会被添加,即这个功能的数量是1个 。
0xB1, 0x82, 这个是规定能够发送给从机设备的数据信息。
0x91, 0x82, 这个规定了该功能的数据方向是输出(传输方向以主机为参照)。
总结一下,通过这个报文描述符,我们就告诉了主机,在HID中有一个功能ID为1的功能,其方向是从主机到从机,每次发送1个有效数据(前边的ID是都要含有的),这个数据可以是0或者是1.
关于HID 报文描述符的详细信息,您可以在下边的网址下载一篇叫做《Device Class Definitionfor HID》的文档来参考。http://www.usb.org/developers/hidpage
这样基本的程序框架就已经成功了。此时我们可以先编译一下,看看是否有任何遗漏的或者笔误。如果编译是正确的,那么我们就可以先下载到硬件开发板上,连接到PC端,看看是否可以枚举出设备。如果您前边的修改都是正确的,那么在PC的设备管理器中会看到如下图所示的内容。
注意:开发板上有两个一模一样的Mini USB接口,一个是USB USER,另 一个是USB ST-link,下载代码的时候用USB ST-Link,连接电脑运行程序的时候要用USB USER。
此时我们的USB枚举就完成了,这个是USB通讯的关键步骤,之后的应用通讯内容都是通过这个枚举工程来进行“规划”的。
下面是具体操作和一些基本的解说。
USBHost软件的准备
PC端软件使用ST免费提供的Usb Hid Demonstrator。这个软件可以在ST官网上免费下载到。连接地址:STSW-STM32084,此软件调用的是windows标准的HID类驱动,所以无需安装任何驱动程序及可运行。
下载安装完这个软件之后,我们就可以开始开发STM32的USB从机程序了。
首先,打开STM32CubeMX">STM32CubeMX,新建工程,选择STM32F072B-DISCOVERY开发板。
其次,在Pinout选项中,开打USB的device功能。
并在Middleware中选择开启class for IP中的 custom Human Interface Device(HID)
点击“保存”后直接生成工程。我们这里以生成IAR工程为例,项目名叫做HID。
这样我们的工程就基本成功了,但是还缺少最最关键的一步,就是USB主机和从机的通讯“协议”,这个协议在那里实现呢?因为我们Host端软件已经是Usb Hid Demonstrator,那么这边的协议就已经固定了(其实在实际的开发中大多是主机端和从机相互沟通后,软件自行修改的),从机只需要对应这套协议即可。
将如下代码复制,替换掉usbd_custom_hid_if.c文件中的同名数组。
__ALIGN_BEGIN static uint8_tCUSTOM_HID_ReportDesc_FS [USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0xFF, 0x00, /* USAGE_PAGE(Vendor Page: 0xFF00) */
0x09, 0x01, /* USAGE (Demo Kit) */
0xa1, 0x01, /* COLLECTION(Application) */
/* 6 */
/* LED1 */
0x85, LED1_REPORT_ID, /* REPORT_ID(1) */
0x09, 0x01, /* USAGE (LED 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, LED1_REPORT_COUNT, /*REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x85, LED1_REPORT_ID, /* REPORT_ID(1) */
0x09, 0x01, /* USAGE (LED 1) */
0x91, 0x82, /* OUTPUT(Data,Var,Abs,Vol) */
/* 26 */
/* LED2 */
0x85, LED2_REPORT_ID, /* REPORT_ID 2*/
0x09, 0x02, /* USAGE (LED 2) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, LED2_REPORT_COUNT, /*REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x85, LED2_REPORT_ID, /* REPORT_ID(2) */
0x09, 0x02, /* USAGE (LED 2) */
0x91, 0x82, /* OUTPUT(Data,Var,Abs,Vol) */
/* 46 */
/* LED3 */
0x85, LED3_REPORT_ID, /* REPORT_ID(3) */
0x09, 0x03, /* USAGE (LED 3) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, LED3_REPORT_COUNT, /*REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x85, LED3_REPORT_ID, /* REPORT_ID(3) */
0x09, 0x03, /* USAGE (LED 3) */
0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
/* 66 */
/* LED4 */
0x85, LED4_REPORT_ID, /* REPORT_ID4) */
0x09, 0x04, /* USAGE (LED 4) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, LED4_REPORT_COUNT, /*REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x85, LED4_REPORT_ID, /* REPORT_ID(4) */
0x09, 0x04, /* USAGE (LED 4) */
0x91, 0x82, /* OUTPUT(Data,Var,Abs,Vol) */
/* 86 */
/* key Push Button */
0x85, KEY_REPORT_ID, /* REPORT_ID(5) */
0x09, 0x05, /* USAGE (Push Button)*/
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x82, /* INPUT(Data,Var,Abs,Vol) */
0x09, 0x05, /* USAGE (Push Button)*/
0x75, 0x01, /* REPORT_SIZE (1) */
0xb1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x75, 0x07, /* REPORT_SIZE (7) */
0x81, 0x83, /* INPUT(Cnst,Var,Abs,Vol) */
0x85, KEY_REPORT_ID, /* REPORT_ID(2) */
0x75, 0x07, /* REPORT_SIZE (7) */
0xb1, 0x83, /* FEATURE (Cnst,Var,Abs,Vol)*/
/* 114 */
/* Tamper Push Button */
0x85, TAMPER_REPORT_ID,/* REPORT_ID(6) */
0x09, 0x06, /* USAGE (Tamper PushButton) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x25, 0x01, /* LOGICAL_MAXIMUM (1)*/
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x82, /* INPUT(Data,Var,Abs,Vol) */
0x09, 0x06, /* USAGE (Tamper PushButton) */
0x75, 0x01, /* REPORT_SIZE (1) */
0xb1, 0x82, /* FEATURE(Data,Var,Abs,Vol) */
0x75, 0x07, /* REPORT_SIZE (7) */
0x81, 0x83, /* INPUT (Cnst,Var,Abs,Vol)*/
0x85, TAMPER_REPORT_ID,/* REPORT_ID(6) */
0x75, 0x07, /* REPORT_SIZE (7) */
0xb1, 0x83, /* FEATURE(Cnst,Var,Abs,Vol) */
/* 142 */
/* ADC IN */
0x85, ADC_REPORT_ID, /* REPORT_ID */
0x09, 0x07, /* USAGE (ADC IN) */
0x15, 0x00, /* LOGICAL_MINIMUM (0)*/
0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM(255) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x81, 0x82, /* INPUT(Data,Var,Abs,Vol) */
0x85, ADC_REPORT_ID, /* REPORT_ID(7) */
0x09, 0x07, /* USAGE (ADC in) */
0xb1, 0x82, /* FEATURE (Data,Var,Abs,Vol)*/
/* 161 */
0xc0 /* END_COLLECTION */
};
注意:这里一定要覆盖“同名”数组,千万不要覆盖错了。
之后将如下代码复制到usbd_custom_hid_if_if.h中。
#define LED1_REPORT_ID 0x01
#define LED1_REPORT_COUNT 0x01
#define LED2_REPORT_ID 0x02
#define LED2_REPORT_COUNT 0x01
#define LED3_REPORT_ID 0x03
#define LED3_REPORT_COUNT 0x01
#define LED4_REPORT_ID 0x04
#define LED4_REPORT_COUNT 0x01
#define KEY_REPORT_ID 0x05
#define TAMPER_REPORT_ID 0x06
#define ADC_REPORT_ID 0x07
最后在usbd_conf.h文件中将USBD_CUSTOM_HID_REPORT_DESC_SIZE的定义值修改
为163(默认值是2)
#defineUSBD_CUSTOM_HID_REPORT_DESC_SIZE 163 //2
为什么这样修改呢? 简单说一下其中关键值的含义。
这个HID 的报文描述符其实定义了8个部分(条目)的功能定义,分为LED1,LED2,LED3,
LED4,按键输入,篡改按键输入和ADC输入。每部分的基本格式都是固定的。以LED1为例(其他条目可自行对照文档解析):
0x85, LED1_REPORT_ID, 含义是这个功能的ID号是LED1_REPORT_ID(宏定义为0x01)
这个ID号是每次报文发送的时候最先被发送出去的(USB都是LSB)字节,之后跟着的才是我们实际有效的数据/指令,到底是数据还是指令,就看你的应用程序如何去解析这个数据了。
0x09, 0x01, 这个功能序号为1,后边的序号依次递加。
0x15, 0x00, 这个是规定逻辑最小值为0 。
0x25, 0x01, 这个是规定逻辑最大值为1 。
上边的这两条语句规定了跟在报文ID后边的数据范围,最大值是1,最小值是0.(因为我们的LED也就只有灭和亮两种状态)
0x75, 0x08, 这个是报文的大小为8,只要别写错就行了。
0x95, LED1_REPORT_COUNT, 这个是说下边有LED1_REPORT_COUNT (宏定义为1)个项目会被添加,即这个功能的数量是1个 。
0xB1, 0x82, 这个是规定能够发送给从机设备的数据信息。
0x91, 0x82, 这个规定了该功能的数据方向是输出(传输方向以主机为参照)。
总结一下,通过这个报文描述符,我们就告诉了主机,在HID中有一个功能ID为1的功能,其方向是从主机到从机,每次发送1个有效数据(前边的ID是都要含有的),这个数据可以是0或者是1.
关于HID 报文描述符的详细信息,您可以在下边的网址下载一篇叫做《Device Class Definitionfor HID》的文档来参考。http://www.usb.org/developers/hidpage
这样基本的程序框架就已经成功了。此时我们可以先编译一下,看看是否有任何遗漏的或者笔误。如果编译是正确的,那么我们就可以先下载到硬件开发板上,连接到PC端,看看是否可以枚举出设备。如果您前边的修改都是正确的,那么在PC的设备管理器中会看到如下图所示的内容。
注意:开发板上有两个一模一样的Mini USB接口,一个是USB USER,另 一个是USB ST-link,下载代码的时候用USB ST-Link,连接电脑运行程序的时候要用USB USER。
此时我们的USB枚举就完成了,这个是USB通讯的关键步骤,之后的应用通讯内容都是通过这个枚举工程来进行“规划”的。
- 实现WUSB设备控制器的设计考虑因素(09-12)
- 基于USB2.0的高速无线数传接收设备的数据接收存储方法(09-09)
- 四种短距离无线监控解决方案的性能对比(09-16)
- Wibree:一个可供选择的新无线联网技术(11-07)
- TI 单芯片手机多媒体电话解决方案(12-01)
- 蓝牙技术硬件实现模式分析(01-11)