一、项目目标
实现一个USB鼠标&键盘复合设备,摇动游戏手柄实现鼠标的移动,一个按键实现左键点击,另一个按键按下实现键盘敲入一串字符"eetree.cn"
二、环境搭建
2.1platformio简介
Platform是一个基于VScode的插件,利用了vscode强大的扩展extension功能,使得开发者可以在vscode中直接调用gcc、jlink、gdb等进行开发、调试。
2.2安装准备工作(windows为例)
1、python(我目前的版本是3.8.5,其他文章有提过PlatformIO只支持python2的,那应该是以前的事,python2在2021年2月停止提供支持,PlatformIO目前也已经使用python3来做脚本)。
2、VScode
3、PlatformIO插件
4、科学上网
2.3创建工程
打开 PIO Home:打开新的 VSCode 的窗口,点击左侧拓展栏的小蜜蜂图标,就能打开 PIO Home 页面了,然后选择右侧的新建工程的按钮。
点击项目操作按钮的 + New Project,在弹窗中分别填入或选择 Name、Board、Framework 点击 Finish:
稍作等待,PIO 会自动根据选择的 Board 和 Framework 配置工程并且下载需要用到的编译工具,需要的编译依赖什么的 PIO 通通帮我们搞定,一段时间过后项目工程就新建完成了,打开 src
文件夹下的 main.cpp
如下:
三、模块调试
3.1 EC11部分
编码器具有一个磁盘,该磁盘具有均匀分布的接触区,这些接触区连接到公共引脚C和两个其他单独的接触引脚A和B,如下所示。
当磁盘逐步开始旋转时,引脚A和B将开始与公共引脚接触,因此将产生两个方波输出信号。 如果我们仅对信号脉冲进行计数,则可以使用两个输出中的任何一个来确定旋转位置。但是,如果我们也要确定旋转方向,则需要同时考虑两个信号,两个输出信号彼此之间相差90度。如果编码器顺时针旋转,则输出A将在输出B之前。
因此,如果我们每次计算信号从高到低或从低到高变化的步数,我们就会注意到那时两个输出信号的值相反。如果编码器逆时针旋转,则输出信号具有相等的值。因此,考虑到这一点,我们可以轻松地对控制器进行编程以读取编码器位置和旋转方向。
但是本次EC11的硬件设计采用的是检测电压来判断按下的按键,因此需要首先对硬件进行测试,最终可以得出没有按键按下时A_Out引脚值大约为7341,KEY_A按键按下的值大约为2225,KEY_C按下的值大约为6032,旋钮左转的值大约为6651,旋钮右转的值大约为7000,因此可根据以上值进行判断,此部分测试代码如下:
#include <Arduino.h>
#include "TFT_espi.h"
#define KeyPin 1
#define KeyCh 0
TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
uint32_t adc_val = 0;
double voltage = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello world");
// KeyCh,设置频率为1kHz,分辨率为12位
ledcSetup(KeyCh, 1000, 12);
tft.init();
tft.setTextSize(1);
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
}
void loop() {
// put your main code here, to run repeatedly:
adc_val = analogRead(KeyPin);
voltage = (((double)adc_val)/4095)*3.3;
tft.drawString("val:", 0, 32, 2);
tft.drawFloat(adc_val, 2, 32, 32);
tft.drawString("vol:", 0, 48, 2);
tft.drawFloat(voltage, 2, 32, 48);
ledcWrite(KeyCh, adc_val);
delay(100);
switch (adc_val)
{
case 7250 ... 8000:
break;
case 6900 ... 7200:
tft.drawString("Right ", 0, 64, 2);
break;
case 6600 ... 6890:
tft.drawString("Left ", 0, 64, 2);
break;
case 5800 ... 6200:
tft.drawString("Key C ", 0, 64, 2);
break;
case 2000 ... 2400:
tft.drawString("Key 1 ", 0, 64, 2);
break;
default:
tft.drawString(" ", 0, 64, 2);
break;
}
}
3.2 摇杆部分
摇杆部分使用了普耀FJ08K-S滑动摇杆和LMV324IPWR四路低电压轨至轨输出运算放大器,将FJ08K-S滑动摇杆的电压变化转变为频率和占空比的变化,此部分测试代码如下:
#include <Arduino.h>
#include "TFT_espi.h"
#define jJoystickPin 2
TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
int ontime,offtime,duty;
float freq, period;
void setup() {
// put your setup code here, to run once
pinMode(jJoystickPin, INPUT);
tft.init();
tft.setTextSize(1);
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
}
void loop() {
// put your main code here, to run repeatedly:
ontime = pulseIn(jJoystickPin, HIGH);
offtime = pulseIn(jJoystickPin, LOW);
period = ontime+offtime;
freq = 1000000.0/period;
duty = (ontime/period)*100;
tft.drawString("HZ:", 0, 0, 2);
tft.drawFloat(freq, 2, 32, 0);
tft.drawString("US:", 0, 16, 2);
tft.drawFloat(duty, 2, 32, 16);
}
3.3鼠标键盘HID模拟
Arduino最新的框架中已经包含了USB操作相关的库,因此无需添加额外的库,主要是根据使用相关的API完成指定的操作。
#include "USBHIDKeyboard.h"
#include "USBHIDMouse.h"
USBHIDKeyboard Keyboard; // 创建键盘设备
USBHIDMouse Mouse; // 创建鼠标设备
void setup() {
USB.usbClass(0);
USB.usbSubClass(0);
USB.usbProtocol(0);
Keyboard.begin();
Mouse.begin();
USB.begin();
}
void Key1Callback(void)
{
Keyboard.press('e');Keyboard.release('e');
Keyboard.press('e');Keyboard.release('e');
Keyboard.press('t');Keyboard.release('t');
Keyboard.press('r');Keyboard.release('r');
Keyboard.press('e');Keyboard.release('e');
Keyboard.press('e');Keyboard.release('e');
Keyboard.press('.');Keyboard.release('.');
Keyboard.press('c');Keyboard.release('c');
Keyboard.press('n');Keyboard.release('n');
}
void KeyCCallback(void)
{
Mouse.press(MOUSE_LEFT);Mouse.release(MOUSE_LEFT);
}
void MouseCallback(signed char x,signed char y)
{
Mouse.move(x, y, 0, 0);
}
四、难题与展望
4.1 遇到的难题
本次项目使用的拓展版为了节省IO将摇杆部分的X轴和Y轴使用芯片映射到IO频率和占空比的变化,因此需要选用合适的函数来对此部分进行解析,否则会无法控制鼠标的运动。
同时同样出于节省IO的考虑,所有的按键需要进行ADC范围判定,此部分需要合理划定ADC范围才能解决。
4.2 未来的计划建议
将TFT屏幕部分进行优化,实现鼠标运动方向的指示;
使用ESP32的蓝牙按键库,实现无线控制鼠标和键盘。