实现用STM32模拟一个USB键盘连接PC的功能
1 STM32CubeMX配置
1.1 USB接口配置
单片机做从机,所以Mode选择Device,其它设置保持默认即可
使能USB接口的中断:
设置IP,选择HID,注意不要选择自定义HID
参数页面不需要调整,设备描述符根据实际需要自行修改
1.2 时钟配置
USB接口使用的时钟频率为48MHz
至此,配置完成,生成代码
2 设备描述符
2.1 修改设备描述符大小
打开usbd_hid.h文件,修改HID_MOUSE_REPORT_DESC_SIZE的值为63,原来为74表示鼠标设备,HAL库默认的HID设备为鼠标,因此变量名、宏名中的MOUSE不必在意,不影响PC端识别到的设备名称和类型,如果要修改,请注意全部替换,不要遗漏
//#define HID_MOUSE_REPORT_DESC_SIZE 74U //鼠标描述符大小
#define HID_MOUSE_REPORT_DESC_SIZE 63U //键盘描述符大小
2.2 修改设备类型
打开usbd_hid.c文件,找到USBD_HID_CfgFSDesc数组的定义:
/* USB HID device FS Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_HID_CfgFSDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
USB_HID_CONFIG_DESC_SIZ,
/* wTotalLength: Bytes returned */
0x00,
0x01, /*bNumInterfaces: 1 interface*/
0x01, /*bConfigurationValue: Configuration value*/
0x00, /*iConfiguration: Index of string descriptor describing
the configuration*/
0xE0, /*bmAttributes: bus powered and Support Remote Wake-up */
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
/************** Descriptor of Joystick Mouse interface ****************/
/* 09 */
0x09, /*bLength: Interface Descriptor size*/
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
0x00, /*bInterfaceNumber: Number of Interface*/
0x00, /*bAlternateSetting: Alternate setting*/
0x01, /*bNumEndpoints*/
0x03, /*bInterfaceClass: HID*/
0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
0x01, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
0, /*iInterface: Index of string descriptor*/
/******************** Descriptor of Joystick Mouse HID ********************/
/* 18 */
0x09, /*bLength: HID Descriptor size*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
0x11, /*bcdHID: HID Class Spec release number*/
0x01,
0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/
HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
0x00,
/******************** Descriptor of Mouse endpoint ********************/
/* 27 */
0x07, /*bLength: Endpoint Descriptor size*/
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/
HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */
0x00,
HID_FS_BINTERVAL, /*bInterval: Polling Interval */
/* 34 */
};
找到nInterfaceProtocol子项,将其值改为1,即将设备类型改为键盘,默认为鼠标
2.3 修改设备描述符
打开usbd_hid.c文件,找到HID_MOUSE_ReportDesc数组的定义,将其内容改为:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop) //63
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0, // END_COLLECTION
};
这里就是HID描述,如果需要自定义描述符,可以用过官网的描述符工具来生成,下载链接如下:
https://usb.org/sites/default/files/documents/dt2_4.zip
3 编写测试程序
基本的配置都完成了,接下来开始编写测试程序,让单片机模拟几个敲键盘的动作,看电脑是否能接收到,首先包含usbd_hid.h头文件,再声明下外部变量hUsbDeviceFS:
#include "usbd_hid.h"
extern USBD_HandleTypeDef hUsbDeviceFS;
我这里测试采用的是用串口助手发送键盘,单片机转发到USB接口的验证方法
void Key_Test(char * Payload)
{
uint8_t key[8] = {0};
if (sscanf(Payload, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu",
&key[0], &key[2], &key[3], &key[4], &key[5], &key[6], &key[7]) != 7)
{
PC_Printf("NG,%s\r\n@_@", __func__);
return;
}
USBD_HID_SendReport(&hUsbDeviceFS, key, 8);
HAL_Delay(10);
for (uint8_t i = 0; i < 8; i++) key = 0;
USBD_HID_SendReport(&hUsbDeviceFS, key, 8);
PC_Printf("OK,%s\r\n@_@", __func__);
}
MSH_CMD_EXPORT(Key_Test, Usb keyboard test);
核心函数为USBD_HID_SendReport,通过USB向PC发送一个键值包,包大小为8个字节
第一个字节:控制键,每个位表示一种特殊按键的按下状态,为1表示有效
-bit0: Left CTRL
-bit1: Left SHIFT
-bit2: Left ALT
-bit3: Left GUI
-bit4: Right CTRL
-bit5: Right SHIFT
-bit6: Right ALT
-bit7: Right GUI
比如要模拟右Shift按下状态,key[0]应设置为0x20
第二个字节:保留,不使用
后6个字节,用于存放最多6个被按下的按键,每个键的键值如下表:
模拟按键的规则:当有按键被按下时,发送按下的命令,当松开时再发送松开的命令,有按下必须有松开,否则PC会连续产生重复的字符,就像一个键被长按了一样,因为我在程序中先发了正常的键值,又发了全零包。
4 总结
配合STM32CubeMX,即使是USB使用起来也非常方便。
参考:
https://blog.csdn.net/weixin_41226265/article/details/133522580
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/shuang_sz/article/details/142875574
|
|