在ESP32开发板上使用LVGL框架开发LCD显示屏界面
显示框架:LVGL
TFT芯片:ST7789
电容触摸芯片:CST816S
1.TFT_eSPI drive LCD https://github.com/Bodmer/TFT_eSPI/discussions/2555
This wiki page was useful: Github
That said, there are some missing parts that due to the state of the library will show up as a non-functioning screen. For my use case (an ILI9488 device), I needed to provide additional values. I believe some of these are necessary for all projects.
Here is the bare minimum project using Visual Studio Code with PlatformIo and using the technique of platformio.ini file modification. No library file modification needed!
platformio.ini:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [env:nodemcu-32s] platform = espressif32 board = nodemcu-32s framework = arduino monitor_speed = 115200 lib_deps = bodmer/TFT_eSPI@^2.5.23 build_flags = -D USER_SETUP_LOADED -D ILI9488_DRIVER -D TFT_MISO=19 -D TFT_MOSI=23 -D TFT_SCLK=18 -D TFT_CS=15 -D TFT_DC=2 -D TFT_RST=4 -D LOAD_GLCD=1 -D SMOOTH_FONT -D SPI_FREQUENCY=27000000
main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <Arduino.h> #include <TFT_eSPI.h> TFT_eSPI tft = TFT_eSPI (); void setup () {Serial.begin (115200 ); tft.init (); tft.setRotation (1 ); tft.fillScreen (TFT_GREEN); } void loop () {}
Note that I had to include USER_SETUP_LOADED as well as SMOOTH_FONT.
There are some minor errors in the wiki article. It projects like we need to have an =1 but I found it works just like the include system and is not necessary.
2.My project, need offset. platformio.ini:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [env:wesp32] platform = espressif32 board = wesp32 framework = arduino monitor_speed = 115200 upload_speed = 230400 board_build.partitions = default_16MB.csv board_upload.flash_size = 16 MB lib_deps = bodmer/TFT_eSPI@^2.5 .30 lvgl/lvgl@^8.3 .7 build_flags = -D USER_SETUP_LOADED -D ST7789_DRIVER -D CGRAM_OFFSET -D TFT_MOSI=23 -D TFT_SCLK=18 -D TFT_DC=2 -D TFT_RST=4 -D LOAD_GLCD=1 -D SMOOTH_FONT -D SPI_FREQUENCY=55000000
3.lvgl main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 #include <lvgl.h> #include <TFT_eSPI.h> static const uint16_t screenWidth = 240 ;static const uint16_t screenHeight = 280 ;static lv_disp_draw_buf_t draw_buf;static lv_color_t buf[ screenWidth * 10 ];TFT_eSPI tft = TFT_eSPI (screenWidth, screenHeight); #if LV_USE_LOG != 0 void my_print (const char * buf) { Serial.printf (buf); Serial.flush (); } #endif void my_disp_flush ( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p ) { uint32_t w = ( area->x2 - area->x1 + 1 ); uint32_t h = ( area->y2 - area->y1 + 1 ); tft.startWrite (); tft.setAddrWindow ( area->x1, area->y1, w, h ); tft.pushColors ( ( uint16_t * )&color_p->full, w * h, true ); tft.endWrite (); lv_disp_flush_ready ( disp ); } void setup () { Serial.begin ( 115200 ); String LVGL_Arduino = "Hello Arduino! " ; LVGL_Arduino += String ('V' ) + lv_version_major () + "." + lv_version_minor () + "." + lv_version_patch (); Serial.println ( LVGL_Arduino ); Serial.println ( "I am LVGL_Arduino" ); lv_init (); #if LV_USE_LOG != 0 lv_log_register_print_cb ( my_print ); #endif tft.begin (); tft.setRotation ( 4 ); lv_disp_draw_buf_init ( &draw_buf, buf, NULL , screenWidth * 10 ); static lv_disp_drv_t disp_drv; lv_disp_drv_init ( &disp_drv ); disp_drv.hor_res = screenWidth; disp_drv.ver_res = screenHeight; disp_drv.flush_cb = my_disp_flush; disp_drv.draw_buf = &draw_buf; lv_disp_drv_register ( &disp_drv ); lv_obj_t *label_top = lv_label_create ( lv_scr_act () ); lv_label_set_text ( label_top, LVGL_Arduino.c_str () ); lv_obj_align ( label_top, LV_ALIGN_TOP_LEFT, 0 , 0 ); lv_obj_t *label = lv_label_create ( lv_scr_act () ); lv_label_set_text ( label, LVGL_Arduino.c_str () ); lv_obj_align ( label, LV_ALIGN_CENTER, 0 , 0 ); lv_obj_t *label_bottom = lv_label_create ( lv_scr_act () ); lv_label_set_text ( label_bottom, LVGL_Arduino.c_str () ); lv_obj_align ( label_bottom, LV_ALIGN_BOTTOM_RIGHT, 0 , 0 ); Serial.println ( "Setup done" ); } void loop () { lv_timer_handler (); delay ( 5 ); }
4.lvgl+touch platformio.ini:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [env:wesp32] platform = espressif32 board = wesp32 framework = arduino monitor_speed = 115200 upload_speed = 230400 board_build.partitions = default_16MB.csv board_upload.flash_size = 16 MB lib_deps = bodmer/TFT_eSPI@^2.5 .30 fbiego/CST816S@^1.1 .0 lvgl/lvgl@^8.3 .7 build_flags = -D USER_SETUP_LOADED -D ST7789_DRIVER -D CGRAM_OFFSET -D TFT_MOSI=23 -D TFT_SCLK=18 -D TFT_DC=2 -D TFT_RST=4 -D LOAD_GLCD=1 -D SMOOTH_FONT -D SPI_FREQUENCY=55000000
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 #include <lvgl.h> #include <TFT_eSPI.h> #include <CST816S.h> static const uint16_t screenWidth = 240 ;static const uint16_t screenHeight = 280 ;static lv_disp_draw_buf_t draw_buf;static lv_color_t buf[ screenWidth * 10 ];TFT_eSPI tft = TFT_eSPI (screenWidth, screenHeight); CST816S touch (15 , 4 , 5 , 34 ) ; #if LV_USE_LOG != 0 void my_print (const char * buf) { Serial.printf (buf); Serial.flush (); } #endif void my_disp_flush ( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p ) { uint32_t w = ( area->x2 - area->x1 + 1 ); uint32_t h = ( area->y2 - area->y1 + 1 ); tft.startWrite (); tft.setAddrWindow ( area->x1, area->y1, w, h ); tft.pushColors ( ( uint16_t * )&color_p->full, w * h, true ); tft.endWrite (); lv_disp_flush_ready ( disp ); } void my_touchpad_read (lv_indev_drv_t * indev_driver, lv_indev_data_t * data ) { bool touched = touch.available (); if ( !touched ) { data->state = LV_INDEV_STATE_REL; } else { data->state = LV_INDEV_STATE_PR; data->point.x = touch.data.x; data->point.y = touch.data.y; Serial.print ( "Data x " ); Serial.println ( touch.data.x ); Serial.print ( "Data y " ); Serial.println ( touch.data.y ); } } void setup () { Serial.begin ( 115200 ); String LVGL_Arduino = "Hello Arduino! " ; LVGL_Arduino += String ('V' ) + lv_version_major () + "." + lv_version_minor () + "." + lv_version_patch (); Serial.println ( LVGL_Arduino ); Serial.println ( "I am LVGL_Arduino" ); lv_init (); #if LV_USE_LOG != 0 lv_log_register_print_cb ( my_print ); #endif tft.begin (); tft.setRotation ( 2 ); touch.begin (); Serial.print (touch.data.version); Serial.print ("\t" ); Serial.print (touch.data.versionInfo[0 ]); Serial.print ("-" ); Serial.print (touch.data.versionInfo[1 ]); Serial.print ("-" ); Serial.println (touch.data.versionInfo[2 ]); lv_disp_draw_buf_init ( &draw_buf, buf, NULL , screenWidth * 10 ); static lv_disp_drv_t disp_drv; lv_disp_drv_init ( &disp_drv ); disp_drv.hor_res = screenWidth; disp_drv.ver_res = screenHeight; disp_drv.flush_cb = my_disp_flush; disp_drv.draw_buf = &draw_buf; lv_disp_drv_register ( &disp_drv ); static lv_indev_drv_t indev_drv; lv_indev_drv_init ( &indev_drv ); indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = my_touchpad_read; lv_indev_drv_register ( &indev_drv ); lv_obj_t *label_top = lv_label_create ( lv_scr_act () ); lv_label_set_text ( label_top, LVGL_Arduino.c_str () ); lv_obj_align ( label_top, LV_ALIGN_TOP_LEFT, 0 , 0 ); lv_obj_t *label = lv_label_create ( lv_scr_act () ); lv_label_set_text ( label, LVGL_Arduino.c_str () ); lv_obj_align ( label, LV_ALIGN_CENTER, 0 , 0 ); lv_obj_t *label_bottom = lv_label_create ( lv_scr_act () ); lv_label_set_text ( label_bottom, LVGL_Arduino.c_str () ); lv_obj_align ( label_bottom, LV_ALIGN_BOTTOM_RIGHT, 0 , 0 ); Serial.println ( "Setup done" ); } void loop () { lv_timer_handler (); delay ( 5 ); }
5.lvgl demo 使用官方demos流程:
lv_conf.h 中 #define LV_USE_DEMO_WIDGETS 1
将lvgl库中的demos移动到src文件夹。不然会出现undefined reference to 'lv_demo_benchmark'
(例如lv_demo_benchmark) 这是由于lv_demo_benchmark.c未被编译导致的 把demos文件夹移动到lvgl的src目录下就行了,这样就会参与到编译中了
包含头文件,例如在main.c文件中 #include "demos/lv_demos.h"
初始化等参考官方例程,setup中调用demo中的函数即可。 lv_demo_widgets();
面包板测试 注意核对FPC座的线序(1脚的位置)
ESP32
FPC
Function
Other
GND
1
GND
GND
2
LED_K
可通过PWM调整亮度
3V3
3
VDD
供电
3V3
4
VDD
GND
5
GND
GND
6
GND
2
7
D/C
GND
8
CS
默认拉低一直有效
18
9
SCL
SPI_SCL
23
10
SDA
SPI_MOSI
32
11
REST
LCD_RST
GND
12
GND
4
13
TP_SCL
I2C0_SCL
15
14
TP_SDA
I2C0_SDA
5
15
TP_RST
Touch_RST
34
16
TP_INT
Touch_INT
3V3
17
VDD
GND
18
GND
6.使用自己设计的PCB板 Controler_ESP32_V0.1(PFC座方向反了)
ESP32
FPC
Function
Other
GND
1
GND
GND
2
LED_K
可通过PWM调整亮度
3V3
3
VDD
供电
3V3
4
VDD
GND
5
GND
GND
6
GND
2
7
D/C
32
8
CS
18
9
SCL
SPI_SCL
23
10
SDA
SPI_MOSI
PCA9535 IO10
11
REST
IO扩展芯片 I2C0控制
GND
12
GND
4
13
TP_SCL
I2C0_SCL
15
14
TP_SDA
I2C0_SDA
PCA9535 IO11
15
TP_RST
IO扩展芯片 I2C0控制
34
16
TP_INT
Touch_INT
3V3
17
VDD
GND
18
GND