基于ESP32S实现游戏手柄控制LCD上的信息
本项目基于ESP32 WiFI模块和输入、输出扩展板,运用扩展板上的X、Y二轴电位计制作的游戏手柄,通过单片机的IO端口测量此手柄产生的PWM信号的频率和占空比的变化,判断出手柄的方向变化,再通过lcd屏以图像化的方式呈现手柄的方向变化。
标签
嵌入式系统
显示
ESP32
2023寒假在家练
ypx
更新2023-03-27
西安电子科技大学
645

任务要求

   1.本任务需要用ESP32板测量IO扩展板上的PWM信号。

   2.在LCD上以图形化的方式显示游戏摇杆的变化。

   3.通过游戏摇杆的拨动,能够触及LCD的全屏幕。

一、环境配置

   1.Arduino IDE 2.0:

      Arduino IDE是一个用于编写和上传代码到Arduino开发板的软件,它可以很方便地下载各种库,而且简单易用、按键极少、逻辑简单、易于配置,对新手非常友好,而且在2.0版本中加入了代码补全,界面也很简洁漂亮。

   2.硬禾学堂ESP32 WiFI模块:

      硬禾学堂为“2023寒假在家练”制作了一个模块,该模块板载了:

  • ESP-S2-MINI_WIFI模组
  • 内置 ESP32­S2 系列芯片,Xtensa® 单核 32 位 LX7 微处理器
  • 内置芯片叠封 4 MB flash,可叠封 2 MB PSRAM
  • 37 个 GPIO,具有丰富的外设
  • 板载 PCB 天线Flqmtbn898LdAecTWhqgUdR6ObnQ

   3.输入、输出扩展版:

      包含:

  • 按键、旋转编码器输入 - 以模拟信号的方式
  • 双电位计控制输入 - 以数字信号的方式
  • RGB三色LED显示
  • 1.44寸128*128 LCD,SPI总线访问
  • MMA7660三轴姿态传感器
  • 电阻加热
  • 温度传感器
  • 与ESP32-S2核心模块的接口

二、程序实现

程序均使用c语言编写

1.模块的实现:

(1)显示屏的使用:

首先需要下载TFT_eSPI库,可以从github上下载,也可以在Arduino IDE上直接下载,在IDE的库管理里直接搜索“TFT_eSPI”,点击第一个直接安装即可。

Fg_StrFPQv1cSltXxwlA0hTCfSWl

使用方式如下:

      找到文件夹里的“User_Setup.h”文件,根据自己屏幕的驱动芯片、分辨率和引脚进行初始化配置。

// Only define one driver, the other ones must be commented out
//#define ILI9341_DRIVER       // Generic driver for common displays
//#define ILI9341_2_DRIVER     // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
#define ST7735_DRIVER      //此拓展板的屏幕是由ST7735驱动,所以取消此行注释
//#define ILI9163_DRIVER     // Define additional parameters below for this display
//#define S6D02A1_DRIVER
//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
//#define HX8357D_DRIVER
//#define ILI9481_DRIVER
//#define ILI9486_DRIVER
//#define ILI9488_DRIVER     // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
//#define ST7789_DRIVER      // Full configuration option, define additional parameters below for this display
//#define ST7789_2_DRIVER    // Minimal configuration option, define additional parameters below for this display
//#define R61581_DRIVER
//#define RM68140_DRIVER
//#define ST7796_DRIVER
//#define SSD1351_DRIVER
//#define SSD1963_480_DRIVER
//#define SSD1963_800_DRIVER
//#define SSD1963_800ALT_DRIVER
//#define ILI9225_DRIVER
//#define GC9A01_DRIVER

      接下来选择屏幕分辨率

// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
// #define TFT_WIDTH  80
 #define TFT_WIDTH  128
// #define TFT_WIDTH  172 // ST7789 172 x 320
// #define TFT_WIDTH  240 // ST7789 240 x 240 and 240 x 320
// #define TFT_HEIGHT 160
 #define TFT_HEIGHT 128
// #define TFT_HEIGHT 240 // ST7789 240 x 240
// #define TFT_HEIGHT 320 // ST7789 240 x 320
// #define TFT_HEIGHT 240 // GC9A01 240 x 240

      然后配置引脚

