周所周知,#STM32 有着板载#USB 接口,之前我们利用STM32的USB实现VCP(虚拟串口)来代替原始串口实现串口。
但是USB的功能还有很多很多,本期我们来介绍利用STM32的USB实现鼠标输入功能。
硬件平台采用STM32F407ZGT6
1、HID
#HID(Human Interface Device)全称#人机接口设备,是一类允许人类与计算机进行交互的设备。我们常用的鼠标、键盘、触摸屏都属于HID设备。它定义了输入/输出数据的格式和协议,不需要专用驱动就能识别。
例如目前在用的鼠标接入电脑时,系统会将其识别为HID鼠标。
HID设备以中断方式与主机通信,定时上报数据主机通过GetReport/SetReport与设备进行数据交互数据采用HID报告(HIDReport)格式,描述鼠标移动、按键状态等
要在STM32中实现鼠标输入,就是STM32作为主机HOST来获取鼠标设备的HIDReport。下面介绍#CubeMX 的配置和部分代码。
2、CubeMX配置
首先开启一组USART用来输出调试信息,接着开启USB_OTG_FS功能,模式选择为主机模式(Host_Only)。
由于对USB设备的性能要求不高,因此不用选择USB_OTG_HS而选择FS即可。
在拓展包中的USB_HOST中,为FS选择HID设备。
对于下方的HID配置详细解释如下:
条目 | 作用 |
USBH_MAX_NUM_ENDPOINTS | USB 接口支持的最大端点 |
USBH_MAX_NUM_INTERFACES | 每个 USB 设备支持的最大接口
数量 |
USBH_MAX_NUM_SUPPORTED_CLASS | 最大 USB 设备类数量 |
USBH_MAX_NUM_CONFIGURATION | USB 主机库支持的最大配置数量 |
USBH_KEEP_CFG_DESCRIPTOR | 保留 USB 设备的配置描述符 |
USBH_MAX_SIZE_CONFIGURATION | 设备配置描述符最大允许大小 |
USBH_MAX_DATA_BUFFER | 主机库在内存中分配的数据缓冲区的最大大小 |
USBH_DEBUG_LEVEL | 调试信息的输出级别 |
这里其他的都选择默认配置,只有最后的调试信息输出级别,推荐使用级别2.
而且需要注意的是,USB库的调试信息使用printf输出,这要求我们对系统进行串口重定向。大家可以参考#串口重定向 那期的文章基于HAL库和CubeMX的STM32 串口通信以及重定向 (点击连接跳转)。
由于我的板子需要单独开启USB电源,因此需要开启一个GPIO来作为USB电源控制。
将一个GPIO设置为OutPut模式之后,同样的可以在USB_HOST中配置电源控制为GPIO:Output。
3、时钟要求
这个晶振时钟也是在CubeMX中配置的,但是这里要单独强调一下,否则会导致工作失败。
USB正常工作要求时钟为48MHZ,但是CubeMX默认工程中大家需要注意修改HSE外部高速时钟的输入和自己芯片的实际输入是否一致,否则可能会导致工作失败。
4、文件结构和使用
CubeMX生成工程之后会出现USB主机库,这里是不需要我们修改什么东西的,大家把目光着重放到main.c中。
while (1)
{
/* USER CODE END WHILE */
MX_USB_HOST_Process();
/* USER CODE BEGIN 3 */
}
这个函数是处理 USB 主机的状态机和相关事件,是 USB 主机库运行机制的核心部分,负责推进 USB 主机的状态机,使主机能够在不同状态之间切换,如未初始化、已初始化、已连接设备、已配置设备等,确保能根据设备连接状态执行相应的操作。
接着我们在头文件中包含下面这个头文件
#include"usbh_hid.h"
之后我们编写鼠标回调函数:
voidUSBH_HID_EventCallback(USBH_HandleTypeDef *phost)
{
HID_MOUSE_Info_TypeDef *mouse_info = USBH_HID_GetMouseInfo(phost);
if (mouse_info != NULL)
{
printf("X: %dtY: %dtButtons: L:%d M:%d R:%drn",
mouse_info->x,
mouse_info->y,
mouse_info->buttons[0],
mouse_info->buttons[1],
mouse_info->buttons[2]);
}
}
每当我们运动鼠标的时候,这个中断回调函数就会触发,因此我们可以获得鼠标运动状态。
4、鼠标屏幕相结合
我们在回调函数中将鼠标运动状态累加起来就可以得到鼠标的位置了,接下来我们设置一下当按下鼠标左键时候,可以在屏幕中画图。按下鼠标右键的时候可以清空画布。