LVGL部分的配置找其它人的嗷,至于为什么我之前已经写过一个Adafruit_GFX库(点此跳转)驱动,现在还要写一个TFT_eSPI库驱动的文章,是因为我后来发现Adafruit_GFX库的时钟速率就400多KHz。。实在是太太太慢了,然后不管我怎么改,发现速率就是不变的(即使代码里读出来的SPI速率已经改变了,但是实际示波器量出来依旧没变),所以没办法只能用TFT_eSPI库
使用TFT_eSPI库写双屏是一件很麻烦的事情,更何况ESP32-C3只有一个硬件SPI可以被我们使用。
接线:
这里直接简单讲一下步骤哈,有空再完善:
-
使TFT_eSPI能够支持单片屏幕的显示(参考其它博主的博客即可)
例程:
#include <Arduino.h>
#include <TFT_eSPI.h>
TFT_eSPI tft =TFT_eSPI();
void setup(void) {
tft.init();
tft.setRotation(0);
tft.fillScreen(TFT_BLUE);
tft.setCursor(20, 10);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(2);
tft.print("Hello ST7735!");
}
void loop() {
}
-
在TFT_eSPI/User_Setup.h文件里增加:
#define TFT_CS_Define 9
#define TFT_RST_Define 18
#define TFT_MOSI1 0
#define TFT_SCLK1 1
#define TFT_DC1 19
#define TFT_CS1 9
#define TFT_RST1 18
#define TFT_MOSI2 0
#define TFT_SCLK2 1
#define TFT_DC2 19
#define TFT_CS2 5
#define TFT_RST2 7
//随你加在文件的哪里,这仅仅只是把管脚定义加进去
-
因为只有CS和RST管脚是不一样的,所以可以从文件里原有的TFT_CS和TFT_RST两个定义右键转到引用,会发现只有TFT_eSPI.h里调用了他们,因此:
接下来把TFT_eSPI.h中所有与TFT_CS和TFT_RST相关的定义改成TFT_CS1、TFT_CS2、TFTRST1、TFT_RST2相关的定义,如图所示:
-
改完这里在TFT_eSPI.h的#include "TFT_eSPI.h"后面加上uint8_t TFT_choice;让这个变量来选择我们要控制哪块屏幕,对应地,为了让main.cpp里能调用TFT_choice这个变量,需要在TFT_eSPI.h里加上extern uint8_t TFT_choice;
然后编译下载一下例程看看是不是正常。
-
之后可以从例程的函数跳进来,会看到对RST管脚的调用(如果从init()函数跳进来)和对CS管脚的调用(如果从其它函数跳进来),同样地需要把他们改成类似于如下的代码:
是的,你的任务是把所有原本与RST、CS相关的代码全部修改一遍
-
改完之后调用这个程序:
#include <Arduino.h>
#include <TFT_eSPI.h>
TFT_eSPI tft =TFT_eSPI();
void setup(void) { //注意如果你有背光引脚记得开启
TFT_choice = 1;
tft.init();
tft.invertDisplay(true);
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE);
tft.setCursor(0, 0);
tft.print("Hello ST7735!");
TFT_choice = 2;
tft.init();
tft.invertDisplay(true);
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE);
tft.setCursor(0, 0);
tft.print("Hello ST7735!");
}
void loop() {
}
只要两个屏幕都能正常显示,那TFT_eSPI库本身对双屏的底层支持就已经做好了(现在是双屏复制)
-
使其支持LVGL,做双屏连接
我这用的是两个160*80的屏幕,然后我做横向的屏幕拼接。
LVGL设置宽度320,高度80,
代码如下:
#include <Arduino.h>
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#define TFT_WIDTH 320
#define TFT_HEIGHT 80
static lv_disp_draw_buf_t draw_buf; //定义显示器变量
static lv_color_t buf[TFT_WIDTH * 10]; //定义刷新缓存
#define TFT_LEFT 2
#define TFT_RIGHT 1
TFT_eSPI tft = TFT_eSPI();
//写双屏函数
void Write_two_screens(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t *data_in)
{
uint16_t *data = data_in;
if(x1 < 160 && x2 < 160) //只写左边屏
{
uint32_t w = (x2 - x1 + 1);
uint32_t h = (y2 - y1 + 1);
TFT_choice = TFT_LEFT;
tft.startWrite();
tft.setAddrWindow(x1,y1,w,h);
tft.pushColors(data_in, w * h, true);
tft.endWrite();
}
else if(x1 >= 160 && x2 >= 160) //只写右边屏
{
uint32_t w = (x2 - x1 + 1);
uint32_t h = (y2 - y1 + 1);
TFT_choice = TFT_RIGHT;
tft.startWrite();
tft.setAddrWindow(x1 - 160,y1,w,h);
tft.pushColors(data_in,w * h, true);
tft.endWrite();
}
else //写双屏
{
uint32_t w = (x2 - x1 + 1);
uint32_t h = (y2 - y1 + 1);
uint32_t i,j;
uint32_t num_left = 0,num_right = 0;
uint16_t data[320*10];
for(j = 0;j < h;j ++)
{
for(i = 0;i < w;i ++)
{
if(x1 + i < 160) data[num_left ++] = data_in[j * w + i];
}
}
TFT_choice = TFT_LEFT;
tft.startWrite();
tft.setAddrWindow(x1,y1,160 - x1,h);
tft.pushColors(data,num_left, true);
tft.endWrite();
for(j = 0;j < h;j ++)
{
for(i = 0;i < w;i ++)
{
if(x1 + i >= 160) data[num_right ++] = data_in[j * w + i];
}
}
TFT_choice = TFT_RIGHT;
tft.startWrite();
tft.setAddrWindow(0,y1,x2 - 159,h); //单屏宽度-1
tft.pushColors(data,num_right, true);
tft.endWrite();
}
Serial.printf("x1 = %d,y1 = %d,x2 = %d,y2 = %d\r\n",x1,y1,x2,y2);
}
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
Write_two_screens(area->x1, area->y1,area->x2,area->y2,(uint16_t *)&(color_p->full));
lv_disp_flush_ready(disp);
}
lv_obj_t *label_time;
lv_obj_t *label_time2;
void setup() {
Serial.begin(921600);
while (!Serial);
TFT_choice = TFT_LEFT;
tft.init();
tft.invertDisplay(true);
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE);
tft.setCursor(0, 0);
TFT_choice = TFT_RIGHT;
tft.init();
tft.invertDisplay(true);
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE);
tft.setCursor(0, 0);
lv_init();
lv_disp_draw_buf_init(&draw_buf, buf, NULL, TFT_WIDTH * 10);
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);
label_time = lv_label_create(lv_scr_act());
lv_label_set_text_fmt(label_time, "%d",2);
lv_obj_align(label_time, LV_ALIGN_BOTTOM_MID,0,0);
lv_obj_set_style_text_font(label_time,&lv_font_montserrat_44,0);
lv_obj_set_style_text_color(label_time,lv_color_hex(0x858585),0);
label_time2 = lv_label_create(lv_scr_act());
lv_label_set_text_fmt(label_time2, "%d:%d",11,20);
lv_obj_align(label_time2, LV_ALIGN_TOP_RIGHT,0,0);
lv_obj_set_style_text_font(label_time2,&lv_font_montserrat_20,0);
lv_obj_set_style_text_color(label_time2,lv_color_hex(0x858585),0);
}
void loop() {
delay(5);
lv_timer_handler();
}
需要注意的是,如果你的代码烧录进去有关于Flash的报错,那就表示你用的buff太大了,给他分配小点的空间即可
另外,有人私信我说需要源码,我已经上传在附件里了,不出意外的话你可以在文章顶部看到它。
其它没啥了,有啥问题可以私信,只是我很有可能得过好几天才会看到
祝学习顺利,工作。。愉快吧