ESP8266/ESP32 驱动ST7789屏幕
本文以ESP12系列的esp8266相关多个开发板和一款ESP32开发板测试。只需要指定自己开发板具体的SPI引脚即可。
以ardunio 框架开发,本项目需要修改库文件,推荐基于platformio开发,一个项目一个第三方库目录这样不会与其他项目冲突。
安装库
这里以arduino ide 2.0举例,库管理搜索 搜索TFT_eSPI 找到作者为Bodmer的那个进行安装
-
使用platformio + ardunio 框架开发的
1.一种方式,使用pio home的界面搜索安装添加到 当前项目
2.第二种方式:在当前项目路径打开终端执行以下命令,则会安装到本项目路径
pio pkg install -l bodmer/TFT_eSPI
3.第三种方式,修改ini.
在platformio.ini里面添加以下内容,再执行构建或者 执行初始化
pio init
,触发检测ini文件变化会自动下载到本项目路径lib_deps = bodmer/TFT_eSPI@^2.4.76
使用clion+platformio 环境的同学使用第三种修改ini配置的,重新初始化项目更好一些,
pio init --ide clion
帮助把下载的库文件路径加到 cmake 的include中。
定义模组引脚和屏幕
找到 TFT_eSPI
库本地文件路径中的 User_Setup_Select.h
文件
ardunio ide需要自己去库的路径去查找文件。
使用platformio开发,当库安装完成后本项目的.pio文件夹下有一个libdeps文件夹。
通过修改platformio.ini可以直接复制配置无需修改库文件
比如使用wemos d1 uno r32开发板可以直接复制以下配置,使用其他开发板可以复制build_flags。
如果是esp8266则需要降低spi频率
[env:wemos_d1_uno32]
platform = espressif32
board = wemos_d1_uno32
framework = arduino
upload_speed = 921600
monitor_speed = 115200
lib_deps =
bodmer/TFT_eSPI@^2.5.34
build_flags =
-D USER_SETUP_LOADED
-D ST7789_DRIVER
-D TFT_RGB_ORDER=TFT_BGR
# SPI引脚
-D TFT_MOSI=23
-D TFT_SCLK=18
-D TFT_CS=5
-D TFT_DC=2
-D TFT_RST=-1
#触控的片选,没有触控
-D TOUCH_CS=(-1)
# 分辨率
-D TFT_WIDTH=240
-D TFT_HEIGHT=320
# 默认字体未修改
-D LOAD_GLCD
-D LOAD_FONT2
-D LOAD_FONT4
-D LOAD_FONT6
-D LOAD_FONT7
-D LOAD_FONT8
-D LOAD_GFXFF
-D SMOOTH_FONT
# SPI频率 esp32正常使用40M问题不大
-D SPI_FREQUENCY=40000000
# SPI触屏频率这里没有触屏
-D SPI_TOUCH_FREQUENCY=2000000
通过修改.pio文件夹下有一个libdeps文件夹中的库文件
找到User_Setup_Select.h中的 #ifndef USER_SETUP_LOADED
在其上方粘贴以下代码
-
ESP8266
// ############# 直接在这里统一定义 屏幕和开发板/模块SPI引脚############ #define USER_SETUP_LOADED // 使其它定义不生效 #define ST7789_DRIVER // 定义SPI的引脚 以下为8266通用的数字引脚 // #define TFT_MISO 12 // 主读从写 暂不需要 #define TFT_MOSI 13 // 主写从读 #define TFT_SCLK 14 // 时钟 #define TFT_CS 15 // 片选 #define TFT_DC 2 // 数据/命令选择线 #define TFT_RST -1 // 这里连RST故设置为-1 #define TOUCH_CS -1 // 触控的片选,这里暂不使用 // 宽 高 #define TFT_WIDTH 240 #define TFT_HEIGHT 320 // 以下设置为默认暂未修改 #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_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts #define SMOOTH_FONT #define SPI_FREQUENCY 27000000 // SPI频率 #define SPI_TOUCH_FREQUENCY 2500000 // 字面意思 触控的SPI频率 // ###########################################################################
-
ESP32 esp32并未测试多个不同的板子spi是否相等
// ############# 直接在这里统一定义 屏幕和开发板/模块SPI引脚############ #define USER_SETUP_LOADED // 使其它定义不生效 #define ST7789_DRIVER // 定义SPI的引脚 以下为esp32 spi引脚 不确定是否通用 // #define TFT_MISO -1 // 主读从写 暂不需要 #define TFT_MOSI 23 // 主写从读 #define TFT_SCLK 18 // 时钟 #define TFT_CS 5 // 片选 #define TFT_DC 2 // 数据/命令选择线 #define TFT_RST -1 // 这里连RST故设置为-1 #define TOUCH_CS -1 // 触控的片选,这里暂不使用 // 宽 高 #define TFT_WIDTH 240 #define TFT_HEIGHT 320 // 以下设置为默认暂未修改 #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_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts #define SMOOTH_FONT #define SPI_FREQUENCY 27000000 // SPI频率 #define SPI_TOUCH_FREQUENCY 2500000 // 字面意思 触控的SPI频率 // ###########################################################################
需要注意需要注意
MOSI
SCLK
CS
这个三个用到引脚是否为默认SPI引脚。
引脚接线
BLK
是背光开关 可以不接MCU,该脚触碰芯片的金属屏蔽罩也能熄屏
ESP8266系列开发板
ST7789引脚 | ESP8266数字引脚 | Wemos D1 R1 | Wemos d1 r2 & mini | NodeMcu 12(E/F) |
---|---|---|---|---|
GND (地) | - | GND | GND | G |
VCC (可以输入3.3或者5V) | - | 5V/3.3V | 5V/3.3V | 3V |
SCL(SCK时钟) | 14 | D13/SCK/D5 | D5 | D5 |
SDA (数据线mcu到屏幕) | 13 | D11/MOSI/D7 | D7 | D7 |
RES (复位线) | - | RST | RST | RST |
DC (数据/命令选择线) | 2 | D9 | D4 | D4 |
CS (片选) | 15 | D10/SS | D8 | D8 |
ESP32系列开发板
ST7789引脚 | ESP32数字引脚 | Wemos D1 R32 |
---|---|---|
GND (地) | - | GND |
VCC (可以输入3.3或者5V) | - | 5V/3.3V |
SCL (SCK时钟) | 18 | IO18 |
SDA (数据线mcu到屏幕) | 23 | IO23 |
RES (复位线) | - | RST |
DC (数据/命令选择线) | 2 | IO2 |
CS (片选) | 5 | IO5 |
代码
在库文件的examples目录很多。这里找了一个分辨率匹配的时钟例子。
#include <Arduino.h>
#include <SPI.h>
#include "TFT_eSPI.h" // Hardware-specific library
#define TFT_GREY 0x5AEB
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0; // Saved H, M, S x & y multipliers
float sdeg = 0, mdeg = 0, hdeg = 0;
uint16_t osx = 120, osy = 120, omx = 120, omy = 120, ohx = 120, ohy = 120; // Saved H, M, S x & y coords
uint16_t x0 = 0, x1 = 0, yy0 = 0, yy1 = 0;
uint32_t targetTime = 0; // for next 1 second timeout
static uint8_t conv2d(const char *p); // Forward declaration needed for IDE 1.6.x
uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time
boolean initial = 1;
void setup(void) {
tft.init();
tft.setRotation(0);
//tft.fillScreen(TFT_BLACK);
//tft.fillScreen(TFT_RED);
//tft.fillScreen(TFT_GREEN);
//tft.fillScreen(TFT_BLUE);
//tft.fillScreen(TFT_BLACK);
tft.fillScreen(TFT_GREY);
tft.setTextColor(TFT_WHITE, TFT_GREY); // Adding a background colour erases previous text automatically
// Draw clock face
tft.fillCircle(120, 120, 118, TFT_GREEN);
tft.fillCircle(120, 120, 110, TFT_BLACK);
// Draw 12 lines
for (int i = 0; i < 360; i += 30) {
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 114 + 120;
yy0 = sy * 114 + 120;
x1 = sx * 100 + 120;
yy1 = sy * 100 + 120;
tft.drawLine(x0, yy0, x1, yy1, TFT_GREEN);
}
// Draw 60 dots
for (int i = 0; i < 360; i += 6) {
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 102 + 120;
yy0 = sy * 102 + 120;
// Draw minute markers
tft.drawPixel(x0, yy0, TFT_WHITE);
// Draw main quadrant dots
if (i == 0 || i == 180) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
if (i == 90 || i == 270) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
}
tft.fillCircle(120, 121, 3, TFT_WHITE);
// Draw text at position 120,260 using fonts 4
// Only font numbers 2,4,6,7 are valid. Font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : . - a p m
// Font 7 is a 7 segment font and only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : .
tft.drawCentreString("clock", 120, 260, 4);
targetTime = millis() + 1000;
}
void loop() {
if (targetTime < millis()) {
targetTime += 1000;
ss++; // Advance second
if (ss == 60) {
ss = 0;
mm++; // Advance minute
if (mm > 59) {
mm = 0;
hh++; // Advance hour
if (hh > 23) {
hh = 0;
}
}
}
// Pre-compute hand degrees, x & y coords for a fast screen update
sdeg = ss * 6; // 0-59 -> 0-354
mdeg = mm * 6 + sdeg * 0.01666667; // 0-59 -> 0-360 - includes seconds
hdeg = hh * 30 + mdeg * 0.0833333; // 0-11 -> 0-360 - includes minutes and seconds
hx = cos((hdeg - 90) * 0.0174532925);
hy = sin((hdeg - 90) * 0.0174532925);
mx = cos((mdeg - 90) * 0.0174532925);
my = sin((mdeg - 90) * 0.0174532925);
sx = cos((sdeg - 90) * 0.0174532925);
sy = sin((sdeg - 90) * 0.0174532925);
if (ss == 0 || initial) {
initial = 0;
// Erase hour and minute hand positions every minute
tft.drawLine(ohx, ohy, 120, 121, TFT_BLACK);
ohx = hx * 62 + 121;
ohy = hy * 62 + 121;
tft.drawLine(omx, omy, 120, 121, TFT_BLACK);
omx = mx * 84 + 120;
omy = my * 84 + 121;
}
// Redraw new hand positions, hour and minute hands not erased here to avoid flicker
tft.drawLine(osx, osy, 120, 121, TFT_BLACK);
osx = sx * 90 + 121;
osy = sy * 90 + 121;
tft.drawLine(osx, osy, 120, 121, TFT_RED);
tft.drawLine(ohx, ohy, 120, 121, TFT_WHITE);
tft.drawLine(omx, omy, 120, 121, TFT_WHITE);
tft.drawLine(osx, osy, 120, 121, TFT_RED);
tft.fillCircle(120, 121, 3, TFT_RED);
}
}
static uint8_t conv2d(const char *p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
可以看出主要就是利用TFT_eSPI相关函数进行绘制。