基于ESP32实现的USB键盘鼠标设备
项目介绍
这是我在参与的第二个硬禾2023寒假在家练项目。上一个StepPico是基于树莓派RP2040做的一个电子水平仪,当时用的是Arduino,做起来很简单,学下来感觉还是太浅了,于是在2月14号又参与了这个基于ESP32的项目。
这次是一个基于ESP32-S2实现USB键盘鼠标设备的项目,采用C语言进行开发,基于ESP-IDF和Clion的一个开发环境,最后实现的是一个通过PWM波形输入和ADC输入模拟USB HID(Universal Serial Bus-Human Interface Device的缩写)。
项目提供的资料不是很清晰,课程提供的指导也比较有限,难度比上一个项目高很多。不过在这个项目真是学到了挺多新的姿势,在里面还学到了FreeRTOS的一些使用方法。
硬件介绍
这个项目提供了一个ESP32-S2-MINI开发板和一块MSP430扩展板。
ESP32-S2 是一款高度集成、高性价比、 低功耗、主打安全的单核 Wi-Fi SoC,具 备强大的功能和丰富的 IO 接口。使用 乐鑫ESP-IF开发环境,我们可以通过USB 对其编程,作为带wifi的MCU单独使用, 也可以烧录AT固件,作为WiFi透传模块 与RP2040游戏机套件结合使用。
开发步骤
一、搭建环境
一般都是推荐用Visual Studio Code,但是我是自己用惯了JetBrains家的产品(主要是 花了钱买的),而且看了一下Clion官方也有对ESP-IDF的支持文档,就干脆用了Clion。那实际开发体验还是很不错的。
1. 安装ESP-IDF
参考文档:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/get-started/linux-macos-setup.html
这里建议安装的时候使用乐鑫自己的源,不然由于众所周知的原因,直接从GitHub上去下载的话慢不慢还是一说,可能都无法正常安装。
使用乐鑫源:
export IDF_GITHUB_ASSETS="dl.espressif.com/github_assets"
2. 配置Clion
参考文档:https://www.jetbrains.com/help/clion/esp-idf.html
表 1关键要配置好环境变量
表 2实际效果
二、程序设计与实现
软件流程图
1. 摇杆的PWM输入读取
这个项目里是有个PWM波形的发生器,摇杆在X、Y两个方向上拨动时会分别改变PWM波形的频率和占空比,波形输出到GPIO2。
手里正好有示波器,通过示波器测量就可以知道X轴影响的是频率,Y轴影响占空比。
我这里是将GPIO配置为中断模式,中断类型设置为GPIO_INTR_ANYEDGE,当收到中断时将当前时间和边沿方向放入队列,队列由一个独立的task进行读取,这个task根据边沿上升下降的时间差分别计算出脉冲频率和占空比放入全局变量PwmData。
这里要吐槽下课程视频里说的要用MCPWM来进行实现简直是欺负小白啊,我愣是在这里耽搁了一天,example怎么也编译不通过,后来才发现ESP32-S2不支持MCPWM。
参考文档:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/gpio.html
2. ADC输入读取
表 3 旋转编码器与按钮输入部分原理图
这个做起来比较简单,但是之前不知道还可以通过这种改变电压的方式来提高IO利用率,在一个GPIO上实现多个按键的输入。我在这个例子里只需要用到旋转编码器的按键事件和按键的按下事件,通过原理图找到对应的引脚,使用万用表分别测量出两个按钮按下时的电压。然后使用乐鑫官方的esp_button组件的adc模式,分别根据测得的电压范围配置两个按钮即可。
参考文档:https://docs.espressif.com/projects/espressif-esp-iot-solution/en/latest/input_device/button.html
3. USB输出
这个部分参考ESP-IDF的官方范例esp-idf/examples/peripherals/usb/device/tusb_hid,使用TinyUSB进行实现键盘和鼠标事件的发送。
在app_main中我创建了一个周期计时器,每隔10ms读取PwmData判断摇杆是否移动,并根据摇杆距离中心点的距离计算出鼠标应该分别往X和Y轴移动的距离,调用tud_hid_mouse_report进行发送。
模拟键盘输入则更简单一点,在adc_button的回调中使用tud_hid_keyboard_report依次发送eetree.com的按键事件即可。
4. 固件编译
在Clion的运行配置菜单里找到app,点击左边的小锤子即可编译固件,产生的文件会放在项目目录的cmake-build-debug目录内。
5. 串口调试
在这个项目里面如果我们需要调试信息的话要么是往LCD上进行打印,要么就是通过串口进行输出,而通常来说串口更方便一些。要使用串口首先我们就需要一个TTL-USB转换器,这个可以在某宝上进行购买,很便宜。然后插入到下图的针脚上,用命令idf.py monitor即可启动监视。在mac系统上可以用ls /dev/cu.* 查看串口设备,然后用-p参数指定要监视的设备端口。如 idf.py -p /dev/cu.usbmodem01 monitor。
表 4红框圈住的两个就是TX和RX口
表 5串口输出
6. 固件烧录(下载)
因为我用的是Clion,从工具栏中找到这个配置选项,选择flash即可进行烧录,也可以选择app-flash完成编译+烧录动作。
三、遇到的问题
之前用Arduino基于8266、Step Pico的RP2040进行开发感觉功能做起来都很简单,大部分时候都是对GPIO进行操作。在这个项目里面硬禾学堂的电路设计算是让我打开了新世界的大门,才知道按钮还可以这么做。原来只用一个IO也可以实现多个按钮的响应。但是随之带来的是PWM和ADC的学习,而在ESP-IDF的环境下,由于社区组件不像Arduino那么丰富且易用,导致这些简单功能的实现都要四处查找资料、翻看组件的源码通过其实现来了解如何使用。
在开发摇杆控制程序的时候,根据视频教程的指导,应该是使用MCPWM进行开发,但是在开发的时候从乐鑫官方示例上面copy下来的代码却死活编译不通过,让第一次接触ESP-IDF的我甚是绝望。后面才知道MCPWM是需要芯片支持的,而我们这个项目中所使用的ESP32-S2并不支持。
后来通过群友“aramy”的提示,决定用IO外部中断来进行实现PWM信号的读取。因为喜欢玩3D打印机,改装风扇控制系统的时候正好学习过PWM,对此并不陌生,翻看乐鑫的官方文档之后很快就完成了这个功能。
四、未来计划
因为这次活动参加的比较晚,给我的时间不太多,我计划之后继续完成其他参考项目,包括完成LCD驱动的移植并基于LVGL实现一个图形界面,在屏幕上显示温度以及摇杆的指向方向等信息。
最后看一下Git log,实际开发大概是用了3、4个晚上的时间。
表 6 git log
参考资料:
- TinyUSB官方文档:https://docs.tinyusb.org/en/latest/
- FreeRTOS官方文档:https://www.freertos.org/zh-cn-cmn-s/freertos-core/overview.html