[Arduino资料] ESP32驱动ST7789触摸屏开发指南:LVGL主题设置与示波器面板

[复制链接]
 楼主| lingzhiLab 发表于 2025-4-28 11:47 | 显示全部楼层 |阅读模式
本帖最后由 lingzhiLab 于 2025-4-28 11:57 编辑

一、项目概述本文介绍如何使用ESP32微控制器驱动ST7789 TFT液晶屏和XPT2046触摸芯片,通过LVGL图形库实现主题切换功能,并开发一个实用的触摸屏示波器应用。项目包含两大核心功能:
  • LVGL多主题切换:支持8种不同风格的UI主题
  • 示波器功能
    模拟/数字信号采集、触摸控制面板、光标测量系统、自动频率检测

二、硬件准备
组件型号说明
主控零知ESP32双核240MHz处理器
屏幕ST7789 2.4寸240×320分辨率
触摸芯片XPT2046电阻式触摸控制器
接线SPI使用硬件SPI接口

接线图
8635680ef6276b8ab.png

三、环境搭建

1. 安装库
lv_arduino v3.0.1
TFT_eSPI
XPT2046_Touchscreen

2. TFT_eSPI配置(User_Setup.h):
  1. ​#define ST7789_DRIVER      // Full configuration option, define additional parameters below for this display

  2. #define TFT_WIDTH  240 // ST7789 240 x 240
  3. #define TFT_HEIGHT 320 // ST7789 240 x 320

  4. #define TFT_MISO 19
  5. #define TFT_MOSI 23   
  6. #define TFT_SCLK 18
  7. #define TFT_CS   15  Chip select control pin
  8. #define TFT_DC   2   Data Command control pin
  9. #define TFT_RST  4   Reset pin (could connect to RST pin)

四、核心代码解析4.1 LVGL主题设置
  1. // 主题初始化
  2. void setup() {
  3.     lv_test_theme(); // 默认主题
  4.     // 可选主题:
  5.     // lv_test_theme_1(lv_theme_night_init(210, NULL));
  6.     // lv_test_theme_1(lv_theme_material_init(210, NULL));
  7. }

  8. // 显示驱动回调
  9. void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
  10.     tft.setAddrWindow(area->x1, area->y1, area->x2, area->y2);
  11.     for(int y=area->y1; y<=area->y2; y++){
  12.         for(int x=area->x1; x<=area->x2; x++){
  13.             tft.writeColor(color_p->full, 1);
  14.             color_p++;
  15.         }
  16.     }
  17.     lv_disp_flush_ready(disp);
  18. }


4.2 触摸驱动(带消抖)
  1. bool my_touchpad_read(lv_indev_drv_t *indev, lv_indev_data_t *data) {
  2.     static lv_coord_t last_x = 0, last_y = 0;
  3.     bool is_touched = ts.touched();
  4.    
  5.     if(is_touched){
  6.         TS_Point p = ts.getPoint();
  7.         // 坐标转换与校准
  8.         last_x = map(p.x, cal_x_min, cal_x_max, 0, 320);
  9.         last_y = map(p.y, cal_y_max, cal_y_min, 0, 240);
  10.         
  11.         // 滑动检测
  12.         if(abs(last_x - prev_x) >5 || abs(last_y - prev_y) >5){
  13.             is_sliding = true;
  14.         }
  15.         
  16.         // 消抖处理
  17.         if(!is_sliding && (millis()-last_touch_time)>CLICK_DEBOUNCE_MS){
  18.             last_touch_time = millis();
  19.         }
  20.     }
  21.     data->point.x = last_x;
  22.     data->point.y = last_y;
  23.     return false;
  24. }


4.3 简易示波器核心逻辑

波形采样:
  1. void takeSample() {
  2.     if(!digitalMode){ // 模拟模式
  3.         uint16_t raw = analogRead(ADC_PIN);
  4.         samplesBuffer[sampleIndex] = raw * amplitudeScale;
  5.     }else{ // 数字模式
  6.         bool state = digitalRead(DIGITAL_PIN);
  7.         samplesBuffer[sampleIndex] = state ? 4095 : 0;
  8.     }
  9.     sampleIndex = (sampleIndex+1) % MAX_SAMPLES;
  10. }

