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); }View Code
參考: