2023年寒假在家练-基于ESP32S2实现的日期选择菜单
此次基于寒假在家练esp32平台实现项目1 - 通过IO扩展板上的按键和旋转编码器控制并实现菜单功能
标签
ESP32
2023寒假在家练
2023年寒假在家练
功能菜单
xinshuwei
更新2023-03-27
226

内容介绍

项目描述(项目介绍、设计思路、框图和软件流程图通过ESP32核心板的ADC监测IO板模拟输出管脚的变化,判断哪一个按键或编码器的旋转发生了变化,进而控制1.44寸LCD屏幕的菜单显示。主要实现led 控制开关及日期(年月日交互选择)控制实现,主要框图如下

FkX903EOexLLru8f5FcXwKNQjJOa

进行如下工作:

1.按键和EC11旋转编码器的底层驱动

2.oled 显示屏驱动

3.旋转编码器单次左旋 右旋的识别 按键的识别等

4.菜单功能实现

5.菜单与按键 旋转编码器输入进行绑定 控制

硬件介绍

整体模块及扩展板连接图(薅的群里,蛮方便的)

Fj0nq1U81r0-kSK-Z4KrHCuV9MUJ

IO扩展板上的1个按键和旋转编码器的3个输入端口是通过R-2R电阻网络的方式连接在一起,生成一个模拟电压量。按下任何一个按键都会改变这个模拟电压量的值, K1其实也可以进行焊接,但是esp32输入范围有限,可以使用其他平台进行识别

Fi_S4WvmMeAZXbNmd2FpnOyYQ3-w

OLED 使用的是ST7789 驱动的128*128分辨率的1.44寸彩色屏幕,通过SPI总线进行访问

Fil05YjBhO7YwKu8JvOWcEyB5Lta

主控模块介绍

ESP32-S2 WiFi模块是物联网、可穿戴电子设备和智能家居等应用场景的理想选择,另搭配输入控制、输出显示以及传感器感知和控制的套件,使其功能更加完善。

该模块板载了:

  • ESP32-S2-MINI-1模组
  • 这是一款2.4 GHz Wi­Fi 模组
  • 内置 ESP32­S2 系列芯片,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供电。

注意实际扩展板未将MOS拉低,小心发热电阻烫到。。。切记切记

实现的功能及图片展示

Fi-FYYGoFORVqPvn3X4U9WXIxiDV

主要代码片段及说明

1.adc 采集主要功能实现,这块花费了好长时间,后续还是使用ADALM2000进行波形的录制,分析采集数据波形如下:

FruyPYEYikfXb2zDomXnqUq7yhxc

 

Fs2etmkGQNNF6d0QOyr_TZvz6rur

发现不管左旋转还是右旋转 都经过两个状态跳变,实际状态机判断时,只需要进行相应ADC 电平状态机判断即可,满足相应的条件,即触发相应的按钮实现,采集调试的代码如下:

static void key_process(void)
{
    static int analogVol;
    analogVol = analogReadMilliVolts(KEY_IN_NUM);
    //Serial0.println(analogVol);
    switch (analogVol)
  {
  case 1180 ... 1800:
    if(Key_mode==EC11_BTN_IN)
    {
        Key_mode = EC11_BTN;
    }
    else if( Key_mode==K2_PRESS_IN)
    {
        Key_mode = K2_PRESS ;
    }
    else
    {
        Key_mode = NO_KEY;
    }
    break;
  case 1140 ... 1160:
    Key_mode = EC11_ROLL_RIGHT;
    break;
  case 1090 ... 1110:
    Key_mode =EC11_ROLL_LEFT;
    break;
  case 1040 ... 1060:
    if(Key_mode==EC11_ROLL_LEFT)
    {
        Key_mode = EC11_LEFT;

    }
    else if(Key_mode ==EC11_ROLL_RIGHT)
    {
        Key_mode = EC11_RIGHT;
    }
    break;
  case 900 ... 1010:
    Key_mode = EC11_BTN_IN;
    break;
  case 200 ... 600:
    Key_mode =K2_PRESS_IN;
    break;
  default:
    Key_mode = NO_KEY;
    break;
  }

OLED显示屏

oled 使用spi 接口,通过TFT_eSP 库 进行基础显示控制,

TFT_eSPI gfx;
 gfx.init();
  gfx.setRotation(0);
  gfx.fillScreen(TFT_GREY);
  gfx.setTextColor(TFT_GREEN, TFT_GREY);  // Adding a black background colour erases previous text automatically
  Serial0.println("gfx init finish");
  pinMode(RED_LED_PIN, OUTPUT);

菜单显示功能是基于arduinomenu 进行实现,主要移植过程

1.指定uart 打印口

serialIn serial(Serial0);
idx_t serialTops[MAX_DEPTH]={0};
serialOut outSerial(Serial0,serialTops);

2.指定不同部位的颜色

const colorDef<uint16_t> display_colors[6] MEMMODE = {
  //{{disabled normal,disabled selected},{enabled normal,enabled selected, enabled editing}}
  {{(uint16_t)Black, (uint16_t)Black}, {(uint16_t)Black, (uint16_t)Red,   (uint16_t)Red}}, //bgColor
  {{(uint16_t)White, (uint16_t)White},  {(uint16_t)White, (uint16_t)White, (uint16_t)White}},//fgColor
  {{(uint16_t)Red, (uint16_t)Red}, {(uint16_t)Yellow, (uint16_t)Yellow, (uint16_t)Yellow}}, //valColor
  {{(uint16_t)White, (uint16_t)White}, {(uint16_t)White, (uint16_t)White, (uint16_t)White}}, //unitColor
  {{(uint16_t)White, (uint16_t)Gray},  {(uint16_t)Black, (uint16_t)Red,  (uint16_t)White}}, //cursorColor
  {{(uint16_t)White, (uint16_t)Yellow}, {(uint16_t)Black,  (uint16_t)Red,   (uint16_t)Red}}, //titleColor
};

颜色的定义如下:颜色定义可以自己修改,注意要进行GB565格式转换

#define Black RGB565(0,0,0)
#define Red	RGB565(255,0,0)
#define Green RGB565(0,255,0)
#define Blue RGB565(0,0,255)
#define Gray RGB565(128,128,128)
#define LighterRed RGB565(255,150,150)
#define LighterGreen RGB565(150,255,150)
#define LighterBlue RGB565(150,150,255)
#define DarkerRed RGB565(150,0,0)
#define DarkerGreen RGB565(0,150,0)
#define DarkerBlue RGB565(0,0,150)
#define Cyan RGB565(0,255,255)
#define Magenta RGB565(255,0,255)
#define Yellow RGB565(255,255,0)
#define White RGB565(255,255,255)

3.屏幕相关的设定 指定输出介质是屏幕,指定屏幕的宽高 字体大小等

onst panel panels[] MEMMODE = {{0, 0, GFX_WIDTH / fontW, GFX_HEIGHT / fontH}};
navNode* nodes[sizeof(panels) / sizeof(panel)]; //navNodes to store navigation status
panelsList pList(panels, nodes, sizeof(panels) / sizeof(panel)); //a list of panels and nodes
idx_t eSpiTops[MAX_DEPTH]={0};
TFT_eSPIOut eSpiOut(gfx,display_colors,eSpiTops,pList,fontW,fontH+1);
menuOut* constMEM outputs[] MEMMODE={&outSerial,&eSpiOut};//list of output devices
outputsList out(outputs,sizeof(outputs)/sizeof(menuOut*));//outputs list controller
//NAVROOT(nav,mainMenu,MAX_DEPTH,serial,out);
NAVROOT(nav,mainMenu,MAX_DEPTH,serial,out);

3.按键回调控制实现  这里通过触发相应的按键实现菜单的上 下 进入 退出的功能实现

void Btn_loop(void)
{
    if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
        portENTER_CRITICAL(&timerMux);
        int my_key =Key_mode;
        portEXIT_CRITICAL(&timerMux);
        switch (my_key)
        {
        case K2_PRESS:
             nav.doNav(escCmd);
             break;
        case EC11_BTN:
             nav.doNav(enterCmd);
             break;
        case EC11_LEFT:
             nav.doNav(upCmd);
             break;
        case EC11_RIGHT:
             nav.doNav(downCmd);
             break;
        default:
            break;
        }

    }

}

4.界面显示菜单内容控制

SUBMENU 是子界面

OP 是本菜单不进行跳转

FILED 是当前界面进行数值调整

const char* constMEM hexDigit MEMMODE="0123456789ABCDEF";
const char* constMEM hexNr[] MEMMODE={"0","x",hexDigit,hexDigit};
char buf1[]="0x11";
MENU(mainMenu,"2023 Happy New Year",doNothing,noEvent,wrapStyle
  //,OP("Op1",doNothing,noEvent)
  //,OP("Op2",doNothing,noEvent)
  ,SUBMENU(subMenu)
  ,SUBMENU(setLed)
  ,OP("LED On",myLedOn,enterEvent)
  ,OP("LED Off",myLedOff,enterEvent)
  ,SUBMENU(YearMenu)
  ,SUBMENU(MonthMenu)
  ,FIELD(ledBacklight,"Day: ","",1,30,10,1,doNothing,noEvent,wrapStyle) // Menu option to set the intensity of the backlight of the screen.
  //,EDIT("Hex",buf1,hexNr,doNothing,noEvent,noStyle)
  ,EXIT("<Back")
);

遇到的主要难题及解决方法

adc采集花费了好长时间,通过电压采集发现和实际示波器采集的有差别,后来通过datasheet发现 esp32s2的adc 采集量程不能达到满量程,电压范围后续通过实测进行调整

左旋 右旋转 对于连续旋转时,需要检测两个电平才能完美识别一次旋转 还是多次旋转,原来只使用一个边沿容易进行误触发,实际体验不好,后来优化状态机解决了此问题

未来的计划或建议

后续希望多举办这样的活动,不仅学习到了知识,同时又认识到了不少朋友,谢谢能提供这样的机会。

 

代码开源下载地址

团队介绍

苏州工程师一枚

评论

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