一、 任务简介
通过IO扩展板上的按键和旋转编码器控制并实现菜单功能。
本任务需要通过ESP32核心板的ADC监测IO板模拟输出管脚的变化,判断哪一个按键或编码器的旋转发生了变化,进而控制1.44寸LCD屏幕的菜单显示,要求实现主菜单和至少二级菜单。
二、 硬件简介
2.1 ESP32-S2 WiFi模块
ESP32-S2 WiFi模块是物联网、可穿戴电子设备和智能家居等应用场景的理想选择,另搭配输入控制、输出显示以及传感器感知和控制的套件,使其功能更加完善。
该模块板载了:
ESP32-S2-MINI-1模组
这是一款2.4 GHz WiFi 模组
内置 ESP32S2 系列芯片,Xtensa® 单核 32 位 LX7 微处理器
内置芯片叠封 4 MB flash,可叠封 2 MB PSRAM
37 个 GPIO,具有丰富的外设
板载 PCB 天线
配套的ESP32 S2 开发板除了ESP32wifi模组之外还集成了USB TYPE -C接口,两个按键,一个电源指示灯,一个用户LED灯,2排10pin的排针,将重要IO引出。使用USB供电或通过排针3.3V供电。
ESP32-S2 是一款高度集成、高性价比、低功耗、主打安全的单核 Wi-Fi SoC,具备强大的功能和丰富的 IO 接口
2.2 IO拓展板
IO扩展板上的1个按键和旋转编码器的3个输入端口是通过R-2R电阻网络的方式连接在一起,生成一个模拟电压量。按下任何一个按键都会改变这个模拟电压量的值。
IO扩展板上的LCD屏幕为128*128分辨率的1.44寸彩色屏幕,通过SPI总线进行访问。
三、 程序设计
3.1 设计思路
利用Arduino中的TFT_eSPI库来操作屏幕;轮询获取旋转编码器的值来判断动作;根据旋转编码器的动作更新屏幕。
3.2 流程图
四、 代码介绍
#include <SPI.h>
#include <TFT_eSPI.h>
#include<pgmspace.h>
TFT_eSPI tft = TFT_eSPI();
unsigned char funindex = 0; //中间值
unsigned char cursor = 0; //选项序号
#define ENDCOUNT 2 //返回序号最小值
void (*fun)();
void menu0();
void menu1();
void menu2();
上面是项目的一些初始化设置,包含所需库、实例化对象、常量函数全局变量的声明。关于引脚等信息的设置在TFT_eSPI的User_Setup.h中。
//存储每个选项信息的结构
//up:同一界面的上一个选项的序号;down:同一界面的上一个选项的序号;button:该选项运行后的选项序号;(*action):选项对应执行的操作。
typedef struct
{
unsigned char up;
unsigned char down;
unsigned char button;
void (*action)();
//cursor_info *now_menu_cursor_info; //将来的拓展模块
}cursor_info;
//选项信息列表
cursor_info table[4] =
{
{0,1,2,(*menu1)},
{0,1,3,(*menu2)},
{2,2,0,(*menu0)},
{3,3,1,(*menu0)},
};
该部分定义了一个储存选项相关信息的结构,其中up:同一界面的上一个选项的序号;down:同一界面的上一个选项的序号;button:该选项运行后的选项序号;(*action):选项对应执行的操作。并创建了该项目的菜单选项信息。
void setscreen(String text, int16_t x, int16_t y, uint16_t color) //屏幕变化设置
{
tft.setTextSize(20);
tft.setTextColor(color);
tft.loadFont(arial_12);
tft.setCursor(x,y);
tft.println(text);
tft.unloadFont();
}
该部分是利用TFT模块实现屏幕信息的更新功能。
void menu0()
{
tft.fillScreen(TFT_WHITE);
if(cursor==0)
setscreen("hello", 10, 10, TFT_BLUE); //选中为蓝色
else
setscreen("hello", 10, 10, TFT_BLACK);
if(cursor==1)
setscreen("world", 10, 30, TFT_BLUE);
else
setscreen("world", 10, 30, TFT_BLACK);
}
void menu1()
{
tft.fillScreen(TFT_WHITE);
setscreen("This is menu1", 10, 10, TFT_BLACK);
setscreen("bye", 10, 100, TFT_BLUE);
}
void menu2()
{
tft.fillScreen(TFT_WHITE);
setscreen("This is menu2", 10, 10, TFT_BLACK);
setscreen("goodbye", 10, 100, TFT_BLUE);
}
这是每个菜单界面的更新设置,包含了对应菜单界面下提示信息、选项、光标选中不同选项时的更新设置。
void uphanded() //向上选择
{
if(cursor<ENDCOUNT)
{
cursor = table[cursor].up;
(*menu0)();
}
}
void downhanded() //向下选择
{
if(cursor<ENDCOUNT)
{
cursor = table[cursor].down;
(*menu0)();
}
}
void button() //按钮操作
{
funindex = cursor;
cursor = table[funindex].button;
fun = table[funindex].action;
(*fun)();
delay(300);
}
}
void loop() {
int Value = analogRead(1);
if((Value > 6690) && (Value < 6740))
uphanded();
if((Value > 7020) && (Value < 7070))
downhanded();
if((Value > 6040) && (Value < 6090))
button();
}
该部分包含了轮询判断旋转编码器的动作与动作对应的操作。
void setup() {
tft.init();
tft.fillScreen(TFT_WHITE);
menu0();
}
初始界面设置。
五、 实现功能与图片
因为图片展示不出旋转操作对应的变化,所以请直接参考视频的实物展示部分。
六、 遇到主要难题与解决方法
6.1 环境配置
最初我想以VScode+espressif32作为项目的开发环境,后来又使用VScode+platformio+Arduino+espressif32作为项目的开发环境,但都遇到了各种各样的问题,包括了库的引用、编译、烧录等方面。最后采用了Arduino+espressif32的方式,这里还会遇到一个问题就是下载espressif32开发板模块时,由于下载内容多且大,在下载时十分容易因为GitHub响应超时而失败,即使使用VPN也容易发生上述问题。这里提供一个解决方案就是将对应的josn文件中的GitHub网址全部替换为国内镜像站的网址,这样就可以快速的成功下载了。提供两个镜像网址:https://hub.yzuu.cf/ https://hub.fgit.ml/ ,使用前请先确保镜像站可用,避免因网站被攻击而导致的损失。
6.2 烧录
在烧录最后会出现芯片不能正常复位而导致失败。疑似的方案:在烧录达到100%的瞬间按下RST键,如果此时电脑的设备管理器自动刷新后仍显示对应串口而不是直接消失,那么问题就解决了,以后可以直接烧录。由于试了很多方法,所以上述方法是否能直接解决问题仍不确定。
七、 未来规划
将菜单界面优化,使其具备可拓展性。修改思路如下
在原有的选项信息结构上进行改造,使其变为界面选项信息,其中包含该界面下选项的上下选项角标信息、该选项对应的操作函数、该选项对应的下级界面角标和下级界面信息数组的指针。在对应对应界面的选项信息数组中进行增删,并增加对应的功能函数,即可实现菜单界面的拓展(按钮操作函数的修改和全局变量增删改自行思考)。