这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取逻辑分析仪】+STC32G12K128以16Bit并口模式驱动ST7789

共1条 1/1 1 跳转至

【换取逻辑分析仪】+STC32G12K128以16Bit并口模式驱动ST77892.4寸TFT显示屏

专家
2024-10-03 20:58:25   被打赏 50 分(兑奖)     打赏

TFT显示屏是常见的显示部件。在显示屏中使用的接口中,常见的有I2CSPI等串口模式,也有8位、16位等并口模式。串口模式因为占用端口少,对于端口紧张的单片机而言,是最好的选择。但串行端口方式驱动显示屏,对于图形、视频处理来说,处理速度上就不如并口了。

本次试验,是我第一次试用16位并口方式驱动ST7789驱动的显示屏。从驱动过程来说,无论串行模式,还是并行模式,其实只是以不同的方式向ST7789的各个寄存器发送指令和数据而已,因此从本质上讲,无论是初始化过程,还是显示数据的过程,只要完成关键数据的传送,处理结果都是一样的。因此在学习过程中,将重点放在如何传输字节数据上。

在贴上代码之前,先讲下接口配置情况。我用的显示屏,使用插接款FPC电缆,计有40个引脚,引脚的定义如下:

引脚编号

功能说明

1

X-

触摸屏信号线

2

Y-

触摸屏信号线

3

X+

触摸屏信号线

4

Y+

触摸屏信号线

5

GND

6

VDDI

I/O口电压(2.8V~3.3V)

7

VDD

模拟电路电源(2.8V~3.3V)

8

NC/FMARK

悬空

9

CSX

片选信号,低电平有效

10

DCX

指令/数据选择,L:指令,H:数据

11

WRX

LCD写控制端

12

RDX

LCD读控制端

13

SPI SDI

SPI输入

14

SPI_SDO

SPI输出

15

RESX

复位信号线

16

GND

17

DB0

数据线

18

DB1

数据线

19

DB2

数据线

20

DB3

数据线

21

DB4

数据线

22

DB5

数据线

23

DB6

数据线

24

DB7

数据线

25

DB8

数据线

26

DB9

数据线

27

DB10

数据线

28

DB11

数据线

29

DB12

数据线

30

DB13

数据线

31

DB14

数据线

32

DB15

数据线

33

LED-A

背光LED+

34

LED-K

背光LED-

35

LED-K

背光LED-

36

LED-K

背光LED-

37

GND

38

IM0

模式选择

39

IM1

模式选择

40

IM2

模式选择

为了测试方便,我是用STC32G12K128核心开发板来连接显示屏进行测试。开发板提供了8Port,每组都是完整的8Bit。我平时特别喜欢用51单片机进行测试的一个理由就是端口被设置为准双向口时,输入输入处理很方便,不需要特别处理。

 图片1.png

显示屏本身有一款转接板。转接板本身可以简化显示屏与开发板之间的连接。

 图片2.png

在经过了转接板后,上面接口中IM0IM1IM2已经被处理为16位的驱动方式。

IM2 IM1 IM0的设置

驱动模式

000

16位驱动,使用DB0 DB15传输指令、数据

001

8位驱动,使用DB8 DB15传输指令、数据。DB0DB7接地不用

101

3线SPI模式

110

4线SPI模式

 

上面接口模式中,受限于转接板的原因,没有进行16位以外模式的测试。准备以后使用其它转接板重新进行学习和测试。经过转接板以后,和显示屏的实际连接为以下方式。

RS



CS

RD



WR

DB0



RST

DB2



DB1

DB4



DB3

DB6



DB5

DB8



DB7

DB10



DB9

DB12



DB11

DB14



DB13

GND



DB15

VDD



BL      3.3V

GND



VDD     3.3V

+5V



GND

MOSI



MISO

NC



PEN

CLK



CS

底色为绿色的部分,是实际使用的接口。

//=======================================液晶屏接线===========================================//
//数据总线类型为16位并口
// DB0~DB7   =        P0.0~P0.7      低8位数据线
// DB8~DB15  =        P2.0~P2.7      高8位数据线
// CS        =        P3.5           片选信号
// RS        =        P4.0           数据/命令选择控制信号
// WR        =        P3.6           写控制信号
// RD        =        P3.7           读控制信号
// RST       =        P3.4           复位信号
// LED       =        P3.3           背光开关控制
 
#define  LCD_DataPortH P2     //高8位数据口
#define  LCD_DataPortL P0     //低8位数据口
 
