前言
STM32CubeMX的USB HID程式碼是個三鍵滑鼠範例,我們將使用它在STM32F072RBT的公板上執行
然後再用USB HID Descriptor Tool的Mouse描述來覆蓋STM32CubeMX原先的
操作環境
- Board:32F072BDISCOVERY
- IDE:STM32CubeIDE
- Code:STM32CubeMX
1. STM32CubeMX
勾選USB功能
勾選USB Role Device(FS)。有的MCU型號支援HOST/Device/OTG
設定不做修改
勾選USB_DEVICE,選擇Human Interface Device Class(HID)
- HID_FS_BINTERVAL:主機讀取設備的時間間隔
- USBD_MAX_NUM_INTERFACE:支援的endpointer數量
- 這些參數都將存在 usbd_conf.h
Clock Configuration裡,F072的USB時脈使用APB1,改為48Mhz
注意
F072的USB PHY在USB_DP上內建了升壓電阻,所以外部電路無須升壓電位
如果你選用的MCU沒有內建升壓電阻,記得要加上,不然USB插上主機會沒有反應
2. STM32CubeIDE
下列是STM32CubeMX針對HID產生的檔案,
- usbd_desc.c:USB裝置的列舉,描述
- usbd_hid.c/.h:HID裝置的描述
- usbd_conf.h:endpointer技援數量,主機訪問間隔,descriptor size等參數
usbd_hid.c的HID_MOUSE_ReportDesc[]是三鍵的滑鼠descriptor
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01,
0x09, 0x02,
0xA1, 0x01,
0x09, 0x01,
0xA1, 0x00,
0x05, 0x09,
0x19, 0x01,
0x29, 0x03,
0x15, 0x00,
0x25, 0x01,
0x95, 0x03,
0x75, 0x01,
0x81, 0x02,
0x95, 0x01,
0x75, 0x05,
0x81, 0x01,
0x05, 0x01,
0x09, 0x30,
0x09, 0x31,
0x09, 0x38,
0x15, 0x81,
0x25, 0x7F,
0x75, 0x08,
0x95, 0x03,
0x81, 0x06,
0xC0, 0x09,
0x3c, 0x05,
0xff, 0x09,
0x01, 0x15,
0x00, 0x25,
0x01, 0x75,
0x01, 0x95,
0x02, 0xb1,
0x22, 0x75,
0x06, 0x95,
0x01, 0xb1,
0x01, 0xc0
};
上列descriptor可以複製到網站做翻譯,比較好閱讀修改
USB标准请求及描述符在线分析
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x03, // Usage Maximum (0x03)
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,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x05, // Report Size (5)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
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,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x09, 0x3C, // Usage (Motion Wakeup)
0x05, 0xFF, // Usage Page (Reserved 0xFF)
0x09, 0x01, // Usage (0x01)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x02, // Report Count (2)
0xB1, 0x22, // Feature (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0xB1, 0x01, // Feature (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
// 74 bytes
上述HID descriptor描述了 三個按鈕+XY方向 4個bytes的裝置
- 第一個byte,bit0為左鍵,bit1為右鍵
- 第二個byte為X軸(0~127向右,-1~-127向左)
- 第三個byte為Y軸(0~127向下,-1~-127向)
- 第四個byte為scroll軸(0~127向上,-1~-127向下)
在main.c加入應用程式,按下User按鍵(PA0)後,鼠標將向執行 右>下>左>上 頁面上>下 按下右鍵
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usbd_hid.h"
/* USER CODE END Includes */
int main(void)
{
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == 1)
{
extern USBD_HandleTypeDef hUsbDeviceFS;
int8_t data[4] = {0,0,0,0};
//X-right
data[1] = 127;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
HAL_Delay(500);
//Y-down
memset(data, 0, 4);
data[2] = 127;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
HAL_Delay(500);
//X-left
memset(data, 0, 4);
data[1] = -127;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
HAL_Delay(500);
//Y-up
memset(data, 0, 4);
data[2] = -127;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
HAL_Delay(500);
//scroll-up
memset(data, 0, 4);
data[3] = 127/2;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
HAL_Delay(500);
//scroll-up
memset(data, 0, 4);
data[3] = -127/2;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
HAL_Delay(500);
//key-right
memset(data, 0, 4);
data[0] = 2;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
HAL_Delay(15);
memset(data, 0, 4);
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
//HAL_Delay(200);
}
}
}
3. USB HID Descriptor Tool
這是USB協會提供用來編輯HID描述的工具
執行它並且開啟dt2_4_HID Descriptor Tool\MSDEV\Projects\test\mouse.hid
mouse.hid描述了一個 三鍵+XY 的滑鼠;少了Page Scroll "Usage (Whell)",HID package 3 bytes
把mouse.hid覆蓋usbd_hid.c的HID_MOUSE_ReportDesc[]
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
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)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
// 50 bytes
然後把usbd_hid.h的HID_MOUSE_REPORT_DESC_SIZE 長度改為50
main.c的應用程式,傳輸封包改為3 bytes,取消Page Scroll
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == 1)
{
extern USBD_HandleTypeDef hUsbDeviceFS;
int8_t data[4] = {0,0,0,0};
//X-right
data[1] = 127;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
HAL_Delay(500);
//Y-down
memset(data, 0, 4);
data[2] = 127;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
HAL_Delay(500);
//X-left
memset(data, 0, 4);
data[1] = -127;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
HAL_Delay(500);
//Y-up
memset(data, 0, 4);
data[2] = -127;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
HAL_Delay(500);
//scroll-up
// memset(data, 0, 4);
// data[3] = 127/2;
// USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
// HAL_Delay(500);
//scroll-up
// memset(data, 0, 4);
// data[3] = -127/2;
// USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
// HAL_Delay(500);
//key-right
memset(data, 0, 4);
data[0] = 2;
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
HAL_Delay(15);
memset(data, 0, 4);
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
//HAL_Delay(200);
}
}