打印
[STM32F4]

STM32F4的USB接口学习笔记-虚拟键盘

[复制链接]
382|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-10-17 08:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
实现用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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1867

主题

15482

帖子

11

粉丝