关于8位单片机驱动液晶屏的应用总结

对于人机界面中的液晶屏的使用大家都不陌生。从简单的电子表到手机、平板电脑,显示器、液晶电视都能看到他们的身影。早其我们常用的液晶屏,比如段码LCD,1602,12232,12864,等非黑即透明,随着技术的不断进步,现在在手机和平板电脑等电子设备上用的主要是TFT液晶屏,本人一直也是对液晶的显示十分好奇,按捺不住,就淘了几个小尺寸TFT液晶屏(呵呵,囊中羞涩)捣鼓捣鼓。发现这东西其实还是很好玩的,除了涉及的知识面比较广,需要阅读不少手册及资料外,只要你要一定的单片机开发的基础,操作起来并不复杂,主要难点还是数据处理和字库的制作上。下面就说道说道这个TFT液晶。

什么是TFT?

TFT液晶屏也就是thin film transistor 即薄膜晶体管显示屏,它的每一个像素点都是由集成在其后的薄膜晶体管来驱动的。

常用TFT模块尺寸:

对角线的尺寸:1.44、1.6、1.8、2.0、2.2、2.4、2.6、2.8、3.0、3.2、3.4、3.6、4.0、4.3、5.7、8.4、10.4、15、17、19、21英寸等。

本人使用过的,1.44、1.8、2.2

屏幕高宽比:4:3或16:9

分辨率:指水平像素和垂直像素的数量。

点距:相邻两个像素之间的距离。

刷新率:每秒更新的画面数。

接口形式:并行接口和串行接口

颜色的表示

对于黑白或单色像素的信息可以用1个位来表示和存储,对于一个彩色像素的信息可以用1个多位二进制数来表示和存储。

用来表示彩色像素的二进制数的尾数,称之为颜色的颜色深度或颜色质量

什么是真彩和伪彩

颜色深度在16为以上的称为真彩色,颜色深度在16位以下的称为伪彩色。

比如采用1个16位二进制数来表示一个彩色点:

  红色               绿色               蓝色

5位               6位               5位

R4 R3 R2 R1 R0 G5 G4G3   G2 G1G0B4B3B2B1B0

 高8位                      低8位

这就是所谓的5-6-5格式。

字符或图像到底是怎样显示出来的?

首先可将光看作是一种电磁波,以电场和磁场相互垂直而交互震荡的方式向前传播。电场在某个方向上震荡,震荡的幅度越大,光所具有的能量越大。某个方向上震荡的光可以分解成两个垂直方向上的分量。

偏光片:作用是让某个方向上震荡的光通过,而把垂直方向上震荡的光挡住。

偏光片组

第一偏光片仅让在某个方向上震荡的光通过,而第二偏光片再把所通过的光挡住,即可阻绝光的行进,达到关闭光的效果。

液晶具有双折射系数的特性,并且在不同的电场下,会有不同的排列方式,因此当光通过液晶时,会受其影响而改变或保持其震荡的方向,当液晶不改变光的震荡方向时,光无法通过第二个偏光板而被关闭,而当液晶将光的震荡方向改变时,光可以在分解成两个分量,虽然一个分量无法通过第二个偏光片,但是仍还有一个分量可以通过第二个偏光片,而成为打开状态。英雌,可用施加的电场来改变液晶的排列方式,来实现光的开关的来实现显示功能。具体液晶是个什么东西,有那些种类,大家想了解就百度吧,这里就不再细谈了。

电场是如何改变的?

首先了解一下TFT(thin-film transister )薄膜电晶体

主要结构是一个非晶矽半导体薄膜,TFT 就有一个门极gate;一个源极source;和一个漏极drain.看看这几电极的名称是不是很熟悉,对了场效应管也是这样命名的,两者类似,但又有不同之处。但是都可以理解成一个受控的开关。

这些开关以矩阵的方式进行排列。