#define TFT_MOSI 21
#define TFT_SCLK 41
#define TFT_CS   13  // Chip select control pin
#define TFT_DC   17  // Data Command control pin
#define TFT_RST  18  // Reset pin (could connect to RST pin)

到现在屏幕配置算是已经完成了可以简单测试一下

#include<SPI.h>
#include<TFT_eSPI.h>

TFT_eSPI tft = TFT_eSPI();
void setup() {
    tft.init();
    tft.fillScreen(TFT_BLACK); //将屏幕变成黑色
}
void loop() {
}

  (2)通过IO端口测量此手柄产生的PWM信号的频率和占空比


以下为手柄部分的电路图:

FiaXbHv1YzlW9NZgt8r4k4GF3miN

可以看出手柄实际上是两个滑动变阻器进行分压,从电路整体来看是个振荡器+比较器输出pwm波形,所以我们可以从pwm的频率和占空比得知滑动变阻器的变化,进而反推出遥感的位置变化

测量思路:

与stm32的硬件支持和丰富的库函数相比,esp32在输入捕获上稍微麻烦一些,这里我采用定时器与外部中断的方式测量

  • 使用外部中断对上升沿和下降沿都进行中断
  • 每次发生中断都记录下当前的时间
  • 中断服务程序中记录下当前电平
  • 脉宽即为触发下降沿的时间减去上次触发上升沿的时间
  • 周期即为触发上升沿的时间减去上一次触发上升沿的时间
  • 占空比=脉宽/周期
  • 频率=1/周期

(3)将手柄方向变化以图形化的方式呈现

这一步由于时间紧迫我做得十分的粗糙,建议使用移植lvgl,并将遥感作为输入设备接入

我使用的是TFT_eSPI里移动光标在屏幕上画小圆点的方式呈现,具体展示见开头视频

2.整体实现

设计思路和程序流程图:

Fj5G4ip_G8Hju91FZ4vKuRHcpZQd
整体代码:

#include <Arduino.h>
#include <SPI.h>
#include <TFT_eSPI.h>

 
TFT_eSPI tft = TFT_eSPI();

volatile unsigned long raiseTime = 0; //前一次上升沿时间
volatile unsigned long fallTime = 0;  //前一次下降沿时间
volatile double duty = 0;  //占空比
volatile double fre = 0;   //频率

int pwmPin = 2;   //信号输入的管脚

unsigned int x = 50, y = 50;    //设置光标的初始坐标

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;  //自旋锁

void changeISR()
{
  auto now = micros();
  if(digitalRead(pwmPin))  //现在是高
  {
    portENTER_CRITICAL_ISR(&mux);   //进入临界区
    auto total = now - raiseTime;
    fre = 1e6/(double)total;
    auto h = fallTime - raiseTime;
    duty = h/(double)total;
    portEXIT_CRITICAL_ISR(&mux);   //离开临界区
    raiseTime = now;
  }
  else
  {
    fallTime = now;
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.print("begin");
  pinMode(pwmPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(pwmPin), changeISR, CHANGE);
  tft.init();         //初始化
  tft.setRotation(0); //屏幕旋转方向(横向)
  tft.fillScreen(TFT_BLACK);
 
}

void loop() {
  delay(50);
  tft.fillScreen(TFT_BLACK);
  portENTER_CRITICAL(&mux);
  double f = fre;
  double d = duty;
  tft.setCursor(5,5);
  tft.println(f);
  tft.setCursor(5,8);
  tft.println(d);
  if (f < 299) {
    x--;
  }
  else if (f > 301) {
    x++;
  }
  if (d < 0.57) {
    y--
  }
  else if (d > 0.59) {
    y++;
  }
  tft.setCursor(x, y);
  tft.print(0);
  portEXIT_CRITICAL(&mux);
  
}

三、后记


除了选择Arduino IDE进行开发,还可以使用VSCODE下载esp-idf插件开发,也是十分优雅,但是我在一开始尝试的时候遇到了一些奇怪的bug就换成Arduino IDE了,确实要省心很多。

由于时间匆忙,本来想移植lvgl来实现此项目的,我已经完成了ui设计并成功显示在lcd屏幕上了,但最后在接入物理摇杆作为鼠标的时候遇到了一些困难,为了在规定时间内完成就换成这种十分不优雅的方式呈现。目前我还在继续研究,今后我还会继续完善这个项目的。

 

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