sbit LCD_RS = P4^0;    //数据/命令切换
sbit LCD_WR = P3^6;    //写控制
sbit LCD_RD = P3^7;    //读控制
sbit LCD_CS = P3^5;    //片选 
sbit LCD_RESET = P3^4; //复位 
sbit LCD_LED = P3^3;   //背光控制
 
//LCD重要参数集
typedef struct {              
    u16 width;   //LCD 宽度
    u16 height;   //LCD 高度
    u16 id;      //LCD ID
    u8  dir;     //横屏还是竖屏控制:0,竖屏;1,横屏。 
    u16 wramcmd;  //开始写gram指令
    u16 setxcmd;  //设置x坐标指令
    u16  setycmd;  //设置y坐标指令  
}_lcd_dev;


使用杜邦线连接转接板和显示屏。

这里面需要特别说明的是,显示屏的BL端必须要接入电源(需要加限流电阻),否则看不到任何显示。

 

在处理程序上,关键的几个处理函数说明如下。

1、复位

使用硬件方式处理。

 

LCD_RESET=1;
delay_ms(10);
LCD_RESET=0;
delay_ms(20);
LCD_RESET=1;
delay_ms(120);


 

2、写寄存器函数

这是向ST7789发送指令/数据用的基本函数。

void LCD_WR_REG(u16 REG) { 
LCD_RS=0;
LCD_CS=0;
LCD_WR=0;
LCD_DataPortH=REG>>8;
LCD_DataPortL=REG;
LCD_WR=1;
LCD_CS=1;  
}


 

3写数据函数

void LCD_WR_DATA(u16 DATA) {
LCD_RS=1;
LCD_CS=0;
LCD_WR=0;
LCD_DataPortH=DATA>>8;
LCD_DataPortL=DATA;
LCD_WR=1;
LCD_CS=1; 
}


 

4写寄存器

//LCD_Reg:寄存器编号
//LCD_RegValue:要写入的值
void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue) { 
LCD_WR_REG(LCD_Reg);  
LCD_WriteRAM(LCD_RegValue);        
}


 

5GRAM

void LCD_WriteRAM_Prepare(void) {
LCD_WR_REG(lcddev.wramcmd);
}


 

6LCDGRAM

//RGB_Code:颜色值
void LCD_WriteRAM(u16 RGB_Code) {
LCD_RS=1;
LCD_CS=0;
LCD_DataPortH=RGB_Code>>8;
LCD_DataPortL=RGB_Code;
LCD_WR=0;
LCD_WR=1;
LCD_CS=1;
}


 

 

7延时i

void opt_delay(u8 i) {
while(i--);
}


 

8LCD开启显示

void LCD_DisplayOn(void) {
LCD_WR_REG(0X29); //开启显示
}


 

9LCD关闭显示

void LCD_DisplayOff(void) {
LCD_WR_REG(0X28); //关闭显示
}


 

10设置光标位置

//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(u16 Xpos, u16 Ypos) {
LCD_WR_REG(lcddev.setxcmd); 
LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);     
LCD_WR_REG(lcddev.setycmd); 
LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);    
}

  

   

11画点

//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x,u16 y) {
LCD_SetCursor(x,y);  //设置光标位置 
LCD_WriteRAM_Prepare(); //开始写入GRAM
LCD_WriteRAM(POINT_COLOR); 
}


 

12快速画点

//x,y:坐标
//color:颜色
void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color) {
    //设置光标位置
    LCD_SetCursor(x,y);   
    //写入颜色
    LCD_WriteReg(lcddev.wramcmd,color);
}


 

13选择方向

//dir:方向选择  0-0度旋转,1-180度旋转,2-270度旋转,3-90度旋转
void LCD_Display_Dir(u8 dir) {
    //竖屏
if(dir==0||dir==1) {
        lcddev.dir=0; //竖屏
        lcddev.width=240;
        lcddev.height=320;
 
        lcddev.wramcmd=0X2C;
        lcddev.setxcmd=0X2A;
        lcddev.setycmd=0X2B;
    
if(dir==0) {
            //0:0度旋转
LCD_WR_REG(0x36); 
LCD_WR_DATA((0<<3)|(0<<7)|(0<<6)|(0<<5));
} else {
            //1:180度旋转
LCD_WR_REG(0x36); 
LCD_WR_DATA((0<<3)|(1<<7)|(1<<6)|(0<<5));  
}
} else if(dir==2 || dir==3) {
        lcddev.dir=1; //横屏
        lcddev.width=320;
        lcddev.height=240;
 
        lcddev.wramcmd=0X2C;
        lcddev.setxcmd=0X2A;
        lcddev.setycmd=0X2B; 
 
        //2:270度旋转
        if(dir==2)  {
            LCD_WR_REG(0x36); 
            LCD_WR_DATA((0<<3)|(1<<7)|(0<<6)|(1<<5));
 
        } else  {
            //3:90度旋转
            LCD_WR_REG(0x36); 
            LCD_WR_DATA((0<<3)|(0<<7)|(1<<6)|(1<<5));
        }  
}
 
    //设置显示区域 
    LCD_WR_REG(lcddev.setxcmd); 
    LCD_WR_DATA(0);LCD_WR_DATA(0);
    LCD_WR_DATA((lcddev.width-1)>>8);LCD_WR_DATA((lcddev.width-1)&0XFF);
    LCD_WR_REG(lcddev.setycmd); 
    LCD_WR_DATA(0);LCD_WR_DATA(0);
    LCD_WR_DATA((lcddev.height-1)>>8);LCD_WR_DATA((lcddev.height-1)&0XFF);  
}


 