彩色的TFT将水平方向的每个像素在次分成3个RGB像素,各个次像素的可以独立的改变,故也分别对应一个TFT。这样3个次像素组成一个像素。
 
 
呵呵,看了上面的图,是不是就想到了单片机矩阵按键的动态扫描程序。呵呵不错,逆向思维,矩阵键盘的扫描是读状态,这个是写状态。具体过程如下。
在水平方向上的同一条扫描线上,所有TFT的门极都连在一起,所以施加的电压是一样的,若在某一条扫面线上施加足够大的正电压,则这条扫描线上所有的TFT 都会被打开。此时该扫描线上的像素电极,会与垂直方向的资料线(漏极)连接,经由对应的资料线送入相应的视信号,将像素电极充电到适当的电压。接着施加足够大的负电压,关闭TFT,直到下次再重新写入信号。其间使得电荷保存在液晶电容上;在按照这种方式扫描下一行。再送入下一行的视信号,如此依次将整个画面的视信号写入,在重新自第一行开始写入,(一般重复的频率为60-70Hz)。
 
对每个像素中的液晶光阀而言,液晶上所施加的电压和光的穿透度具有一定的关系,因此,只要依据所要显示的画面,控制施加在液晶上的电压,即可将各个像素设定在适当的光穿透度,配合均匀的背光源就显示出想要的画面了。这就是主动式矩阵型液晶的显示原理。
 
就几款液晶屏的参数做一下总结说明
 
1、1.44寸液晶屏(以下数据来自液晶屏数据手册)
 
LCD type :     1.45”active matrix TFT-LCD
Rsolution:      128(W)X128(H) Pixels
Display mode :   transmissive type
Display color:    262Kcolor
driverIC:         ILI9163C
Luminance:       120cd/m2
Contrast ratio:     400:1
Viewing direction:  6o’clock 
Interface :         4 wire SPI interface
Back light:         1 white  LED ,18ma ,3,15V
 
2、引脚说明:
 
       VCC:    电源  +3,3V
       GND:      电源地
       CS:      片选  (低电平有效)
       RST:     复位   (低电平有效)
       AO:      寄存器选择信号(低电平:选择命令寄存器;高电平:选择数据寄存器)
       SDA:    data input in SPI mode  在SPI模式下的数据输入
       SCL:    在SPI模式下的同步时钟输入
       LED:    背光LED电源,
 
呵呵,从引脚定义上就可以看出是不是在SPI模式下只需要4条IO口线就可以和MCU构成一个显示系统了。(其实还用一种模式只要3条IO口线就可以)。
 
再看1.8寸TFT的相关数据
 
显示点阵数:     128W  x   160H     dots
模块外形尺寸:   34W  x  45.83H  x  2.65T    mm
可视区域:       28.03W x 35.04H   mm
像素尺寸:       0.06W   *   3   *  0.18H    mm
像素中心距:     0.18W   *  0.18H    mm
占空比:         1/400
视角:            6点钟
LCD模式:       260k color
IC:              ST7735B
主要引脚定义:同1.44’
再看2.2英寸的屏
Size            2.2inch
Resolution:      240*320
Interface        4-wire SPI
Color depth      262k/65k
Technology      a-Si
Pixel pitch(mm):  0.141*0.141
Viewing direction: 6o’clock
LED numbers     4 LEDs
Driver IC        ILI9340C
主要引脚定义同1.44’英寸。
 
从上面不同尺寸液晶屏的引脚的定义看出,1.44英寸和1.8英寸及2.2英寸的TFT液晶屏,在和MCU构成显示系统时操作方式是一样的(因为都是4线 SPI),尽管他们使用的驱动IC型号不同。但是只要你翻看IC的数据手册就会发现,他们的寄存器的定义基本是一样的,操作原理相同。
 
如何构成一个显示系统:
 
电源+MCU+TFT液晶屏
 
呵呵,是不是觉得少了点什么?驱动IC那里去了?
其实驱动IC我们是看不到的,它被集成在了液晶屏中,我们只要知道它的寄存器的定义,利用液晶屏的端口会进行读写即可。
电源:3.3V的直流电源,呵呵,这个不用细说,小功率的可以利用ASM1117-3;大功率的可以利用LM2596S-3.3(最高3A的输出)来构成一个电源。
 
