新闻  |   论坛  |   博客  |   在线研讨会
ST7789-TFT屏幕驱动(整理有stm32/51单片机/arduino等驱动代码)
优信电子 | 2025-04-11 12:00:00    阅读:28   发布文章


       [ST7789-TFT屏幕驱动(整理有stm32/51单片机/arduino等驱动代码)]


前言

不久前我们收到用户反馈问题中,多次反馈各种不同型号的屏幕驱动不起来,从0开

始编写代码花费大量时间,也有不少初次学习驱动屏幕代码编写经验过少等问题,为此我

们决定以文章的形式发布到CSDN来分享相应的一些经验以及收集整理好的资料,希望可

以帮助用户更加简单的学习或快速移植代码进行项目续我们将陆续分享有关ST7789GC9A01ST7735ILI9341等驱动IC的屏幕驱动案例。

需要整理好的代码可以在评论区留言邮箱!


关于ST7789

市面采用ST7789驱动IC的屏幕不算少见,本人有幸使用过的屏幕中有一款1.3寸和一款

1.54寸的屏幕驱动芯片为ST7789,两者的分辨率均为240x240,网上搜集加上自己编写以

及移植整理有stm32f10x、stm32f407、arduino、stc89c516、ESP32等单片机代码,需

要整理好的代码可以在评论区留言邮箱!


1.3寸TFT-300.jpg

Snipaste_2022-09-14_16-39-41-300.jpg


综合了解并观察屏幕一下的一些参数之后开始进行驱动。

硬件接口使用的 2.54mm 间距的排针接口,这使用杜邦线进行连接,需要设计到自己的PCB上高度也是刚好匹配上面的铜柱做定位使用的。

ST7789

参数

供电电压

3.3~5.5V

驱动IC

ST7789

分辨率

240x240

尺寸

1.3 / 1.54寸

驱动接口

4线SPI


产商在屏幕设计上添加了3.3V稳压芯片以及电平转换芯片,使得这款原本3.3V供电的裸屏可以兼容5V和3.3V的单片机,这也意味着arduino51单片机的用户也可以驱动这款屏幕了,虽然51单片机性能很一般但总比不能驱动的好。

最后了解各个引脚功能之后就可以开始进行驱动


引脚名称

引脚功能

VCC

电源正,3.3 - 5V,需要与通信电平一致

GND

电源负,地

CS

片选,低电平使能

RST

复位,低电平使能

DC

数据/命令选择,低电平命令,高电平数据

SDA

SPI数据输入端口

SCL

SPI时钟信号输入端口

BLK

背光,悬空使能接地关闭,默认上拉至3.3V


stm32驱动


引脚接线

代码方面先按照下表接好线烧录程序之后再对代码移植的关键部分进行说明

stm32f10x

ST7789

3V3

VIN

GND

GND

CS

PB6

RST

PA6

DC

PA7

SDA

PA4

SCL

PA5

BLK

PB7

BLK背光引脚不用可以悬空不接

默认的代码烧录进行之后显示上面图片中大大的 优信电子logo,先把示例代码驱动起来,如果示例代码驱动不起来先检查一下接线供电方面的问题,不然后面代码改了半天没有用找问题就和我刚驱动的时候一样头皮发麻。

1.3寸TFT-300.jpg

驱动成功之后用户可以开始移植代码。



对于“插入”选项卡上的库,在设计时都充分考虑了其中的项与文档整体外观的协调性。 您可以使用这些库来插入表格、页眉、页脚、列表、封面以及其他文档构建基块。 您创建的图片、图表或关系图也将与当前的文档外观协调一致。

代码移植

文件复制

将 lcd、lcd_init的C文件和h文件复制到自己的工程里面,这四个文件包含屏幕初始化以及

驱动画点划线显示文字图像的代码。

另外还有两个文件为image.h和lcdfont.h,这两个文件分别存储显示图片数组与显示文字

数组。


复制到自己工程中编译后会报错,因为缺少了pbdata.h中的毫秒级延时函数,可以把原工

程中的ms延时函数复制过来也可以使用自己编写的,名称与下面的相同即可


void delay_ms(u16 a)


添加好文件到工程里面之后再次编译一般不会报错,如果仍然报错就只能看具体报错信息去修改了

       和上面的接线不变,编写下面主函数先进行测试

int main(void)
{
LCD_Init();
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);   //填充为白色背景色
while(1)
{
LCD_ShowPicture(0,0,LCD_W,LCD_H,YXDZ_logo);   //显示一张图片
}
}

