一、项目概述
本次参加手势翻页的项目,主要是实现如何驱动STM32H503的USB来模拟键盘或者鼠标,通过获取PAJ7620U2的隔空手势来实现对PC的外设驱动。本次项目使用了六个手势,分别为左、右、上、下扫,以及下压、抬起。对应的模拟键盘为:
PAJ_UP-------------Keyboard PageUp
PAJ_DOWN--------Keyboard PageDown
PAJ_LEFT-----------Keyboard LeftArrow
PAJ_RIGHT---------Keyboard RightArrow
PAJ_FORWARD---- Keyboard Home
PAJ_BACKWAR-----Keyboard End
本项目的重点与难点为如何驱动HID设备。
二、开发环境
1、MDK5.39
2、STM32CubeMAX6.2.0
三、开发硬件
2、PAJ7620U2 手势传感器 Grove 平台评估扩展板
四、开发步骤
1、使用stm32cubeMAX新建一个基于stm32H503RBTx的工程。
2、开启I2C1配置,IO为PB7、PB6,速率为400K快速模式:
3、打开外部晶振输入:
并配置总线时种为250M,并确认USB的总线时钟为48M
4、打开THREADX,并按下图配置相关配置。因为USBX需要TheadX来实现多任务系统。在配置中,我们主要配置时钟,是否创建ThreadX任务,以及配置ThreadX内存空间。
5、打开USB,配置为Device_Only模式,打开中断,GPIO选择PA12、PA13。
6、打开USBX,按下图依次选择。
配置USBX参数如下:
【注意】特别要注意第3与第4,如果分配太小,会出现在运行中挂机。
这些参数需要阅读USBX协议才能明白,我也是根据其他的大佬的文章来设置的。
接着打开参数,设置为USB
7、接打开工程设置中的高级配置,把下面两个选项钩选:
8、调整中断级别如下:
9、配置按外设生成单个的代码。
最后生成代码。就可以使用MDK来打开工程了。
【用户代码】
以上的工程创建,还不能驱动HID。还需要添加用户的代码。
1、打ux_device_keyboard.c,添加hid_keyboard并在函数中初始化。
2、打开app_usbx_device.c添加一个任务,代码如下:
/* USER CODE BEGIN MX_USBX_Device_Init1 */ /* Allocate the stack for usbx hid thread */ if (tx_byte_allocate(byte_pool, (VOID **) &pointer, 1024, TX_NO_WAIT) != TX_SUCCESS) { return TX_POOL_ERROR; } /* Create the usbx hid thread */ if (tx_thread_create(&ux_hid_read_thread, "hid_acm_read_usbx_app_thread_entry", usbx_hidkeyboard_thread_entry, 1, pointer, 1024, 20, 20, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) { return TX_THREAD_ERROR; } /* USER CODE END MX_USBX_Device_Init1 */
代码主要是动态创建任务,并指定hid_acm_read_usbx_app_thread_entry为入口函数。
3、添加PAJ7620驱动到工程中:
驱动我在前面的帖子里有介绍:【换取手持数字示波器】STM32U083实现手势识别功能-电子产品世界论坛 (eepw.com.cn)
4、将头文件加入到ux_device_keyboard.c中。同时编译获取手势状到,并更新到HID发送函数中,其代码如下:
static VOID usbx_hidkeyboard_thread_entry(ULONG thread_input) { /* USER CODE BEGIN app_ux_device_thread_entry */ UX_SLAVE_DEVICE *device; UX_SLAVE_CLASS_HID_EVENT hid_event; TX_PARAMETER_NOT_USED(thread_input); device = &_ux_system_slave->ux_system_slave_device; ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT)); PAJ7620U2_init(); while(1) { /* Check if the device state already configured */ if ((device->ux_slave_device_state == UX_DEVICE_CONFIGURED) && (hid_keyboard != UX_NULL)) { /* sleep for 10ms */ tx_thread_sleep(MS_TO_TICK(100)); hid_event.ux_device_class_hid_event_length = 8; hid_event.ux_device_class_hid_event_buffer[0] = 0; hid_event.ux_device_class_hid_event_buffer[1] = 0; int Gesture_Data = PAJ7620U2_Gesture_ReadData(); if( Gesture_Data != PAJ_NONE ) { switch (Gesture_Data) { case PAJ_UP: hid_event.ux_device_class_hid_event_buffer[2] = 0x4B; break; //Keyboard PageUp case PAJ_DOWN: hid_event.ux_device_class_hid_event_buffer[2] = 0x4E; break; //Keyboard PageDown case PAJ_LEFT: hid_event.ux_device_class_hid_event_buffer[2] = 0x50; break; // Keyboard LeftArrow case PAJ_RIGHT:hid_event.ux_device_class_hid_event_buffer[2] = 0x4F; break; // Keyboard RightArrow case PAJ_FORWARD: hid_event.ux_device_class_hid_event_buffer[2] = 0x4A; // Keyboard Home break; case PAJ_BACKWARD: hid_event.ux_device_class_hid_event_buffer[2] = 0x4A; // Keyboard End break; case PAJ_CLOCKWISE: break; case PAJ_ANTI_CLOCKWISE: break; case PAJ_WAVE: break; // default: break; } ux_device_class_hid_event_set(hid_keyboard, &hid_event); } else{ hid_event.ux_device_class_hid_event_buffer[2] = 0; ux_device_class_hid_event_set(hid_keyboard, &hid_event); } } else { /* sleep for 10ms */ tx_thread_sleep(MS_TO_TICK(10)); } } /* USER CODE END app_ux_device_thread_entry */ }
5、最后需要添加自定义的初始化函数:
VOID USBX_APP_Device_Init(VOID) { /* USER CODE BEGIN USB_Device_Init_PreTreatment_0 */ /* USER CODE END USB_Device_Init_PreTreatment_0 */ /* initialize the device controller HAL driver */ MX_USB_PCD_Init(); /* USER CODE BEGIN USB_Device_Init_PreTreatment_1 */ HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x00, PCD_SNG_BUF, 0x14); HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x80, PCD_SNG_BUF, 0x54); HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x81, PCD_SNG_BUF, 0x94); HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x01, PCD_SNG_BUF, 0xD4); HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x82, PCD_SNG_BUF, 0x114); /* USER CODE END USB_Device_Init_PreTreatment_1 */ /* Initialize and link controller HAL driver */ ux_dcd_stm32_initialize((ULONG)USB_DRD_FS, (ULONG)&hpcd_USB_DRD_FS); /* Start the USB device */ HAL_PCD_Start(&hpcd_USB_DRD_FS); /* USER CODE BEGIN USB_Device_Init_PostTreatment */ /* USER CODE END USB_Device_Init_PostTreatment */ }
其代码意思大家可以查阅相关资料,说实在话,我也没有弄明白。希望有大佬给科普一下。
然后将此函数添加工程任务初始化中:
到用户代码编写结束,主要是添加一个任务,创建任务入口函数,任务周期读取手势传感器的数据,并按USB 键盘的规则组装数据,并发送给上位机。
同时还需要添加USB_HID的初始化代码。
视频链接:https://www.bilibili.com/video/BV1NZ421g7GM/?pop_share=1