ESP32 + Arduino使用TFT_eSPI库(LCD驱动芯片ST7789)
TFT_eSPI是用于TFT-LCD液晶屏的Arduino图形库,可支持下面多种液晶屏驱动芯片:
- ILI9163
- ILI9225
- ILI9341
- ILI9481 (DMA not supported with SPI)
- ILI9486 (DMA not supported with SPI)
- ILI9488 (DMA not supported with SPI)
- HX8357D
- S6D02A1
- SSD1351
- SSD1963
- ST7735
- ST7789
- ST7796
- GC9A01
之前在淘宝买了一块2.4寸240×320像素的SPI串口屏(使用的驱动芯片是ST7789V),下面尝试使用TFT_eSPI库在Arduino+ESP32上快速点亮这个屏幕。屏幕上有8个引脚,我对应的接线如下(我买的这个屏幕背光线不接悬空的话屏幕不会亮)
ESP32引脚 | ST7789引脚 | 功能 |
---|---|---|
GND | GND | 接地 |
3V3 | VCC | 电源 |
18 | SCL | SPI时钟 |
23 | SDA(MOSI) | SPI主出从入 |
26 | RES | 复位引脚 |
27 | DC | 数据/命令选择 |
5 | CS | SPI片选 |
22 | BLK | 背光控制 |
在Arduino的库管理器中下载TFT_eSPI库,之后在该库的路径下(C:\Users\xx\Documents\Arduino\libraries\TFT_eSPI)打开User_Setup.h文件。User_Setup.h中有一些需要自己配置的宏,需要仔细阅读这个头文件中的注释。几个比较关键的地方如下:
(1)选择对应的液晶屏驱动芯片,取消注释
// 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 // Define additional parameters below for this display //#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
(2)定义屏幕尺寸,我的屏幕是240×320像素,因此选择TFT_WIDTH为240,TFT_HEIGHT为320
// 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 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
(3) 定义对应模块的引脚
// For ESP32 Dev board (only tested with ILI9341 display) // The hardware SPI can be mapped to any pins #define TFT_MISO 19 #define TFT_MOSI 23 #define TFT_SCLK 18 #define TFT_CS 5 // Chip select control pin #define TFT_DC 27 // Data Command control pin #define TFT_RST 26 // Reset pin (could connect to RST pin) #define TFT_BL 22 //#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
(4)定义用到的字体(由于会占用单片机存储空间,没用的字体可以注释掉)
// Comment out the #defines below with // to stop that font being loaded // The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not // normally necessary. If all fonts are loaded the extra FLASH space required is // about 17Kbytes. To save FLASH space only enable the fonts you need! #define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH #define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters #define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters #define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm #define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-. #define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. //#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT #define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
(5)其它设置如SPI频率,按照User_Setup.h头文件中的提示来设置。
// Define the SPI clock frequency, this affects the graphics rendering speed. Too // fast and the TFT driver will not keep up and display corruption appears. // With an ILI9341 display 40MHz works OK, 80MHz sometimes fails // With a ST7735 display more than 27MHz may not work (spurious pixels and lines) // With an ILI9163 display 27 MHz works OK. // #define SPI_FREQUENCY 1000000 // #define SPI_FREQUENCY 5000000 // #define SPI_FREQUENCY 10000000 // #define SPI_FREQUENCY 20000000 // #define SPI_FREQUENCY 27000000 #define SPI_FREQUENCY 40000000 // #define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz) // #define SPI_FREQUENCY 80000000 // Optional reduced SPI frequency for reading TFT #define SPI_READ_FREQUENCY 20000000 // The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here: #define SPI_TOUCH_FREQUENCY 2500000 // The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default. // If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam) // then uncomment the following line: //#define USE_HSPI_PORT
在测试的时候发现屏幕上某些颜色很奇怪,比如设置字体为蓝色但显示红色。原因是在ST7789芯片中MADCTL (36h)寄存器的第3位控制像素颜色顺序,当该位为0时颜色按R-G-B显示,当该位为1时按B-G-R显示:
Bit D3- RGB/BGR Order
“0” = RGB (When MADCTL D3=”0”)
“1” = BGR (When MADCTL D3=”1”)
出现这种问题时可以在User_Setup.h中取消掉下面某一行的注释,来控制颜色顺序
// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display // Try ONE option at a time to find the correct colour order for your display // #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
初次使用过程中还可能遇到屏幕方向或者颜色反转的问题,可以通过TFT_eSPI提供的函数来控制屏幕旋转和颜色反转(参考光学中的互补色,如白-黑,蓝-黄)
/*************************************************************************************** ** Function name: invertDisplay ** Description: invert the display colours i = 1 invert, i = 0 normal ***************************************************************************************/ void TFT_eSPI::invertDisplay(bool i) /*************************************************************************************** ** Function name: setRotation ** Description: rotate the screen orientation m = 0-3 or 4-7 for BMP drawing ***************************************************************************************/ void TFT_eSPI::setRotation(uint8_t m)
注意到TFT_eSPI库下面还有一个User_Setup_Select.h头文件,这个头文件中可以选择预先定义好的用户配置(相关文件位于TFT_eSPI/User_Setups文件夹中)。由于这些配置不适用于我买的这个屏幕,因此直接使用User_Setup.h中的定义。
// Only ONE line below should be uncommented. Add extra lines and files as needed. #include <User_Setup.h> // Default setup is root library folder //#include <User_Setups/Setup1_ILI9341.h> // Setup file configured for my ILI9341 //#include <User_Setups/Setup2_ST7735.h> // Setup file configured for my ST7735 //#include <User_Setups/Setup3_ILI9163.h> // Setup file configured for my ILI9163 //#include <User_Setups/Setup4_S6D02A1.h> // Setup file configured for my S6D02A1 //#include <User_Setups/Setup5_RPi_ILI9486.h> // Setup file configured for my stock RPi TFT //#include <User_Setups/Setup6_RPi_Wr_ILI9486.h> // Setup file configured for my modified RPi TFT //#include <User_Setups/Setup7_ST7735_128x128.h> // Setup file configured for my ST7735 128x128 display //#include <User_Setups/Setup8_ILI9163_128x128.h> // Setup file configured for my ILI9163 128x128 display //#include <User_Setups/Setup9_ST7735_Overlap.h> // Setup file configured for my ST7735 //#include <User_Setups/Setup10_RPi_touch_ILI9486.h> // Setup file configured for ESP8266 and RPi TFT with touch
...
下面的代码在屏幕上测试文字输出,从TFT_eSPI/examples中可以找到各种例子来进行测试。
#include <TFT_eSPI.h> #include <SPI.h> #define TFT_GREY 0x5AEB // New colour TFT_eSPI tft = TFT_eSPI(); // Invoke library void setup(void) { tft.init(); tft.setRotation(0); tft.invertDisplay(0); } void loop() { // Fill screen with grey so we can see the effect of printing with and without // a background colour defined tft.fillScreen(TFT_GREY); // Set "cursor" at top left corner of display (0,0) and select font 2 // (cursor will move to next line automatically during printing with 'tft.println' // or stay on the line is there is room for the text with tft.print) tft.setCursor(0, 0, 2); // Set the font colour to be white with a black background, set text size multiplier to 1 tft.setTextColor(TFT_WHITE,TFT_BLACK); tft.setTextSize(1); // We can now plot text on screen using the "print" class tft.println("Hello World!"); // Set the font colour to be yellow with no background, set to font 7 tft.setTextColor(TFT_YELLOW,TFT_BLACK); tft.setTextFont(7); tft.println(1234.56); // Set the font colour to be green with black background, set to font 4 tft.setTextColor(TFT_GREEN,TFT_BLACK); tft.setTextFont(4); tft.println("Groop"); tft.println("I implore thee,"); // Change to font 2 tft.setTextFont(2); tft.println("my foonting turlingdromes."); tft.println("And hooptiously drangle me"); tft.println("with crinkly bindlewurdles,"); // This next line is deliberately made too long for the display width to test // automatic text wrapping onto the next line tft.println("Or I will rend thee in the gobberwarts with my blurglecruncheon, see if I don't!"); // Test some print formatting functions float fnumber = 123.45; // Set the font colour to be blue with no background, set to font 4 tft.setTextColor(TFT_BLUE); tft.setTextFont(4); tft.print("Float = "); tft.println(fnumber); // Print floating point number tft.print("Binary = "); tft.println((int)fnumber, BIN); // Print as integer value in binary tft.print("Hexadecimal = "); tft.println((int)fnumber, HEX); // Print as integer number in Hexadecimal delay(10000); }
参考: