STM32驱动TFT屏
0赞
现在开始找工作了,要将以前做过学习的东西要回顾一下,还记着以前用STM32加一个TFT屏,实现了2048游戏。通过按键控制游戏运行,界面通过TFT显示。
要通过TFT显示,就要先实现TFT驱动。TFT本身的驱动是比较麻烦的,要控制各种信号,但是有了TFT驱动芯片,那驱动TFT就相当简单了,只要你会驱动1602,你就会驱动TFT屏了。
我使用的STM32开发板用的是ILI9320的驱动芯片。接口原理图如下:
信号说明
1、 LCDCS: 片选信号,低电平有效
2、 LCDRS: 命令/数据标志,0命令,1数据
3、 LCDWR:写数据信号
4、 LCDRD: 读数据信号
5、 RESET: 复位信号
6、 DB[15:0]: 16位真彩色数据
7、 SP2CLK: SPI协议clk信号
8、 SP2MOSI: SPI协议mosi信号
9、 SP2MISO: SPI协议miso信号
10、TCS: SPI协议片选信号
上面这些信号,是不是和LCD1602是相似了。只是多了一个SPI接口,表示可以通过SPI和驱动芯片数据交互的。
下面是时序图:
1、对于写入
在WR的上升沿,数据/命令被写入
2、对于读取
在RD的上升沿,数据被读取
这时序图是不是也比较熟悉了,和LCD1602也差不多。只是读写信号分开,并且是在上升沿触发。
有了这些基础了,写程序,那就简单了。先实现最底层的三个函数,一个写命令,一个写数据,一个读数据。
1、 写数据,写数据是比较常用的,所以使用宏定义,加快写的速度
//写16位数据函数 #define LCD_WR_DATA(data){\ LCD_RS_SET;\ LCD_CS_CLR;\ DATAOUT(data);\ LCD_WR_CLR;\ LCD_WR_SET;\ LCD_CS_SET;\ }
2、 写命令,这个就直接用函数是函数实现就可以了
//写命令 void LCD_WR_REG(u16 data) { LCD_RS_CLR; LCD_CS_CLR; DATAOUT(data); LCD_WR_CLR; LCD_WR_SET; LCD_CS_SET; }
3、 读数据,首先写命令,然后将数据线设置为输入,在读取数据,读取完毕后,在将数据线设置为输出
//读寄存器 u16 LCD_ReadReg(u8 LCD_Reg) { u16 t; LCD_WR_REG(LCD_Reg); //写入要读的寄存器号 GPIOE->CRL=0X88888888; //PE0-7 上拉输入 GPIOE->CRH=0X88888888; //PE8-15 上拉输入 GPIOE->ODR=0XFFFF; //全部输出高 LCD_RS_SET; LCD_CS_CLR; //读取数据 LCD_RD_CLR; delay_us(5);//FOR 8989,延时5us LCD_RD_SET; t=DATAIN; LCD_CS_SET; GPIOE->CRL=0X33333333; //PE0-7 上拉输出 GPIOE->CRH=0X33333333; //PE8-15 上拉输出 GPIOE->ODR=0XFFFF; //全部输出高 return t; }
以上就是3个底层函数了。其中的SET,CLR都是使用的宏。有了这三个代码,下面就可以封装一个函数,向寄存器写数据。从寄存器读数据,上面已经是实现了。
//写寄存器写数据
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{
LCD_WR_REG(LCD_Reg);
LCD_WR_DATA(LCD_RegValue);
}
以上程序,都没有加延时,那是因为STM32是运行比较慢的,运行起来完全符合芯片规定的时序,所以就不用加延时,但是如果用高速的设备的话,就要考虑芯片的时序了。以下是芯片的时序:
有了向寄存器写数据和从寄存器读取数据,然后就可以封装其他的函数了。比如显示图片,显示数字,画线,画矩形框等。无非就是调用这两个函数,再看数据手册,要往哪些寄存器写数据,往哪些寄存器读数据即可。
我用的TFT是用的16位真彩色,R(5位)G(6位)B(5位)。我们使用的pc机用的是24位真彩色,所以如果我们想要把PC上的某一种颜色给显示到TFT上的话,就要将24位真彩色给转换成16位真彩色。
转换的原则也很简单,在24位真彩色中,RGB都是8位。将R,B低3位舍弃,G低两位舍弃,然后在按照RGB的顺序组合即可。
以下代码可以实现这个功能:
/*********************************************
RGB颜色混合
入口参数:R(红色分量)0-255,G(绿色分量)0-255,B(蓝色分量)0-255
出口参数: 按R5-G6-B5格式混合后的16位颜色码。
说明:将电脑上常见的R8-G8-B8格式转换成16位单片机常用的R5-G6-B5格式。
**********************************************/
u16 RGB(u8 R,u8 G,u8 B)
{
return((u16)(R&0XF8)<<8|(u16)(G&0XFC)<<3|(u16)(B&0XF8)>>3);
}
因为后面实现2048,会在TFT上显示图片,所以,要实现显示图片的函数。以下就是显示图片的函数:
/**********************************************************
显示图片(图标)
入口参数:(x,y)是开始点的坐标,length是图片长度,high是图片高度。//pic 图片数组的指针
出口参数: 无
说明:用指定位置上显示事先定义的图片。
要显示的图片事先定义在bmp pic[]数组中,
如果想修改图片大小、内容,请修改bmp pic[]数组,
建议用Image2Lcd软件将你要显示的图象自动转换为数组数据。
************************************************************/
void GUI_DisPicture(uchar x, uint y, uchar length, uint high ,const uchar *pic)
{
u16 temp=0,tmp=0,num=0;
u32 address=0;
LCD_setwindow(x,y,x+length-1,y+high-1);
num=length*high*2;
do
{
temp=pic[tmp]|( pic[tmp+1]<<8);
LCD_WR_DATA(temp);//逐点显示
tmp+=2;
}while(tmp<num);
}
参数有5个:
x:显示图片的左上角的x坐标
y:显示图片的左上角的y坐标
length: 图片的长度(x方向)
high: 图片的高度(y方向)
pic: 图片数据的一维数组
首先是使用LCD_setwindow函数,因为是要在一个矩形区域里面显示图片,也就意味着是在这个区域内写数据,如果每次都写一行数据,然后写下一行坐标,再写数据的话,效率就比较低,ILI9320提供了4个寄存器,只要往这4个寄存器里面写入矩形区域的坐标的话,就可以一直写数据,数据会依次的填充矩形区域,就实现在矩形区域显示图片了。
然后就是不断从图片的数组中把数据取出来,因为数据是以8位存储的,所以要读取两个数据再拼接下,再讲数据写入到TFT中。直到图片的数据写完。
所以TFT驱动,核心的还是底层的三个函数,只要底层的三个函数实现了,实现其他的函数也就很简单了。