MCU:主要是3个要求。工作电压,3.3V   够大,够快。
 
够大才能存的下程序和数据,够快才会图像流畅。
 
本人手头只有15L2K08S2这个单片机,8K程序存储区,2K的SRAM,最高时钟33.1776MHz,最高输出8MHz的外部时钟,比起60S2的60KB的FLASH,小了不少,但是对于普通的不太复杂的应用已经足够了,主要是搞通应用的原理。
 
液晶屏:
 
以上列举的液晶屏都是串口屏,所以屏的引出脚较少,除此之外还有引出管脚较多的并口屏,当然串口屏的数据是一位一位的送出的,速度相对是比较慢的。
 
在操作上,串口和并口原理差不多。这里就先介绍串口屏的使用。
 
好了,你有了上面的3大件下面在准备点辅料。
 
1、数据线,USB转串口数据线,用于烧写MCU
2、字符LCD点阵提取软件:百度一下吧,zimo221.exe
3、图片点阵数据提取软件:同样百度,Image2Lcd.exe
4、编程软件:KEIL
5、单片机烧写软件:这个不多说了,看你用的芯片而定。
 
好的,齐活了,准备开工。
 
用导线将单片机的电源接口和LCD的电源及LED端口同3.3V电源的输出连接起来。供电的问题解决了。
 
用导线将自己选择的单片机的端口和LCD的REST、CS、SCL、AO、SDA   一一对应的连接起来。数据输出的问题解决。
 
硬件问题解决,开始代码的编写
 
TFT初始化函数
 
也就是对液晶屏进行基本的配置。
这个基本直接套用就行。(除了个别地方需要修改,后面会说)
TFT驱动芯片的手册还是有必要看看的,最好是看英文原版内容比较详细。
也没有必要全部看,但是下面初始化代码中涉及到的指令及4wireSPI的时序图,还是很有必要了解的,不然显示的界面出了问题,就会感觉无从下手解决。
写数据和写命令
很明显要想让液晶屏显示字符或图像,必须要把要显示的内容转换成数据写到液晶屏的控制器,想写内容数据还要对液晶屏的控制寄存器进行设置,也就是写命令数据。只有一条SDA串口数据线,怎么区分是内容数据还是命令数据呢,那就要靠 AO(RS):      寄存器选择信号(低电平:选择命令寄存器;高电平:选择数据寄存器)。 
 
