程序功能:
1,将STM32的USB枚举为HID设备。
2,STM32使用3个端点,端点0用于枚举用,端点1和2用于数据的发送和接收。
5,上位机程序通过调用windows的API实现对HID设备的读写控制。
原理图:
说明:实际测试的时候不用这么复杂的电路,接好PA11和PA12即可,当然在PA12引脚上需要一个上拉电阻,其他电路都可以省略。
HID枚举成功:
说明:枚举成功后会自动安装HID驱动,无需单独安装。
上位机程序运行效果图:
说明:上位机程序是在VS2010环境下写的,不过可以根据自己需求移植到其他环境中。
单片机运行输出:
说明:单片机端采用超级终端输出相关信息,使用的USART1串口,也就是PA9和PA10两个引脚。
Bus Hound抓取数据截图:
说明:Bus Hound是一个很不错的数据抓包工具,调试USB程序相当有用。
部分程序源码:
STM32的报告描述符:
上位机测试程序:
1,将STM32的USB枚举为HID设备。
2,STM32使用3个端点,端点0用于枚举用,端点1和2用于数据的发送和接收。
3,端点长度为64,也就是单次最多可以传输64个字节数据。
4,STM32获取上位机下发的数据并将该数据通过USB原样返回,同时将数据打印输出。5,上位机程序通过调用windows的API实现对HID设备的读写控制。
原理图:
说明:实际测试的时候不用这么复杂的电路,接好PA11和PA12即可,当然在PA12引脚上需要一个上拉电阻,其他电路都可以省略。
HID枚举成功:
说明:枚举成功后会自动安装HID驱动,无需单独安装。
上位机程序运行效果图:
说明:上位机程序是在VS2010环境下写的,不过可以根据自己需求移植到其他环境中。
单片机运行输出:
说明:单片机端采用超级终端输出相关信息,使用的USART1串口,也就是PA9和PA10两个引脚。
Bus Hound抓取数据截图:
说明:Bus Hound是一个很不错的数据抓包工具,调试USB程序相当有用。
部分程序源码:
STM32的报告描述符:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
const uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] =
{
0x05, 0x8c, /* USAGE_PAGE (ST Page) */
0x09, 0x01, /* USAGE (Demo Kit) */
0xa1, 0x01, /* COLLECTION (Application) */
// The Input report
0x09,0x03, // USAGE ID - Vendor defined
0x15,0x00, // LOGICAL_MINIMUM (0)
0x26,0x00, 0xFF, // LOGICAL_MAXIMUM (255)
0x75,0x08, // REPORT_SIZE (8bit)
0x95,0x40, // REPORT_COUNT (64Byte)
0x81,0x02, // INPUT (Data,Var,Abs)
// The Output report
0x09,0x04, // USAGE ID - Vendor defined
0x15,0x00, // LOGICAL_MINIMUM (0)
0x26,0x00,0xFF, // LOGICAL_MAXIMUM (255)
0x75,0x08, // REPORT_SIZE (8bit)
0x95,0x40, // REPORT_COUNT (64Byte)
0x91,0x02, // OUTPUT (Data,Var,Abs)
0xc0 /* END_COLLECTION */
}; /* CustomHID_ReportDescriptor */
|
上位机测试程序:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
/**
* @brief 发送数据后读取数据
* @param None
* @retval None
*/
void HIDSampleFunc( void )
{
HANDLE hDev;
BYTE recvDataBuf[1024],reportBuf[1024];;
DWORD bytes;
hDev = OpenMyHIDDevice(0); // 打开设备,不使用重叠(异步)方式 ;
if (hDev == INVALID_HANDLE_VALUE){
printf ( "INVALID_HANDLE_VALUE\n" );
return ;
}
reportBuf[0] = 0; // 输出报告的报告 ID 是 0
for ( int i=0;i<REPORT_COUNT;i++){
reportBuf[i+1]=i+1; //将数据存放在数据缓冲区
}
printf ( "开始写数据到设备...\n" );
// 写入数据到设备,注意,第三个参数值必须为REPORT_COUNT+1,否则会返回1784错误
if (!WriteFile(hDev, reportBuf, REPORT_COUNT+1, &bytes, NULL)){
printf ( "write data error! %d\n" ,GetLastError());
return ;
} else {
printf ( "成功向设备写出%d个数据... \n" ,bytes);
}
printf ( "开始从设备读取数据...\n" );
// 从设备读取数据,注意,第三个参数值必须大于等于REPORT_COUNT+1,否则会返回1784错误
if (!ReadFile(hDev, recvDataBuf, REPORT_COUNT+1, &bytes, NULL)){ // 读取设备发给主机的数据
printf ( "read data error! %d\n" ,GetLastError());
return ;
} else {
printf ( "成功向设备读出%d个数据... \n" ,bytes);
}
printf ( "设备返回的数据为:\n" );
//显示读取回来的数据
for ( int i=0;i<REPORT_COUNT;i++){
printf ( "0x%02X " ,recvDataBuf[i+1]);
}
printf ( "\n\r" );
}
|