兄弟们,写这个文章的原因是因为百度上是真找不到单片机驱动双屏的资料啊。。。研究了一两个星期的干货都塞进来了。
一、硬件
1、材料:
a.开发板:合宙的ESP32-C3真香板 RMB12.9,链接
b.屏幕:0.96寸 ST7735S驱动 80*160像素,优信的链接
2、接线:
用开发板测试通过之后,我就画了块板子来做的好看点。
两块屏都是8位SPI(带DC脚的),然后可以共用一些脚:DC、SPI_MOSI(SDA)、 SPI_SCLK(SCL),RST和SPI_CS不能共用
![](https://img-blog.csdnimg.cn/img_convert/49a52b4d2244448ea6fc005f0b6da9af.png)
3、PCB的3D截个图表示一下
![](https://img-blog.csdnimg.cn/img_convert/8959f42df5948a2d0b6aa9c8c7436ca9.png)
所以两个屏幕是一左一右的,这个后面做LVGL的双屏支持的时候需要用到
二、软件
1、驱动屏幕,Adafruit_GFX库
a.环境的搭建
VScode+PIO的环境从PIO的Libraryies里找Adafruit ST7735 and ST7789
![](https://img-blog.csdnimg.cn/img_convert/cdae45477d61508b9ef4236c21c24bda.png)
我这边这个库的版本是1.9.3,Add to Project后可以直接使用这些个代码来验证一下硬件链接啥的
![](https://img-blog.csdnimg.cn/img_convert/4ff77be396f0aa80bc17bf4900ef2977.png)
只是需要修改IO,并且将setup()和loop()函数放到其它函数的最下面去(不细说了)
我这边跑过这个例程OK之后删改的代码是这样的:
#include <Arduino.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>
#define TFT_CS 9 //管脚定义,左边的屏幕
#define TFT_RST 18
#define TFT_DC 19
#define TFT_SCLK 1
#define TFT_MOSI 0
#define TFT_CS2 5 //管脚定义,右边的屏幕
#define TFT_RST2 7
#define TFT_DC2 19
#define TFT_SCLK2 1
#define TFT_MOSI2 0
#define BL_EN 2
//简单粗暴的双屏定义
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
Adafruit_ST7735 tft2 = Adafruit_ST7735(TFT_CS2, TFT_DC2, TFT_MOSI2, TFT_SCLK2, TFT_RST2);
void setup(){
pinMode(BL_EN,OUTPUT);
digitalWrite(BL_EN,LOW); //打开背光
tft.initR(INITR_MINI160x80); // Init ST7735S chip, black tab
tft.setRotation(3); //旋转屏幕
tft2.initR(INITR_MINI160x80); // Init ST7735S chip, black tab
tft2.setRotation(1); //旋转屏幕
tft.fillRect(0,0,160,80,ST77XX_RED);
tft2.fillRect(0,0,160,80,ST77XX_GREEN);
tft.invertDisplay(true); //两个屏幕反色
tft2.invertDisplay(true);
}
void loop(){
}
b.问题的解决
如果你跟我使用的是一样的屏幕的话,就会看到写了红色的屏幕亮的是蓝色,写了绿色的屏幕却正常显示绿色。
如果你跟我使用的不是一样的屏幕,可能会看到写了红色的屏幕亮的是黄色,写了绿色的屏幕显示的是紫红色,那请你将 tft.invertDisplay(true);的true改为false,因为你不需要反色。
好了,如果你的屏幕与我一样,那很容易地,就能分析到:代码中颜色是RGB的顺序,而屏幕的颜色所需要的是BGR的顺序。
首先从main.cpp的tft.setRotation(3);的函数跳进去,从里面的四个case中可以看到RGB与GRB的字样,很显然代码走了RGB这条路,我们现在需要让他走GRB的路,我使用的方法是注释掉if...else...然后直接把原本else里的代码拿出来,如下:
![](https://img-blog.csdnimg.cn/img_convert/23da5f203717dbc9ddb5421d53479e00.png)
![](https://img-blog.csdnimg.cn/img_convert/98f12366914cf6810fecfc520b7dddb6.png)
然后我们烧录一下,就会发现颜色已经正常了。
然后烧录一下如下代码:
#include <Arduino.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>
#define TFT_CS 9 //管脚定义,左边的屏幕
#define TFT_RST 18
#define TFT_DC 19
#define TFT_SCLK 1
#define TFT_MOSI 0
#define TFT_CS2 5 //管脚定义,右边的屏幕
#define TFT_RST2 7
#define TFT_DC2 19
#define TFT_SCLK2 1
#define TFT_MOSI2 0
#define BL_EN 2
//简单粗暴的双屏定义
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
Adafruit_ST7735 tft2 = Adafruit_ST7735(TFT_CS2, TFT_DC2, TFT_MOSI2, TFT_SCLK2, TFT_RST2);
void setup(){
pinMode(BL_EN,OUTPUT);
digitalWrite(BL_EN,LOW); //打开背光
tft.initR(INITR_MINI160x80); // Init ST7735S chip, black tab
tft.setRotation(3); //旋转屏幕
tft2.initR(INITR_MINI160x80); // Init ST7735S chip, black tab
tft2.setRotation(1); //旋转屏幕
tft.fillRect(0,0,160,80,ST77XX_WHITE);
tft2.fillRect(0,0,160,80,ST77XX_WHITE);
tft.drawLine(0,0,159,0,ST77XX_BLUE); //第一块屏幕最顶部画一条线-蓝色
tft.drawLine(0,1,159,1,ST77XX_YELLOW); //第一块屏幕第二排像素画一条线-黄色
tft.drawLine(0,2,159,2,ST77XX_GREEN); //第一块屏幕第三排像素画一条线-绿色
tft2.drawLine(0,0,0,79,ST77XX_BLUE); //第二块屏幕最左侧那一列的像素画一条线-蓝色
tft2.drawLine(1,0,1,79,ST77XX_YELLOW); //第二块屏幕最左侧倒数第二列的像素画一条线-黄色
tft2.drawLine(2,0,2,79,ST77XX_GREEN); //第二块屏幕最左侧倒数第二列的像素画一条线-绿色
tft.invertDisplay(true); //两个屏幕反色
tft2.invertDisplay(true);
}
void loop(){
}
这只是在刷全屏之后画几条线,注意37~43的注释,烧录完这个代码之后断电再重新上电,会发现有几条线理应刷上来的却没有显示。并且屏幕的下方和右侧有杂色点。
这是因为屏幕被偏移了,仔细看看可以确定屏幕被左移了1个像素,被上移了2个像素。(看不太清,可能我说反了)
解决方法是:从setup()里的tft.initR(INITR_MINI160x80);跳进去,改这两行:
![](https://img-blog.csdnimg.cn/img_convert/aa5233e3e06d662ab3ffc231fc78914b.png)
这两行是x和y的偏移,改了之后屏幕就对准了。
2、LVGL移植
VScode+PIO的环境从PIO的Libraryies里找LVGL
![](https://img-blog.csdnimg.cn/img_convert/d4a9f5aed776d022ca6bb85866e9de43.png)
然后建议大家第一次用类似GUI的,或是英文不太好的,选用8.2或更低的版本,因为我在百度找了一圈,中文教程做的好的应该只有百问网,百问网现在还没有汉化8.3版本的文档,百问网LVGL8.2版本文档汉化网址
LVGL是这样的,B站很多视频是跑他的Demo,LVGL的Demo也好,主体的源码也好,都是分开的,上面这个只是添加了LVGL的主体源码进来。然后LVGL有个特点是它的配置文件一开始是没配置好的,所以需要这样操作:
在Vscode左侧找到.pio\libdeps\esp32-c3-devkitm-2(这个可能与你不一样)\lvgl找到lv_conf_template.h文件,复制它并粘贴到.pio\libdeps\esp32-c3-devkitm-2(这个可能与你不一样)目录下。 然后改名成lv_conf.h (就是把_template删掉),如图:
![](https://img-blog.csdnimg.cn/img_convert/b75be01684d9369fb4b9d38c9df0e3b7.png)
![](https://img-blog.csdnimg.cn/img_convert/1cbc5396f1b5e421cead732b4cc46d8e.png)
不要放到lvgl的文件夹里哈,不然编译会报错
然后把lv_conf.h的第15行 #if 0改成#if 1,
把第88行的#define LV_TICK_CUSTOM 0 改成#define LV_TICK_CUSTOM 1。
然后保存好,main.cpp里代码写成这样:
#include <Arduino.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>
#include <lvgl.h> //调用LVGL
#define TFT_WIDTH 320 //LVGL认为的屏幕大小
#define TFT_HEIGHT 80
static lv_disp_draw_buf_t draw_buf; //定义显示器变量
static lv_color_t buf[TFT_WIDTH * 20]; //定义刷新缓存
static lv_color_t buf2[TFT_WIDTH * 20]; //定义刷新缓存
#define TFT_CS 9 //管脚定义,左边的屏幕
#define TFT_RST 18
#define TFT_DC 19
#define TFT_SCLK 1
#define TFT_MOSI 0
#define TFT_CS2 5 //管脚定义,右边的屏幕
#define TFT_RST2 7
#define TFT_DC2 19
#define TFT_SCLK2 1
#define TFT_MOSI2 0
#define BL_EN 2
//简单粗暴的双屏定义
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
Adafruit_ST7735 tft2 = Adafruit_ST7735(TFT_CS2, TFT_DC2, TFT_MOSI2, TFT_SCLK2, TFT_RST2);
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) //LVGL用来调用显示库的函数,所以不同的显示库这个函数的内容不同
{
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
//跨屏幕操作
if(area->x1 < 160) tft2.drawRGBBitmap(area->x1, area->y1,(uint16_t *)&(color_p->full),w, h);
if(area->x2 >= 160) tft1.drawRGBBitmap(area->x1-160, area->y1,(uint16_t *)&(color_p->full),w, h);
lv_disp_flush_ready(disp); //调用区域填充颜色函数
}
void setup(){
pinMode(BL_EN,OUTPUT);
digitalWrite(BL_EN,LOW); //打开背光
tft.initR(INITR_MINI160x80); // Init ST7735S chip, black tab
tft.setRotation(3); //旋转屏幕
tft2.initR(INITR_MINI160x80); // Init ST7735S chip, black tab
tft2.setRotation(1); //旋转屏幕
tft.invertDisplay(true); //两个屏幕反色
tft2.invertDisplay(true);
lv_init();
lv_disp_draw_buf_init(&draw_buf, buf, buf2, TFT_WIDTH * 20);
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = TFT_WIDTH;
disp_drv.ver_res = TFT_HEIGHT;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
static lv_disp_t* disp1 = lv_disp_drv_register(&disp_drv); //初始化好显示屏的区域
lv_obj_set_style_bg_color(lv_scr_act(),lv_color_hex(0x000000),0); //改个黑色的背景色
lv_obj_t *label_1 = lv_label_create(lv_scr_act()); //建立一个标签对象
lv_label_set_text(label_1, "Display left:\r\nHello word"); //给他打个字
lv_obj_align(label_1, LV_ALIGN_CENTER,-80,0); //设置位置在居中左移80的位置,这样就是左边屏幕的中间了
lv_obj_set_style_text_font(label_1,&lv_font_montserrat_14,0); //在没修改的情况下只有这个字体能用,如果报错就注释掉
lv_obj_set_style_text_color(label_1,lv_color_hex(0xFF0000),0); //设置颜色
lv_obj_t *label_2 = lv_label_create(lv_scr_act()); //建立一个标签对象
lv_label_set_text(label_2, "Display right:\r\nHello word"); //给他打个字
lv_obj_align(label_2, LV_ALIGN_CENTER,80,0); //设置位置在居中右移80的位置,这样就是右边屏幕的中间了
lv_obj_set_style_text_font(label_2,&lv_font_montserrat_14,0); //在没修改的情况下只有这个字体能用,如果报错就注释掉
lv_obj_set_style_text_color(label_2,lv_color_hex(0x0000FF),0); //设置颜色
}
void loop(){
lv_timer_handler();
delay(5);
}
然后效果就有了
最后附上我这边的效果图
![](https://img-blog.csdnimg.cn/img_convert/c1a067016f33e3620996e11f00d2b9a2.png)
不过这屏是真的小。。。。
愿这篇文章能帮到你,共勉。