(6)STM32 USB设备开发-USB键鼠一体设备

例程:STM32USBdevice: 基于STM32的USB设备例子程序 - Gitee.com

键鼠一体的应用场景如集合器,比如我们在网上购买的键鼠套装,是将2.4G集合到一个USB接收器中,这个USB接收器对于PC来说就是一个键鼠一体设备。或者我们可以自制一个带有鼠标摇杆的键盘等场景。

键鼠一体实现方式是在报告描述符中描述两个设备,即键盘设备和鼠标设备,报告描述就是将键盘描述和鼠标描述何为一个,那么PC如何区分这两个报告呢?通过REPORT_ID来区分,下面展示一下使用DT工具生成的报告描述符。

其中键盘REPORT_ID为1,鼠标REPORT_ID为2.在软件发送消息时,使用 REPORT_ID 作为报告的第一个字节,可以让主机准确区分不同类型的报告。也就是我们需要在额外的报告消息中添加第一个字节为REPORT_ID即可。

(6)STM32 USB设备开发-USB键鼠一体设备_第1张图片

我们在keyboard代码的基础上进行修改。

前置操作步骤可以看我上一篇关于keyboard的教程,这篇我们之列出差异。

首先我们需要将上面的报告描述符添加到代码Middlewares\ST\STM32_USB_Device_Library\Class\HID\Src\usbd_hid.c中,

__ALIGN_BEGIN static uint8_t HID_KEYMOUSE_ReportDesc[HID_KEYMOUSE_REPORT_DESC_SIZE]  __ALIGN_END = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x06,                    // USAGE (Keyboard)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x01,                    //   REPORT_ID (1)
    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
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x02,                    // USAGE (Mouse)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x02,                    //   REPORT_ID (2)
    0x09, 0x01,                    //   USAGE (Pointer)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x05, 0x09,                    //     USAGE_PAGE (Button)
    0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
    0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
    0x95, 0x03,                    //     REPORT_COUNT (3)
    0x75, 0x01,                    //     REPORT_SIZE (1)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x75, 0x05,                    //     REPORT_SIZE (5)
    0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
    0x09, 0x30,                    //     USAGE (X)
    0x09, 0x31,                    //     USAGE (Y)
    0x09, 0x38,                    //     USAGE (Wheel)
    0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
    0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
    0x75, 0x08,                    //     REPORT_SIZE (8)
    0x95, 0x03,                    //     REPORT_COUNT (3)
    0x81, 0x06,                    //     INPUT (Data,Var,Rel)
    0xc0,                          //   END_COLLECTION
    0xc0                           // END_COLLECTION
};

将代码中HID_KEYBOARD_REPORT_DESC_SIZE替换为HID_KEYMOUSE_REPORT_DESC_SIZE,将HID_KEYBOARD_REPORT_DESC_SIZE替换为HID_KEYMOUSE_REPORT_DESC_SIZE。

在Middlewares\ST\STM32_USB_Device_Library\Class\HID\Inc\usbd_hid.h中定义HID_KEYMOUSE_REPORT_DESC_SIZE

#define HID_KEYMOUSE_REPORT_DESC_SIZE 119U

这里我们就把USB描述符相关的修改完成了,剩下我们就是编写测试逻辑。

在Core\Src\freertos.c文件中添加鼠标结构体

/* USER CODE BEGIN PTD */
/* 鼠标报文结构体 */ 
 struct mouseHID_t {
    uint8_t reportId;
    uint8_t buttons;
    int8_t x;
    int8_t y;
    int8_t wheel;
};
/* USER CODE END PTD */

第一个字节为report ID,固定为2,因为报告描述符是这样定义的。

在测试任务中代码如下

void StartDefaultTask(void *argument)
{
  /* init code for USB_DEVICE */
  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN StartDefaultTask */
    uint8_t keyBoard[9] = {1, 0, 0, 0, 0, 0, 0, 0, 0};
    uint8_t key1Status = 0;
    uint8_t key2Status = 0;
    TickType_t xLastFlashTime = osKernelGetTickCount();
    /* Infinite loop */
    for (;;) {
        // 获取当前时间戳
        TickType_t xCurrentTime = osKernelGetTickCount();
        // 检查是否已经过了 1 秒(pdMS_TO_TICKS 函数将毫秒转换为系统时钟节拍)
        if ((xCurrentTime - xLastFlashTime) >= pdMS_TO_TICKS(1000)) {
            // 切换 LED1 的状态
            HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
            // HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
            // 更新上一次的时间戳
            xLastFlashTime = xCurrentTime;
        }
        if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_SET) {
            if (key1Status == 0) {
                keyBoard[3] = 0x39;  // 设置caps lock按键状态
                USBD_HID_SendReport(&hUsbDeviceFS, keyBoard, sizeof(keyBoard));
                key1Status = 1;
            }
        } else {
            if (key1Status == 1) {
                key1Status = 0;
                keyBoard[3] = 0;  // 清除按键状态
                USBD_HID_SendReport(&hUsbDeviceFS, keyBoard, sizeof(keyBoard));
            }
        }
        if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_SET) {
        /* 发送鼠标报文(一直发送该报文,鼠标会水平向右移动) */
        struct mouseHID_t mouseHID;
        mouseHID.reportId = 2;
        mouseHID.buttons = 0b00001000;
        mouseHID.x = -10;
        mouseHID.y = 0;
        mouseHID.wheel = 0;
        USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t *)&mouseHID, sizeof(struct mouseHID_t));
        }

    osDelay(1);
  }

键盘数组改为了uint8_t keyBoard[9] = {1, 0, 0, 0, 0, 0, 0, 0, 0};,第一字节为1,必须与报告描述符中定义相同。

按下按键1会切换大小写,这时我们的键盘灯会跟着变化。按键2按下时鼠标会向左移动。

你可能感兴趣的:(STM32,USB设备开发,stm32,嵌入式硬件,单片机)