14设置窗口,并自动设置画点坐标到窗口左上角(sx,sy).

//sx,sy:窗口起始坐标(左上角)
//width,height:窗口宽度和高度,必须大于0!!
//窗体大小:width*height. 
void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height) {
u16 twidth,theight;
twidth=sx+width-1;
theight=sy+height-1;
 
    LCD_WR_REG(lcddev.setxcmd); 
    LCD_WR_DATA(sx>>8); 
    LCD_WR_DATA(sx&0XFF);  
    LCD_WR_DATA(twidth>>8); 
    LCD_WR_DATA(twidth&0XFF);  
    LCD_WR_REG(lcddev.setycmd); 
    LCD_WR_DATA(sy>>8); 
    LCD_WR_DATA(sy&0XFF); 
    LCD_WR_DATA(theight>>8); 
    LCD_WR_DATA(theight&0XFF); 
}


 

15清屏函数

//color:要清屏的填充色
void LCD_Clear(u16 color) {
u32 index=0;      
u32 totalpoint;
totalpoint=lcddev.width;
totalpoint*=lcddev.height;    //得到总点数 
LCD_SetCursor(0,0);                 //设置光标位置 
LCD_WriteRAM_Prepare();       //开始写入GRAM      
for(index=0;index<totalpoint;index++)
        LCD_WriteRAM(color);
}


 

16在指定区域内填充指定颜色

//区域大小:(xend-xsta+1)*(yend-ysta+1)
//xsta
//color:要填充的颜色
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color) {          
u16 i,j;
u16 xlen=0;
    xlen=ex-sx+1;  
    for(i=sy;i<=ey;i++) {
        LCD_SetCursor(sx,i);          //设置光标位置 
        LCD_WriteRAM_Prepare();        //开始写入GRAM   
        for(j=0;j<xlen;j++)LCD_WriteRAM(color); //设置光标位置      
    }
}

 

 

测试效果如下:

图片3.png 

作为对比,看看SPI模式下的写指令/数据函数:

1、写一个字节

void spi_write_byte(u8 d)  {
  u8 val=0x80;
  while(val) {
    if(d&val) {
      LCD_SDI = 1;
    } else {
      LCD_SDI = 0;
    }
    LCD_CLK = 0;
    LCD_CLK = 1;
    val>>=1;
  }
}


2、写寄存器

void LCD_WR_REG(u8 Reg) {
    LCD_RS=0;
    LCD_CS=0;
    spi_write_byte(Reg);
    LCD_CS=1;
}


3、写数据

void LCD_WR_DATA(u8 Data) {
    LCD_RS=1;
    LCD_CS=0;
    spi_write_byte(Data);
    LCD_CS=1;
}


4、写16Bit数据

void LCD_WR_DATA_16Bit(u16 Data) {
    LCD_CS=0;
    LCD_RS=1;
    spi_write_byte(Data>>8);
    spi_write_byte(Data);
    LCD_CS=1;
}


5、向寄存器写数据

void LCD_WriteReg(u8 LCD_Reg, u8 LCD_RegValue) {
    LCD_WR_REG(LCD_Reg);
    LCD_WR_DATA(LCD_RegValue);
}


6、写GRAM

void LCD_WriteRAM_Prepare(void) {
     LCD_WR_REG(lcddev.wramcmd);    
}


7、清除屏幕

void LCD_Clear(u16 Color) {
    u16 i,j;
    LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);  
    LCD_CS=0;
    LCD_RS=1;
    for(i=0;i<lcddev.width;i++) {
        for (j=0;j<lcddev.height;j++) {
            spi_write_byte(Color>>8);
            spi_write_byte(Color);
        }
    }
    LCD_CS=1;
}