需要用户修改的接口一般有一下几个点

端口修改

lcdfont.h文件中包含对使用引脚的宏定义,修改其中的GPIO以及引脚即可修改使用的端口

//-----------------LCD端口定义---------------- 

#define LCD_SCLK_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_5)//SCL=SCLK
#define LCD_SCLK_Set() GPIO_SetBits(GPIOA,GPIO_Pin_5)

#define LCD_MOSI_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_4)//SDA=MOSI
#define LCD_MOSI_Set() GPIO_SetBits(GPIOA,GPIO_Pin_4)

#define LCD_RES_Clr()  GPIO_ResetBits(GPIOA,GPIO_Pin_6)//RES
#define LCD_RES_Set()  GPIO_SetBits(GPIOA,GPIO_Pin_6)

#define LCD_DC_Clr()   GPIO_ResetBits(GPIOA,GPIO_Pin_7)//DC
#define LCD_DC_Set()   GPIO_SetBits(GPIOA,GPIO_Pin_7)
       
#define LCD_CS_Clr()   GPIO_ResetBits(GPIOB,GPIO_Pin_6)//CS
#define LCD_CS_Set()   GPIO_SetBits(GPIOB,GPIO_Pin_6)

#define LCD_BLK_Clr()  GPIO_ResetBits(GPIOB,GPIO_Pin_7)//BLK
#define LCD_BLK_Set()  GPIO_SetBits(GPIOB,GPIO_Pin_7)

但值得注意的是仅仅修改这里的宏定义是没办法使用的,在lcdfont.c文件中包含着对GPIO引脚以及时钟初始化的函数需要进行端口的修改

oid LCD_GPIO_Init(void)
{
GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);  //使能端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  GPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);
}

修改完这里之后才算是将端口修改完毕

lcdfont.h顶部还有两个宏定义可以自行决定是否修改,分别对应这屏幕显示方向屏幕分辨率的参数

#define USE_HORIZONTAL 0  //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏
#define LCD_W 240
#define LCD_H 240

显示函数

       在lcd.h中包含了屏幕显示内容的函数,以及部分颜色的色号主要用于刷新屏幕背景色的

void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color);//指定区域填充颜色
void LCD_DrawPoint(u16 x,u16 y,u16 color);//在指定位置画一个点
void LCD_DrawLine(u16 x1,u16 y1,u16 x2,u16 y2,u16 color);//在指定位置画一条线
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2,u16 color);//在指定位置画一个矩形
void Draw_Circle(u16 x0,u16 y0,u8 r,u16 color);//在指定位置画一个圆

