最近买了一个圆形的液晶显示屏,这个造型很特别是表盘的原型。它的主控是 GC9A01,我在网上搜了一圈没有找到现成的库于是只能自己研究。查看了一下 SPEC发现Command 之类的和ST7789基本相同,但是直接使用 ST7789 无法驱动显示。为此只能从头研究。
测试使用 FireBeetle(ESP32),特别需要注意的是从资料上看这个屏幕只支持 3.3V,因此使用 UNO 这样的板子有烧毁的可能,我也并没有试验过UNO 这样的5V 的板子,具体建议询问卖家。
硬件连接:
FireBeetle(ESP32) | GC9A01 | |
3.3V | VCC | |
GND | GND | |
D9 | DC | |
D2 | RST | |
D10(预留给CS 未使用) | ||
CS | GND | |
BLK | 未连接 | |
SCL | ||
SDA |
最终只得从卖家的代码上修改。卖家提供了很多代码,最终选择从C51 代码上修改:
#include <SPI.h>
//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
#define DARKBLUE 0X01CF //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458 //灰蓝色
#define LIGHTGREEN 0X841F //浅绿色
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
#define TFT_DC D9
#define TFT_RST D2
#define TFT_CS D10
#define LCD_RES_Clr() digitalWrite(TFT_RST,LOW)
#define LCD_RES_Set() digitalWrite(TFT_RST,HIGH)
#define LCD_DC_Clr() digitalWrite(TFT_DC,LOW)
#define LCD_DC_Set() digitalWrite(TFT_DC,HIGH)
#define u16 word
#define delay_ms delay
#define LCD_W 240
#define LCD_H 240
#if defined (SPI_HAS_TRANSACTION)
static SPISettings mySPISettings;
#endif
/******************************************************************************
函数说明:LCD写入命令
入口数据:dat 写入的命令
返回值: 无
******************************************************************************/
void LCD_WR_REG(byte c)
{
LCD_DC_Clr();//写命令
#if defined (SPI_HAS_TRANSACTION)
SPI.begin();
SPI.beginTransaction(mySPISettings);
SPI.transfer(c);
SPI.endTransaction();
#endif
LCD_DC_Set();
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA(u16 dat)
{
#if defined (SPI_HAS_TRANSACTION)
SPI.begin();
SPI.beginTransaction(mySPISettings);
SPI.transfer(dat>>8);
SPI.transfer(dat);
SPI.endTransaction();
#endif
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA8(byte c)
{
#if defined (SPI_HAS_TRANSACTION)
SPI.begin();
SPI.beginTransaction(mySPISettings);
SPI.transfer(c);
SPI.endTransaction();
#endif
}
void LCD_Init(void)
{
LCD_RES_Clr();//复位
delay_ms(100);
LCD_RES_Set();
delay_ms(100);
LCD_WR_REG(0xEF);
LCD_WR_REG(0xEB);
LCD_WR_DATA8(0x14);
LCD_WR_REG(0xFE);
LCD_WR_REG(0xEF);
LCD_WR_REG(0xEB);
LCD_WR_DATA8(0x14);
LCD_WR_REG(0x84);
LCD_WR_DATA8(0x40);
LCD_WR_REG(0x85);
LCD_WR_DATA8(0xFF);
LCD_WR_REG(0x86);
LCD_WR_DATA8(0xFF);
LCD_WR_REG(0x87);
LCD_WR_DATA8(0xFF);
LCD_WR_REG(0x88);
LCD_WR_DATA8(0x0A);
LCD_WR_REG(0x89);
LCD_WR_DATA8(0x21);
LCD_WR_REG(0x8A);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0x8B);
LCD_WR_DATA8(0x80);
LCD_WR_REG(0x8C);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0x8D);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0x8E);
LCD_WR_DATA8(0xFF);
LCD_WR_REG(0x8F);
LCD_WR_DATA8(0xFF);
LCD_WR_REG(0xB6);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x20);
LCD_WR_REG(0x36);
LCD_WR_DATA8(0x08);
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x05);
LCD_WR_REG(0x90);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x08);
LCD_WR_REG(0xBD);
LCD_WR_DATA8(0x06);
LCD_WR_REG(0xBC);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0xFF);
LCD_WR_DATA8(0x60);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x04);
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x13);
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x13);
LCD_WR_REG(0xC9);
LCD_WR_DATA8(0x22);
LCD_WR_REG(0xBE);
LCD_WR_DATA8(0x11);
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0x10);
LCD_WR_DATA8(0x0E);
LCD_WR_REG(0xDF);
LCD_WR_DATA8(0x21);
LCD_WR_DATA8(0x0c);
LCD_WR_DATA8(0x02);
LCD_WR_REG(0xF0);
LCD_WR_DATA8(0x45);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x26);
LCD_WR_DATA8(0x2A);
LCD_WR_REG(0xF1);
LCD_WR_DATA8(0x43);
LCD_WR_DATA8(0x70);
LCD_WR_DATA8(0x72);
LCD_WR_DATA8(0x36);
LCD_WR_DATA8(0x37);
LCD_WR_DATA8(0x6F);
LCD_WR_REG(0xF2);
LCD_WR_DATA8(0x45);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x26);
LCD_WR_DATA8(0x2A);
LCD_WR_REG(0xF3);
LCD_WR_DATA8(0x43);
LCD_WR_DATA8(0x70);
LCD_WR_DATA8(0x72);
LCD_WR_DATA8(0x36);
LCD_WR_DATA8(0x37);
LCD_WR_DATA8(0x6F);
LCD_WR_REG(0xED);
LCD_WR_DATA8(0x1B);
LCD_WR_DATA8(0x0B);
LCD_WR_REG(0xAE);
LCD_WR_DATA8(0x77);
LCD_WR_REG(0xCD);
LCD_WR_DATA8(0x63);
LCD_WR_REG(0x70);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x0E);
LCD_WR_DATA8(0x0F);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x03);
LCD_WR_REG(0xE8);
LCD_WR_DATA8(0x34);
LCD_WR_REG(0x62);
LCD_WR_DATA8(0x18);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x71);
LCD_WR_DATA8(0xED);
LCD_WR_DATA8(0x70);
LCD_WR_DATA8(0x70);
LCD_WR_DATA8(0x18);
LCD_WR_DATA8(0x0F);
LCD_WR_DATA8(0x71);
LCD_WR_DATA8(0xEF);
LCD_WR_DATA8(0x70);
LCD_WR_DATA8(0x70);
LCD_WR_REG(0x63);
LCD_WR_DATA8(0x18);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x71);
LCD_WR_DATA8(0xF1);
LCD_WR_DATA8(0x70);
LCD_WR_DATA8(0x70);
LCD_WR_DATA8(0x18);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x71);
LCD_WR_DATA8(0xF3);
LCD_WR_DATA8(0x70);
LCD_WR_DATA8(0x70);
LCD_WR_REG(0x64);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x29);
LCD_WR_DATA8(0xF1);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0xF1);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x07);
LCD_WR_REG(0x66);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0xCD);
LCD_WR_DATA8(0x67);
LCD_WR_DATA8(0x45);
LCD_WR_DATA8(0x45);
LCD_WR_DATA8(0x10);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0x67);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x54);
LCD_WR_DATA8(0x10);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x98);
LCD_WR_REG(0x74);
LCD_WR_DATA8(0x10);
LCD_WR_DATA8(0x85);
LCD_WR_DATA8(0x80);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x4E);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0x98);
LCD_WR_DATA8(0x3e);
LCD_WR_DATA8(0x07);
LCD_WR_REG(0x35);
LCD_WR_REG(0x21);
LCD_WR_REG(0x11);
delay_ms(120);
LCD_WR_REG(0x29);
delay_ms(20);
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1);
LCD_WR_DATA(x2);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1);
LCD_WR_DATA(y2);
LCD_WR_REG(0x2c);//储存器写
}
/******************************************************************************
函数说明:在指定区域填充颜色
入口数据:xsta,ysta 起始坐标
xend,yend 终止坐标
color 要填充的颜色
返回值: 无
******************************************************************************/
void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color)
{
u16 i,j;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);//设置显示范围
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
LCD_WR_DATA(color);
}
}
}
void setup() {
pinMode(TFT_CS,OUTPUT);
digitalWrite(TFT_CS,LOW);
pinMode(TFT_DC,OUTPUT);
pinMode(TFT_RST,OUTPUT);
mySPISettings = SPISettings(1000000, MSBFIRST, SPI_MODE0);
LCD_Init();
}
void loop() {
LCD_Fill(0,0,LCD_W,LCD_H,BLUE);
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
LCD_Fill(0,0,LCD_W,LCD_H,BRED);
LCD_Fill(0,0,LCD_W,LCD_H,GRED);
LCD_Fill(0,0,LCD_W,LCD_H,RED);
LCD_Fill(0,0,LCD_W,LCD_H,MAGENTA);
LCD_Fill(0,0,LCD_W,LCD_H,GREEN);
LCD_Fill(0,0,LCD_W,LCD_H,CYAN);
}
测试的内容是不断让屏幕变换颜色:
老哥, 有没有清屏的命令啊? 我想做个矩形移动的动画, 但是用LCD_Fill() 速度太慢. 请您指教
我查了一下,没有的。不过Esp32 可以达到 40Mhz 的 SPI 速度,填充速度不慢啊。
void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color)
{
u16 i,j;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);//设置显示范围
SPI.begin();
SPI.beginTransaction(mySPISettings);
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
SPI.transfer16(color);
}
}
SPI.endTransaction();
}
这样写刷屏速度能提高十几倍
谢谢指教,有机会我试试。