写命令
void  write_command(uchar c)
{
cs=0; //片选有效
rs=0; //选择命令寄存器
bitdata=c;//送数据
sda=bit7;scl=0;scl=1;
sda=bit6;scl=0;scl=1;
sda=bit5;scl=0;scl=1;
sda=bit4;scl=0;scl=1;
sda=bit3;scl=0;scl=1;
sda=bit2;scl=0;scl=1;
sda=bit1;scl=0;scl=1;
sda=bit0;scl=0;scl=1;
cs=1;//片选无效      
}
写数据
void  write_data(uchar d)
{
cs=0;
rs=1;
bitdata=d;
sda=bit7;scl=0;scl=1;
sda=bit6;scl=0;scl=1;
sda=bit5;scl=0;scl=1;
sda=bit4;scl=0;scl=1;
sda=bit3;scl=0;scl=1;
sda=bit2;scl=0;scl=1;
sda=bit1;scl=0;scl=1;
sda=bit0;scl=0;scl=1;
cs=1;
}
初始化
/*****************TFT初始化函数***************/
 void lcd_initial()
{
 
   reset=0;
   delay(100);
   reset=1;
   delay(100);
 
//------------------------------------------------------------------//  
//-------------------Software Reset-------------------------------//
  
  write_command(0x2A);     //列地址设置
        write_data(0x00);    //列起始地址低8位
        write_data(0x00);    //列起始地址高8位
        write_data(0x00);    //列终止地址高8位
write_data(0x9F);     //列终止地址低8位
//上面的列终止地址为什么设置成0x9f,0x9f=十进制的159,1.8寸的屏的分辨率是128*160.
//也就是说有0-159共160列。 下面的同样的道理,只不过是说明行的起始和终止地址。  
  write_command(0x2B); //行地址设置
        write_data(0x00);
        write_data(0x00);
        write_data(0x00);
write_data(0x7F); 
 
 
  write_command(0xCB); //功耗控制A 
        write_data(0x39); 
        write_data(0x2C); 
        write_data(0x00); 
        write_data(0x34); 
        write_data(0x02); 
 
        write_command(0xCF);//功耗控制B  
        write_data(0x00); 
        write_data(0XC1); 
        write_data(0X30); 
 
        write_command(0xE8);//驱动时序控制A  
        write_data(0x85); 
        write_data(0x00); 
        write_data(0x78); 
 
        write_command(0xEA);//驱动时序控制B  
        write_data(0x00); 
        write_data(0x00); 
 
        write_command(0xED);//电源序列控制  
        write_data(0x64); 
        write_data(0x03); 
        write_data(0X12); 
        write_data(0X81); 
 
        write_command(0xF7); //泵比控制 
        write_data(0x20); 
  
        write_command(0xC0);    //Power control 功耗控制1
        write_data(0x23);   //VRH[5:0] `
 
        write_command(0xC1);    //Power control 功耗控制2
        write_data(0x10);   //SAP[2:0];BT[3:0] 
 
        write_command(0xC5);    //VCM control 
        write_data(0x3e); //对比度调节
        write_data(0x28); 
 
        write_command(0xC7);    //VCM control2 
        write_data(0x86);  //--
 
        write_command(0x36);  // Memory Access Control  存储器访问控制
        write_data(0x68); //C8   //48 68竖屏//28 E8 横屏
                           //cc同c8
 
        write_command(0x3A); //像素格式设置   
        write_data(0x55); 
 
        write_command(0xB1);//帧速率控制    
        write_data(0x00);  
        write_data(0x18); 
 
        write_command(0xB6);    // Display Function Control 
        write_data(0x08); 
        write_data(0x82);
        write_data(0x27);  
 
        write_command(0xF2);    // 3Gamma Function Disable 
        write_data(0x00); 
 
        write_command(0x26);    //Gamma curve selected 
        write_data(0x01); //共4条曲线供选择,分别是1248;这里选择1,
 
        write_command(0xE0);    //Set Gamma 
        write_data(0x0F); 
        write_data(0x31); 
        write_data(0x2B); 
        write_data(0x0C); 
        write_data(0x0E); 
        write_data(0x08); 
        write_data(0x4E); 
        write_data(0xF1); 
        write_data(0x37); 
        write_data(0x07); 
        write_data(0x10); 
        write_data(0x03); 
        write_data(0x0E); 
        write_data(0x09); 
        write_data(0x00); 
 
        write_command(0XE1);    //Set Gamma 
        write_data(0x00); 
        write_data(0x0E); 
        write_data(0x14); 
        write_data(0x03); 
        write_data(0x11); 
        write_data(0x07); 
        write_data(0x31); 
        write_data(0xC1); 
        write_data(0x48); 
        write_data(0x08); 
        write_data(0x0F); 
        write_data(0x0C); 
        write_data(0x31); 
        write_data(0x36); 
        write_data(0x0F); 
 
        write_command(0x11);    //Exit Sleep 
        delay(120); 
        write_command(0x29);    //Display on 
        write_command(0x2c); 
}
 
写入数据时要先确定,图像的起始坐标和终止坐标,可以用如下的代码实现
static void LCD_SetPos(unsigned int x0,unsigned int x1,unsigned int y0,unsigned int y1)//设置位置
{
   write_command(0x2A);   //列地址设置
   write_data(x0>>8);       //列起始地址高8位
   write_data(x0);          //列起始地址低8位
   write_data(x1>>8);       //列终止地址高8位
   write_data(x1);          //列终止地址低8位
  
   write_command(0x2B);//页地址设置
   write_data(y0>>8);
   write_data(y0);
   write_data(y1>>8);
   write_data(y1);
write_command(0x2c);//写存储器 
}
写命令时,先将命令的地址写入,然后在将设定的数据写入寄存器。如
write_command(0x2A); //列地址设置
        write_data(0x00);
        write_data(0x00);
        write_data(0x00);