void LCD_ShowChinese(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示汉字串
void LCD_ShowChinese12x12(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个12x12汉字
void LCD_ShowChinese16x16(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个16x16汉字
void LCD_ShowChinese24x24(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个24x24汉字
void LCD_ShowChinese32x32(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个32x32汉字

void LCD_ShowChar(u16 x,u16 y,u8 num,u16 fc,u16 bc,u8 sizey,u8 mode);//显示一个字符
void LCD_ShowString(u16 x,u16 y,const u8 *p,u16 fc,u16 bc,u8 sizey,u8 mode);//显示字符串
u32 mypow(u8 m,u8 n);//求幂
void LCD_ShowIntNum(u16 x,u16 y,u16 num,u8 len,u16 fc,u16 bc,u8 sizey);//显示整数变量
void LCD_ShowFloatNum1(u16 x,u16 y,float num,u8 len,u16 fc,u16 bc,u8 sizey);//显示两位小数变量

void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[]);//显示图片


//画笔颜色
#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 //浅棕蓝色(选择条目的反色)

在使用的时候只需要看后面的中文注释去调用对应的函数即可,非常方便使用

       但是如果需要显示文字和图片的话只是直接调用上面的函数还不够,汉字数组存储的

lcdfont.h文件中只包含了中英文字母、数字、符号以及非常少量的中文数组,中文数组存储在

以下几个数组中,按照相同的格式自行添加进去即可

中文汉字数组

typedef struct 
{
	unsigned char Index[2];	
	unsigned char Msk[24];
}typFNT_GB12; 
const typFNT_GB12 tfont12[]={
"优",0x24,0x01,0x24,0x02,0x22,0x00,0xFA,0x07,0xA3,0x00,0xA2,0x00,0xA2,0x00,0xA2,0x00,
0x92,0x00,0x92,0x04,0x8A,0x04,0x06,0x07,
"信",0x44,0x00,0x84,0x00,0xFA,0x07,0x02,0x00,0xF3,0x03,0x02,0x00,0xF2,0x03,0x02,0x00,
0xF2,0x03,0x12,0x02,0xF2,0x03,0x12,0x02,
"电",0x10,0x00,0x10,0x00,0xFF,0x01,0x11,0x01,0x11,0x01,0xFF,0x01,0x11,0x01,0x11,0x01,
0xFF,0x01,0x11,0x04,0x10,0x04,0xE0,0x07,
"子",0x00,0x00,0xFC,0x01,0x80,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0xFF,0x07,0x20,0x00,
0x20,0x00,0x20,0x00,0x20,0x00,0x38,0x00,
};

typedef struct 
{
	unsigned char Index[2];	
	unsigned char Msk[32];
}typFNT_GB16; 
const typFNT_GB16 tfont16[]={
"优",0x10,0x09,0x10,0x11,0x10,0x11,0x08,0x01,0xE8,0x7F,0x0C,0x05,0x0C,0x05,0x0A,0x05,
0x09,0x05,0x08,0x05,0x88,0x04,0x88,0x44,0x88,0x44,0x48,0x44,0x48,0x78,0x28,0x00,
"信",0x10,0x02,0x10,0x04,0xD0,0x7F,0x08,0x00,0x08,0x00,0x8C,0x3F,0x0C,0x00,0x0A,0x00,
0x89,0x3F,0x08,0x00,0x08,0x00,0x88,0x3F,0x88,0x20,0x88,0x20,0x88,0x3F,0x88,0x20,
"电",0x80,0x00,0x80,0x00,0x80,0x00,0xFC,0x1F,0x84,0x10,0x84,0x10,0x84,0x10,0xFC,0x1F,
0x84,0x10,0x84,0x10,0x84,0x10,0xFC,0x1F,0x84,0x50,0x80,0x40,0x80,0x40,0x00,0x7F,
"子",0x00,0x00,0xFE,0x1F,0x00,0x08,0x00,0x04,0x00,0x02,0x80,0x01,0x80,0x00,0xFF,0x7F,
0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xA0,0x00,0x40,0x00,
};

数组名字里面的GB12和GB16代表了12号字体和16号字体的数组,文件中也有24号和32号

       图片

       图片存储在image.h文件中,图片文件中的内容比较简单,一个纯数组取模放进去的

const unsigned char YXDZ_logo[115200] = { /*0X10,0X10,0X00,0XF0,0X00,0XF0,0X01,0X1B,*/
0XFF,0XDF,0XFF,0XDF,0XFF,0XDF,0XFF,0XFF,0XFF,0XFF,0XFF,0XDF,0XFF,0XDF,0XFF,0XDF,
...................
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
};

  记得在数组前面加const就行

其他单片机驱动

       使用其他单片机编写的代码显示的效果与上面的STM32的相同,都是一张图片,空间不够

的单片机只是显示了一张小一点的图片。


51单片机

       51单片机程序由stm32的移植过去的,所以是一样的使用,唯一的区别是51单片机空间小

显示不了大图片,速度也比较慢。


arduino/ESP32

       arduino和ESP32的代码也是从原来STM32的移植过去的,不过因为编译器不同做了比较

多的修改,总体上做的函数接口和stm32的是一致的并没有做修改,由于数据兼容性不一样在

调用汉字显示之类的功能的时候需要对数据做类型转换,如下所示的中文汉字显示函数调用。

LCD_ShowChinese(0,0,(unsigned char*)"优信电子",RED,WHITE,32,0);

其他的参数没发现有哪里和STM32函数上的不同,由于是移植,并没有像C++一样做库进行使用(还是懒。。。),所以函数修改还是在文件中进行修改,而不是声明的方式去定义使用引脚,用户修改使用引脚的话只需要打开lcd_init.h文件找到下面的代码段,看到了自然知道怎么进行修改。

//-----------------LCD端口定义---------------- 
#define CS 5
#define RST 33
#define DC 27
#define SDA 23
#define SCL 18
#define BLK 22

没有采用硬件SPI,所以速度没有想象中的那么快,确实肉眼可见的慢了很多。


总结

后续我们将编写、移植或者收集测试好的一些屏幕代码分享相应的一些LCD、OLED等显示器件的驱动案例,也由衷的感谢中景园开源了如此优秀的LCD驱动库非常方便了用户的使用与移植,供大家共同学习进步,前行路上,优信与大家同在,欢迎一键三连,感谢各位大佬!








*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客