波形绘制:
  1. void updateWaveform() {
  2.     waveSprite.fillSprite(BG_COLOR);
  3.     // 绘制网格
  4.     for(int x=0; x<GRAPH_WIDTH; x+=32){
  5.         waveSprite.drawFastVLine(x,0,GRAPH_HEIGHT,GRID_COLOR);
  6.     }
  7.     // 绘制波形
  8.     for(int i=0; i<visibleSamples; i++){
  9.         uint16_t y = map(samplesBuffer[i],0,4095,GRAPH_HEIGHT,0);
  10.         waveSprite.drawPixel(i*2, y, WAVE_COLOR);
  11.     }
  12.     // 绘制光标
  13.     if(cursorMode){
  14.         waveSprite.drawFastVLine(cursor1Pos,0,GRAPH_HEIGHT,CURSOR1_COLOR);
  15.         waveSprite.drawFastVLine(cursor2Pos,0,GRAPH_HEIGHT,CURSOR2_COLOR);
  16.     }
  17.     waveSprite.pushSprite(0, GRAPH_TOP);
  18. }

五、触摸控制面板实现
  1. void create_ui(){
  2.     // 创建选项卡式控制面板
  3.     lv_obj_t *tabview = lv_tabview_create(rightPanel, NULL);
  4.     lv_obj_t *timeTab = lv_tabview_add_tab(tabview, "时基");
  5.    
  6.     // 时基选择滚轮
  7.     lv_obj_t *timebaseRoller = lv_roller_create(timeTab);
  8.     lv_roller_set_options(timebaseRoller, "0.5ms\n1.0ms\n2.0ms", LV_ROLLER_MODE_NORMAL);
  9.    
  10.     // 幅度控制滑块
  11.     lv_obj_t *ampSlider = lv_slider_create(ampTab);
  12.     lv_slider_set_range(ampSlider, 0, 400);
  13.    
  14.     // 模式切换开关
  15.     modeSwitch = lv_switch_create(controlPanel);
  16.     lv_obj_set_event_cb(modeSwitch, mode_switch_event_cb);
  17. }

六、性能优化技巧
  • 双缓冲机制:使用TFT_eSPI的Sprite功能减少闪烁
  • 异步采样:在loop()中分离采样和显示逻辑
  • 动态刷新:根据时基自动调整刷新率
  • 内存管理
  1. static lv_color_t buf[LV_HOR_RES_MAX * 10]; // LVGL缓冲区
  2. TFT_eSprite waveSprite = TFT_eSprite(&tft); // 波形缓冲


七、实测效果7.1 LVGL不同主题切换
b2a38417c8084826b46ed41706ddf6a0.jpeg
演示视频:


7.2示波器触控界面效果
3ef7a3e0-5bfb-402f-8dd1-f379638427ca.jpg
演示视频:


参数性能指标
最大采样率20KSPS
电压范围0-3.3V
时基范围0.5-25ms/div
触控响应<50ms


八、常见问题解决触摸校准异常
修改cal_x_min/max和cal_y_min/max值
使用校准例程获取实际参数

LVGL内存不足
  1. // 修改lv_conf.h配置
  2. #define LV_MEM_SIZE (48*1024)
  3. #define LV_DISP_DEF_REFR_PERIOD 30

完整代码获取:
Github仓库
https://github.com/Leeri1y/esp32-st7789

或者

百度网盘
https://pan.baidu.com/s/19TVS2PBJpYqExxsannnH3w?pwd=epyd

互动交流: 欢迎在评论区留言讨论,遇到问题可提交Issues

附录:关键函数速查表函数功能调用示例
lv_btn_create()创建按钮lv_obj_t * btn = lv_btn_create(parent, NULL);
lv_sw_get_state()获取开关状态bool state = lv_sw_get_state(sw);
lv_roller_set_options()设置滚轮选项lv_roller_set_options(roller, "1\n2\n3", true);
waveSprite.pushSprite()刷新显示waveSprite.pushSprite(0, 0);
ts.touched()检测触摸if(ts.touched()) { ... }
动手实践建议
先运行基础显示示例验证硬件连接
逐步添加功能模块(先显示后触摸)
使用串口监视器调试输出
保存不同版本的代码备份



56093680ef5141cd87.png
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

33

帖子

0

粉丝

22

主题

33

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部