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 80static lv_disp_draw_buf_t draw_buf; //定义显示器变量static lv_color_t buf[TFT_WIDTH * 10]; //定义刷新缓存#define TFT_LEFT 2#define TFT_RIGHT 1TFT_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);//单屏宽度-1tft.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太大了,给他分配小点的空间即可
其它没啥了,有啥问题可以私信,只是我很有可能得过好几天才会看到
祝学习顺利,工作。。愉快吧