write_data(0x9F); 
 
至于这些写入的数据的意义及数值大小,请查阅液晶屏对应的液晶屏的数据手册。
 
了解一下颜色代码:
 
几种常用的颜色的代码
 
#define White          0xFFFF    //白
#define Black          0x0000     //黑
#define Red           0x001F     //红
#define Blue            0xF800   //蓝
#define Magenta        0xF81F   //紫
#define Green          0x07E0    //绿
#define Cyan           0x07FF    //青   
#define Yellow         0xFFE0    //黄
 
好了说了这么多,一个字晕。好吧,来点实际的简单的,咱先啥字符也不显示,只是让液晶屏显示不同的颜色。
 
刷整个屏幕的颜色,可以用如下代码实现
/*********显示色彩******************/
void dsp_single_colour(DH,DL)//前景颜色,背景颜色
{
unsigned int i,j;
for (i=0;i<128;i++)
 for (j=0;j<160;j++)
{
 write_data(DH>>8);
 write_data(DH);
 write_data(DL>>8);
 write_data(DL); 
 }
}
延时函数
/******延时函数************************/
void delay(uint time)
{
 uint i,j;
  for(i=0;i<time;i++)
   for(j=0;j<500;j++);
}
好了,将上面的函数组合起来,准备刷屏。
main()
{
 lcd_initial();//TFT初始化
 
 while(1)
 {
  LCD_SetPos(0,159,0,10);//设置位置
  dsp_single_colour(Blue,Black); //
  delay(2000) ;
    LCD_SetPos(0,159,10,20);//设置位置
  dsp_single_colour(Blue,Blue); //
  delay(2000) ;
    LCD_SetPos(0,159,20,30);//设置位置
  dsp_single_colour(Green,White); //
  delay(2000) ;
      LCD_SetPos(0,159,30,40);//设置位置
  dsp_single_colour(Green,Green); //
  delay(2000) ;
    LCD_SetPos(0,159,40,50);//设置位置
  dsp_single_colour(Yellow,White); //
  delay(2000) ;
      LCD_SetPos(0,159,50,60);//设置位置
  dsp_single_colour(Yellow,Yellow); //
  delay(2000) ;
    LCD_SetPos(0,159,60,70);//设置位置
  dsp_single_colour(Black,White); //
  delay(2000) ;
      LCD_SetPos(0,159,70,80);//设置位置
  dsp_single_colour(Black,Black); //
  delay(2000) ;
    LCD_SetPos(0,159,80,90);//设置位置
  dsp_single_colour(Red,White); //
  delay(2000) ;
      LCD_SetPos(0,159,90,100);//设置位置
  dsp_single_colour(Red,Red); //
  delay(2000) ;
    LCD_SetPos(0,159,100,110);//设置位置
  dsp_single_colour(Magenta ,Black); //
  delay(2000) ;
      LCD_SetPos(0,159,110,120);//设置位置
  dsp_single_colour(Magenta ,Magenta ); //
     delay(2000) ;
   LCD_SetPos(0,159,0,120);//设置位置
  dsp_single_colour(White,White ); //只刷到第121行留下了7行
     delay(2000) ;
 }
}
 
最终结果,滚动刷屏
 
 
感觉有点不对劲,不错,最下面故意留了7行没写颜色数据。可以看到如果不写任何数据,屏的状态就是花屏。
 
通过上面的说明了解了:
 
TFT液晶屏的操作原理,就是写数据和写命令。
通过对写数据或写命令的代码的分析,可以看到数据是怎样输送的。
TFT液晶屏的初始化工作的主要内容。
常用的颜色代码。
如何让液晶屏显示不同的颜色。
最后仔细观察图片,可以了解
什么是隔行扫面,前景颜色,背景颜色。
以及,花屏是什么原因造成的。
至于如何显示字符,汉字,图片,下回再说。
永不止步步 发表于11-29 13:56 浏览65535次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

永不止步步
金币:67410个|学分:308117个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号