基于ESP32S2的USB键盘鼠标设备
实现一个USB鼠标&键盘复合设备,摇动游戏手柄实现鼠标的移动,一个按键实现左键点击,另一个按键按下实现键盘敲入一串字符"eetree.cn"
标签
嵌入式系统
显示
USB
退役熬夜选手
更新2023-03-28
502

一、项目目标

实现一个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 页面了,然后选择右侧的新建工程的按钮。

image-20230116104506754

点击项目操作按钮的 + New Project,在弹窗中分别填入或选择 Name、Board、Framework 点击 Finish:

image-20230116104654058

稍作等待,PIO 会自动根据选择的 Board 和 Framework 配置工程并且下载需要用到的编译工具,需要的编译依赖什么的 PIO 通通帮我们搞定,一段时间过后项目工程就新建完成了,打开 src 文件夹下的 main.cpp 如下:

 

三、模块调试

3.1 EC11部分

编码器具有一个磁盘,该磁盘具有均匀分布的接触区,这些接触区连接到公共引脚C和两个其他单独的接触引脚A和B,如下所示。

image-20230119194121955

当磁盘逐步开始旋转时,引脚A和B将开始与公共引脚接触,因此将产生两个方波输出信号。 如果我们仅对信号脉冲进行计数,则可以使用两个输出中的任何一个来确定旋转位置。但是,如果我们也要确定旋转方向,则需要同时考虑两个信号,两个输出信号彼此之间相差90度。如果编码器顺时针旋转,则输出A将在输出B之前。 EC11-3

因此,如果我们每次计算信号从高到低或从低到高变化的步数,我们就会注意到那时两个输出信号的值相反。如果编码器逆时针旋转,则输出信号具有相等的值。因此,考虑到这一点,我们可以轻松地对控制器进行编程以读取编码器位置和旋转方向。

但是本次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的蓝牙按键库,实现无线控制鼠标和键盘。


 
附件下载
ESP32_S2_HID.7z
团队介绍
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号