8、画点

void LCD_DrawPoint(u16 x,u16 y) {
    LCD_SetWindows(x,y,x,y);//设置光标位置 
    LCD_WR_DATA_16Bit(POINT_COLOR);       
}


9、复位

void LCD_Reset(void) {
  LCD_RESET=0;
  delay_ms(20);
  LCD_RESET=1;
  delay_ms(20);
}


10、设置窗口

void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd) {  
  LCD_WR_REG(lcddev.setxcmd);  
  LCD_WR_DATA((xStar+lcddev.xoffset)>>8);
  LCD_WR_DATA(xStar+lcddev.xoffset);    
  LCD_WR_DATA((xEnd+lcddev.xoffset)>>8);
  LCD_WR_DATA(xEnd+lcddev.xoffset);
 
  LCD_WR_REG(lcddev.setycmd);  
  LCD_WR_DATA((yStar+lcddev.yoffset)>>8);
  LCD_WR_DATA(yStar+lcddev.yoffset);    
  LCD_WR_DATA((yEnd+lcddev.yoffset)>>8);
  LCD_WR_DATA(yEnd+lcddev.yoffset);
 
  LCD_WriteRAM_Prepare();  //开始写入GRAM        
}


 

11、初始化

void LCD_Init(void) {
  LCD_Reset(); //初始化之前复位
 
//************* ST7789初始化**********//  
  LCD_WR_REG(0x36); 
  LCD_WR_DATA(0x00);
 
  LCD_WR_REG(0x3A); 
  LCD_WR_DATA(0x05);
 
  LCD_WR_REG(0xB2);
  LCD_WR_DATA(0x0C);
  LCD_WR_DATA(0x0C);
  LCD_WR_DATA(0x00);
  LCD_WR_DATA(0x33);
  LCD_WR_DATA(0x33);
 
  LCD_WR_REG(0xB7); 
  LCD_WR_DATA(0x35);  
 
  LCD_WR_REG(0xBB);
  LCD_WR_DATA(0x1A);//
 
  LCD_WR_REG(0xC0);
  LCD_WR_DATA(0x2C);
 
  LCD_WR_REG(0xC2);
  LCD_WR_DATA(0x01);
 
  LCD_WR_REG(0xC3);
  LCD_WR_DATA(0x0B); //  
 
  LCD_WR_REG(0xC4);
  LCD_WR_DATA(0x20);  
 
  LCD_WR_REG(0xC6); 
  LCD_WR_DATA(0x0F);    
 
  LCD_WR_REG(0xD0); 
  LCD_WR_DATA(0xA4);
  LCD_WR_DATA(0xA1);
 
  LCD_WR_REG(0xE0);     
  LCD_WR_DATA(0x00);   
  LCD_WR_DATA(0x03);   
  LCD_WR_DATA(0x07);   
  LCD_WR_DATA(0x08);   
  LCD_WR_DATA(0x07);   
  LCD_WR_DATA(0x15);   
  LCD_WR_DATA(0x2A);   
  LCD_WR_DATA(0x44);   
  LCD_WR_DATA(0x42);   
  LCD_WR_DATA(0x0A);   
  LCD_WR_DATA(0x17);   
  LCD_WR_DATA(0x18);   
  LCD_WR_DATA(0x25);   
  LCD_WR_DATA(0x27);   
 
  LCD_WR_REG(0xE1);     
  LCD_WR_DATA(0x00);   
  LCD_WR_DATA(0x03);   
  LCD_WR_DATA(0x08);   
  LCD_WR_DATA(0x07);   
  LCD_WR_DATA(0x07);   
  LCD_WR_DATA(0x23);   
  LCD_WR_DATA(0x2A);   
  LCD_WR_DATA(0x43);   
  LCD_WR_DATA(0x42);   
  LCD_WR_DATA(0x09);   
  LCD_WR_DATA(0x18);   
  LCD_WR_DATA(0x17);   
  LCD_WR_DATA(0x25);   
  LCD_WR_DATA(0x27); 
 
  LCD_WR_REG(0x21); 
 
  LCD_WR_REG(0x11); 
  delay_ms(120); 
 
  LCD_WR_REG(0x29);     
 
  //设置LCD属性参数
  LCD_direction(USE_HORIZONTAL);//设置LCD显示方向 
  LCD_BL=1;//点亮背光   
}


可以看到,只要处理好基本的数据传输用函数,其它处理完全一样。

显示屏处理部分的代码:LCD.zip



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]