一、项目介绍
本次任务选择的方向是智能设备。
本设计旨在实现一款基于STM32H533开发板及手势传感器的智能辅助键盘,通过手势控制实现特殊按键操作,如上下翻页、常用组合按键Ctrl+C及Ctrl+V等。改变特殊按键或者组合按键的操作方式,实现手部操作的放松,在忙碌的时候频繁操作这些案件导致手部僵硬不适,这都是码农们不希望出现的。
该设计依托于开发板的USB功能,结合板载按键、LED指示灯以及转接板上的手势传感器模块,为用户提供一种全新的键盘操作方式,放松身体。
二、硬件介绍
本次使用的第一个硬件就是于贸泽电子采购的STM32H533开发板:
该板是STM32Nucleo-64板系列中的一个,STM32 Nucleo板,作为一款兼具低成本与易用性的开发平台,以其多样化的规格满足了不同需求。本次H533项目特别选用了64引脚封装的STM32 Nucleo-64板,它为用户开启了一扇通往创新的大门——以经济实惠的方式,灵活选取STM32微控制器所提供的多样性能和功耗组合,从而轻松尝试新理念并快速构建原型。对于兼容板而言,外部SMPS(开关模式电源)的引入,在运行模式下显著降低了功耗,进一步提升了效率。该平台特性卓越:
- 核心采用LQFP64封装的STM32微控制器,与ARDUINO平台共享资源,包括1个用户LED、1个用户按钮及1个复位按钮,便于开发者快速上手。
- 配备32.768 kHz晶体振荡器及24 MHz HSE(高速外部时钟),确保系统时钟的精准与稳定。
- 板载丰富连接器:ARDUINO V3扩展连接器,以及意法半导体的morpho延长引脚头,全面开放STM32 I/O资源,满足多样化连接需求。
- 灵活的供电选项,支持ST-LINK、USB VBUS及外部电源,确保在各种场景下均能稳定工作。
- 板上集成带USB重新枚举功能的ST-LINK调试器/编程器,提供大容量存储器、虚拟COM端口及调试端口,大大简化了开发流程,提升了调试效率。
主控平台板载MCU为STM32H533RET6,基于Arm Cortex-M33内核,主频可达250MHz,具备足够的处理能力和丰富的外设资源,再加上板载按键与LED,可以利用开发板上的按键作为智能辅助键盘功能的开启/关闭开关,通过板载LED进行状态展示(闪烁表示未开启,常量表示已开启)。
接下来就是最重要的传感器模块——手势传感器(PAJ7620U2模块):
PAJ7620是原相科技( PixArt)公司推出的一款光学数组式传感器,内置光源和环境光抑制滤波器集成的 LED,镜头和手势感测器在一个小的立方体模组,能在黑暗或低光环境下工作。同时传感器内置手势识别,支持 9个手势类型和输出的手势中断和结果。并且内置还提供接近检测功能,可用于感测物体接近或离开。采用IIC通信,使用的物理接口做是HY2.0-4的座。
还有一个就是需要做转接板,起初的时候想要直接通过线材连接,不过板卡和传感器的位置最好还是固定的,就做一个转接板,这一部分在PCB设计方面介绍。
三、原理图及PCB设计
本部分简单介绍一下转接板的介绍和设计,其中最重要的接口就是手势传感器的转接口,需要一个同样的HY2.0-4的座进行传感器的连接,我看一下IIC的接口用到的引脚情况:
主要用到的是PB6和PB7,我们将这两个引脚转接过来,不管采用软件模拟的方式还是硬件IIC方式都是非常方面的;
接下来就是功能需求中的状态LED,采用GPIO直接控制的方式进行,这里我们选取的是PA5~PA7引脚:
结合到开发板上的资源可以看到,都是在CN10上:
为了实现差异化安装,接下来采用ARDUINO V3扩展器的CN6进行供电,最后全部的原理图如下:
这里我们只选取了CN7和CN10的上部分引脚进行连接,最后的PCB效果如下:
传感器通过铜柱进行固定安装,通过2.0间距的线材进行电气连接;转接板通过排针排母的方式与开发板连接。
四、硬件框图
硬件连接主要包含三部分:开发板、转接板、传感器模块,整体通过USB线与PC机相连,效果如下:
整体思路是通过开发板的USB与电脑连接,并可以通过枚举是电脑将开发板识别成键盘,这个时候通过采集手势传感器的数据,识别特定的手势,并处理成按键逻辑的操作,进而实现电脑按键的键入。
实际整体硬件连接如下:
五、软件设计及功能说明
我们在进行软件设计的时候首先需要明确的就是需要实现哪些功能?用了哪些硬件资源?通过硬件分析我们已经知道使用了哪些硬件资源了,接下来就说一说需要实现的功能都有哪些:
1、开发板连接后需要实现USB枚举并且可以被设备是键盘设备;
2、上电初始化后不是可以直接使用的,通过板载按键进行控制智能辅助键盘是否开启,并通过板子LED指示,这一点可以减少不使用期间的误操作的发生概率;
3、智能辅助键盘开启后的手势的识别,这里认定有效的手势包括上、下、左、右;
4、手势控制逻辑:默认是模式一或者手势下切换到模式一,这个时候向左、向右手势被识别为pgup和pgDn按键,向上为Enter键(按下抬起为一次操作),手势下被切换到模式二,这个时候向左、向右手势被识别Ctrl+C以及Ctrl+V的组合按键,向上为Enter键(按下不抬起,再一次为抬起)
通过功能分析进行软件设计:
开发环境:我们使用KEIL作为软件开发环境,通过STM32CubeMX配置基础代码,包括时钟、USB、GPIO、I2C等外设的初始化。
USB通信:配置STM32H533开发板为USB HID设备,实现与主机的键盘数据传输。
手势传感器驱动:编写PAJ7620U2模块的驱动程序,包括初始化、配置为手势检测模式、读取手势数据等。
中断与轮询:由于手势传感器的中断上报接口未在座上,采用轮询方式不断检测是否有手势被识别。同时,利用外部中断处理板载按键的开启/关闭操作。
手势识别与处理:
模式一:默认模式或手势下切换到模式一。此时,向左、向右手势被识别为PgUp和PgDn按键,向上手势被识别为Enter键(按下抬起为一次操作)。
模式二:手势下切换到模式二。此时,向左、向右手势被识别为Ctrl+C和Ctrl+V的组合按键,向上手势被识别为Enter键(按下不抬起,再一次为抬起)。
状态指示:通过转接板上的LED指示灯展示当前智能辅助键盘的开启/关闭状态、手势识别模式等信息。
软件流程图如下:
关键代码说明:
本次使用的UBSx协议栈,通过ThreadX实时操作系统进行控制,ThreadX针对USBx设有专门的处理栈,使得处理更为高效便捷,采用实时操作系统后,在`main`函数中注意到新增了`MX_ThreadX_Init();`,跳转到`tx_initialize_kernel_enter()`函数内部,随后定位至`tx_application_define()`的入口。所有的初始化流程都在这里了,其中尤为关键的是`MX_USBX_Device_Init(VOID *memory_ptr)`的调用,由于使用了实时操作系统,我们不会进入到主程序的while中,而是在实时操作系统中循环,我们可以通过初始化阶段如下模式添加任务分支:
if (tx_byte_allocate(byte_pool, (VOID**) &pointer,
TX_APP_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
return TX_POOL_ERROR;
}
/* Create tx app thread. */
if (tx_thread_create(&tx_app_thread, "tx app thread", tx_app_thread_entry, 0, pointer,
TX_APP_STACK_SIZE, TX_APP_THREAD_PRIO, TX_APP_THREAD_PREEMPTION_THRESHOLD,
TX_APP_THREAD_TIME_SLICE, TX_APP_THREAD_AUTO_START) != TX_SUCCESS)
{
return TX_THREAD_ERROR;
}
USB的初始化在USBX_APP_Device_Init中:
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 */
}
接下来是手势传感器的驱动和采集:
void tx_app_thread_entry(ULONG thread_input)
{
/* USER CODE BEGIN tx_app_thread_entry */
while(1)
{
if(Button_State == 1)
{
tx_app_cnt++;
if(tx_app_cnt>=20)
{
tx_app_cnt = 0;
if(Button_State == 1&& gesture_init_flag == 0)
{
GestureDeal();
}
}
}
tx_thread_sleep(1);
}
/* USER CODE END tx_app_thread_entry */
}
static void GestureDeal(void)
{
ret = 0;
ret = PAJ7620_get_gesture(&gesture);
if (ret == PAJ7620_EOK)
{
switch (gesture)
{
case PAJ7620_GESTURE_DOWN:
{
if(gesture_mode == 0)
{
gesture_mode = 1;
LED1_On;
}
else
{
gesture_mode = 0;
LED1_Off;
}
break;
}
case PAJ7620_GESTURE_LEFT:
{
gesture_LEFT_flag = 1;
LED2_Toggle;
break;
}
case PAJ7620_GESTURE_RIGHT:
{
gesture_RIGHT_flag = 1;
LED3_Toggle;
break;
}
case PAJ7620_GESTURE_UP:
{
gesture_UP_flag = 1;
LED3_Toggle;
break;
}
default:
{
break;
}
}
}
}
然后是手势与按键联动的处理:
VOID usbx_hid_thread_entry(ULONG thread_input)
{
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;
while(1)
{
if(device->ux_slave_device_state == UX_DEVICE_CONFIGURED && hid_keyboard != UX_NULL)
{
tx_thread_sleep(MS_TO_TICK(10));
if(gesture_LEFT_flag == 1)
{
gesture_LEFT_flag = 0;
if(gesture_mode == 0)
{
GetKeyboardData(&hid_event,0x4B);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
}
else
{
GetKeyByte1Data(&hid_event,Byte1_Left_Ctrl);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
GetKeyboardData(&hid_event,0x06);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
}
}
if(gesture_RIGHT_flag == 1)
{
gesture_RIGHT_flag = 0;
if(gesture_mode == 0)
{
GetKeyboardData(&hid_event,0x4E);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
}
else
{
GetKeyByte1Data(&hid_event,Byte1_Left_Ctrl);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
GetKeyboardData(&hid_event,0x19);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
}
}
if(gesture_UP_flag == 1)
{
gesture_UP_flag = 0;
if(gesture_mode == 0)
{
GetKeyboardData(&hid_event,0x28);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
}
else
{
if(enter_state == 0)
{
enter_state = 1;
GetKeyboardData(&hid_event,0x28);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
}
else
{
enter_state = 0;
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
}
}
}
}
else
{
tx_thread_sleep(MS_TO_TICK(10));
gesture_LEFT_flag = 0;
gesture_RIGHT_flag = 0;
gesture_UP_flag = 0;
}
}
}
按键的对应的HID键值可以通过搜索进行确认,数据结构上是一个8个字节的数据,注意不同按键在数据结构中的位置不一样,例如本次用的“Ctrl”就在数据结构的第一个位置上。
六、预期效果展示
主要节点的展示包括USB枚举成功,电脑设备识别正常:
下面是我们使用键盘测试工具采集到的一些按键的键入情况:
具体的测试过程与效果可以查看视频讲解部分。
七、心得体会
通过本设计,用户可以通过手势控制实现智能辅助键盘的特殊按键操作,如上下翻页、常用组合按键Ctrl+C及Ctrl+V等。该设计不仅改变了传统的键盘操作方式,降低了手部疲劳,还提高了工作效率。同时,通过转接板的设计,实现了手势传感器模块的固定与I2C接口的转接,增加了系统的灵活性和可扩展性。
也通过本次活动体验了贸泽电子方便的采购体验,我们可以通过全面的产品信息介绍快速了解产品,网站上有很多产品的应用等信息,查找也非常的方便,学习收获两不误。