跟晓雅数码学单片机之 LCD学习全攻略(软件篇)
说明:文中涉及到的资料有《2.4寸TFT原理图.pdf》、《LMS241GF31_PI_Rev000_090210(1)
(图纸).pdf》和《S6D04H0驱动 IC手册.pdf》,已经上传到百度文库和新浪爱问共享资料。
下载地址:http://ishare.iask.sina.com.cn/f/35461926.html
晓雅数码在此也只是抛砖引玉,难免有不足或者错误的地方,欢迎大家提出,可以发邮
件:2652599905@qq.com联系,特此声明!晓雅数码,与你同行!
1. LCD模块接口
通过《跟晓雅数码学单片机之 LCD学习全攻略(硬件篇)》我们知道:厂家出厂的时候
将其接口模型设置成了“80 MCU 16-bit Parallel I/F”,即数据位 16位,8080总线。
因为 80 MCU 16-bit Parallel I/F属于 80-series Parallel Interface(80-系列并行接口),所
以我们现在只关心 datasheet《S6D04H0驱动 IC手册.pdf》里面关于 80-系列并行接口的描述。
如果你的 LCD模块是其他类型接口那么就关注相应的接口描述,这就是传说中的举一反三。
用到什么学什么,即突出了重点(不然整个资料全看,头都大了,这个不仅是现在学习 LCD
控制如此,在学习其他芯片也是如此,有的芯片资料只有英文而且好几百页,如何从快速获
得自己想要的信息,是驱动编程的一项重要能力哦!),又因为学习的内容有实物可以调试,
效果更佳!---------晓雅数码#
体会#,呵呵~
废话少说,我们直接打开《S6D04H0驱动 IC手册.pdf》找讲到 80-series Parallel Interface
(80-系列并行接口)内容的地方,首先我们看到了这里:
我们跳到第 33页,可以看如下两张图:
图 1 80-系列并行接口时序图
图 2 80-系列并行接口时序特性
图 1 是 80-系列并行接口时序图,图 2是 80-系列并行接口时序特性即时序的时间要求。
在这里我们可以看到时序的时间都是以 ns为单位的,这对 51单片机来说很快了,那么我们
编程的时候就不需要额外的延时,因为 51单片机一般都是 us级别的;如果换成其他 ns级
别的处理器,那么我们编程的时候就需要延时等待如上图 2所列的时间。
图 1是 80-系列并行接口时序图,这里似乎将的还不是很清楚,我们继续在资料里面找,
《S6D04H0驱动 IC手册.pdf》的第 53页再次将到了 80-系列并行接口的内容,摘自如下:
上面的英文大致意思是:写周期指的是主机通过接口写信息(命令或者数据,命令和数
据)。每个写周期(WRX 高-低-高序列)由 3个控制信号(DCX, RDX, WRX)和数据信号
(DB[17:0])组成。DCX位是一个控制信号,它指明写的是命令还是数据。当控制信号 DCX
是低即 0的时候写入的是命令,反之写入的是数据。
翻译完毕,总之告诉我们了两件事情:1.哪些是数据线和控制信号;2 控制信号 DCX
的作用。注释:这里的主机在我们的开发板上面指的是 51单片机。
英文下面的图也很重要,从图中的英文注释我们可以得知:在WRX从低电平到高电平
的跳变时,从机(这里指 LCD驱动芯片)读取数据线上的数据-----编程会用用的哦!
接下来的这张图就更加重要了:
图 3 80-系列并行总线
,写(数据或命令)到寄存器或者显存
图 3 为什么重要?因为 LCD 模块的控制都是通过单片机对其模块的内部寄存器、 显
存进行操作来最终完成的。因此 LCD模块操作必然有写数据或者命令,图 3 就告诉我们如
何写数据或者命令到寄存器或显存。
现在我们仔细认真的看看图 3的时序(关于时序的详细讲解,可以看我收集和整理的另
一篇文章:《跟晓雅数码学单片机之时序图详解》。)
下载地址:http://ishare.iask.sina.com.cn/f/35462470.html
从图 3 的红色英文注释我们知道这里是以 8位数据线为例的,而我们用的是 16位数据
线,但并不影响我们的理解,因为除了数据线的增加以外,其他都是一样的。
时序图都是从左往右看的:最左边的蓝色是刚刚开始的地方是一种不定的状态不用理
会。紧接着与第一根竖线“1-byte command(第一字节命令)”相交的 3条控制线 DCX、RDX、
WRX,我们一一道来:
(1)CSX,其电平是低电平,前面在讲硬件的时候已经说过 CSX就是 CS片选信号,
一般的片选信号在 LCD操作期间是一直有效的,从图上也证明这一点,故以后对片选信号
不再说明。
(2)DCX这里是低电平,说明这里是写命令,从数据线用“CMD”也得到证实。
(3)RDX 这时为高,因为是写操作,当然读操作要禁止,所以在写的整个过程当中
RDX一直为高,故以后对 RDX信号也不再说明。
(4)WRX此时是低电平,因为我们知道由低到高变化数据或者命令才能送到从机(LCD
芯片),所以先要拉低,然后数据线上放上数据,再拉高WRX。
(5)接着在数据线上写入命令,拉高WRX就可以了。
第二条竖线“2-byte command(第二字节命令)”相交的 3条控制线 DCX、RDX、WRX,
除WRX需要有一个从低到高的变化以外,其他不变,理由很简单,这里还是写操作而且还
是写命令,当然和写第一个字节命令一样了。
注:在WRX为低的同时数据或命令已经加载到数据线,所以,程序中是先加载数据,
然后让WRX产生跳变。
通过上面的讲解,我们可以理解如下的代码:
void LCD_Write_COM(char VL) //发送命令
{
LCD_RS=0; //RS=0
示写命令,这里的 RS就是上面的 DCX,详见
//《普中科技开发板之 LCD学习全攻略(硬件篇)》
LCD_DataPortL=VL; //送数据到数据线
LCD_WR=0;
LCD_WR=1; //WR产生一个由低到高的跳变
}
说明:上面的程序没有看到片选信号和读信号的操作是因为在其他地方已经将片选信号
清零和将读信号置高了。
理解了写命令,就不难理解写数据了,从图中第三条竖线与控制信号的电平变化可以知
道,将 DCX拉高而其他操作和之前一样,就是写数据了,程序如下:
void LCD_Write_Para (char VL) //发送数据
{
LCD_RS=1; //RS=1表示写数据,这里的 RS就是上面的 DCX,详见
//《普中科技开发板之 LCD学习全攻略(硬件篇)》
LCD_DataPortL=VL; //送数据到数据线
LCD_WR=0;
LCD_WR=1; //WR产生一个由低到高的跳变
}
其中,对于程序中出现的宏定义,在其头文件中已经声明好了,如下所述:
#define LCD_DataPortH P1 //高 8位数据口,8位模式下只使用高 8位
#define LCD_DataPortL P0 //低 8位数据口 ,8位模式下低 8位可以不接线
sbit LCD_REST = P3^3; //RST 引脚定义
sbit LCD_RD = P3^2; //RD 引脚定义
sbit LCD_WR = P2^5; //WR 引脚定义
sbit LCD_RS = P2^6; //RS 引脚定义
sbit LCD_CS = P2^7; //CS 引脚定义
写命令或者写数据就到此为止。下面介绍读操作:
图 4 80-系列并行总线协议—从寄存器读操作
从第一条红色竖线看过去:
(1)CSX为低,已经说过 CXS为片选信号,在对 LCD操作时必须一直为低。
(2)DCX 为低表示发送的是命令,因为要先告诉 LCD 模块,需要读取的是哪个寄存
器。
(3)RDX为高,这时候还没有开始读,而是写命令所以还是为高。
(4)WRX为低,后面再拉高,一个由低到高的跳变,写入命令。
(5)在WRX为低的同时,命令加载到数据线,WRX一个由低到高的跳变写入命令。
这里和上面图 3的写入命令操作是一样的。
从第二条红色竖线看过去:
(1)CSX当然为低;
(2)DCX拉高;
(3)RDX为低,然后拉高;
(4)对于这个 LCD 的驱动芯片来说为了读取里面内容需要读两次,第一次读到的是
DM意思是 dummy(没有用的)。
从第三条红色竖线看过去和从第二条红色竖线看过去的操作都是一样的,正如上面说
的,为了读取芯片里面的内容需要两次读,第一次读取的内容没有意义,舍去;第二次才是
真正有用的信息。
之后读显存数据又是重复的操作了。
以几个函数就是要介绍的最基本的时序操作程序, 它们是L C D驱动程序当中与底层硬
件打交道的代码。要改变驱动 LCD 的 MCU端口时或者换用别的控制芯片来驱动 LCD 时,
基本上只需要在这些代码里做一下修改即可。记住:软件是依据硬件而来的,不能凭空臆念!
2. LCD模块的初始化
LCD模块的初始化主要就是对 LCD模块中的寄存器进行初始化, 初始化的方法就是调
用前面介绍的写命令和写数据函数,将 LCD模块中的寄存器设置为合适的值。
例如:
void LCD_Init(void)
{
LCD_REST=1;
delayms(50);
LCD_REST=0;
delayms(50);
LCD_REST=1;
delayms(5);
LCD_CS =0;
LCD_Write_COM(0XF0);
LCD_Write_Para(0X5A);
LCD_Write_Para(0X5A);
………………………………………………………………………………..
LCD_Write_COM(0x29);
LCD_Write_COM(0x2c);
LCD_CS =1;
}
这里只是取了初始化中的一小部分。对寄存器进行写入之前, 为了确定 LCD 完成正确
的复位,一般会控制端口对 LCD模块进行一次复位操作, 即给 LCD模块的复位引脚一个低
电平的脉冲。
从 LCD_Init()函数可以知道里面有很多的 LCD_Write_COM()和 LCD_Write_Para
(),对于里面设置的值一般都是厂商提供的,因为有些设置与制造 LCD模块时的配置有关;
如果没有告诉我们推荐的初始化值, 那自己去摸索是一件相当费力不讨好的事情。因此拿到
一块新屏没有初始化代码时,你可以联系供应商或者 LCD厂商,他们会乐意告诉你的。当
然,如果自己想弄明白他们代表的意思最好的办法就是自己先阅读 datasheet,然后修改程序,
编译,下载后观察结果,如此反复。
3. 点阵显示原理
图 5 汉字“你”的一种取模方式
我们以上图显示一个“你”为例来说明。里面的每一个小方正格子代表 LCD屏上面的
一个点,这个点用数据形式来表示就是占一个位(bit)。我们知道一个位(bit)可以是 1,
也可以是 0,那么我们可以规定当该位为 1的时候此点为白色,该位为 0的时候此点显示黑
色,这样就出现了上图的效果----黑底白字。假如我们定义该位为 1 的时候此点为红色,该
位为 0的时候此点为绿色,这样出来的效果----绿底红字。(对于单色 LCD 更好理解,某点
为 1就亮,否则就灭)
对于汉字来说,哪些点需要显示哪些不需要是有规定的,否则你显示的汉字可能大家都
不认识。这样就出现了右边对应的编码,当 N 多个汉字的编码放在一起时,我们称之为汉
字字库(晓雅数码是这样理解的,呵呵,精确字库定义自己去找吧,个人觉得理解就好)。
因为一个汉字可以 16*16点表示,也可以 32*32点表示,如此等等,由此便有了不同的字库。
不同字库之间除了点阵数据量不同,可能取模方式也不同,但如何在 LCD上显示的本质是
一样的。
这样显示一个汉字,就转换成了在某一点显示出某一颜色的问题了。绘制一个指定位置
的点就是将显存当中对应该点的数据位进行操作,这样就用到了第一小节将的显存与 LCD
屏上的点的对应关系,由此通过程序来控制 LCD屏上的点的显示。
4. 取模与显示的关系
上一小节提到了取模方式,那么什么是取模方式呢?取模方式说简单一点就是如何对一
个汉字进行编码,比如图 5中的“你”从右边的编码来看,这里的取模方式是“逐行式,从
左到右,从上到下”。既然可以逐行扫描,自然也可以逐列扫描,还可以从下到上,从右到
左,由此可以组合出很多种不同的取模方式。
在如此多的取模方式中具体选择哪一种方式呢?这是由显存和 LCD屏显示对应关系而
定的,在资料《S6D04H0驱动 IC手册.pdf》中的第 124页中有:
图 6 显存与屏对应关系
其中的:B5 B6 B7的设置是在初始化 LCD寄存器时配置的,具体如下(见 P189)
有时候我们一下子也没有明白他们究竟是什么对应关系,肿么办?在编程当中有一种方
法就是穷举法,也就是将 B5 B6 B7设置好后,将某个汉字常用的几种取模方式都显示一次,
其中总会有一种取模是正确的。
很抱歉这里似乎写的很模糊,这是因为如果前面的东东已经明白了,你只需要动动手,
实际多测试不同的 B5 B6 B7设置下的汉字显示自然就理解了。晓雅数码个人一直认为单片
机这种东西必须要实际操作才能真正体会的,“纸上得来终觉浅,绝知此事要躬行”对于单
片机学习来说算是至理名言。
这里推荐给大家一个很好用的取模软件《PCtoLCD.rar》,可以设置好几种不同的取模方
式,如下图:
右边还有取模演示,真的是不错的!
这款软件是在网上找到的,版权当然归原作者,从软件帮助里面可以看到作者是陈新汀,
特别感谢!(需要的童鞋可以到网上自己搜索,为避免涉及到版权问题,在此没有提供,请
谅解!)
(LCD显示实例,晚上照的,有点不清楚,呵呵)
附录:汉字显示函数
void ChineseChar(uint x,uint y,int size,uint For_color,uint Bk_color ,char c)
{
int e=0,i,j;
int ed;
uint ncols;
uint nrows;
uint nbytes;
uchar *pfont;
uchar *pchar;
uchar *fonttable[]={(uchar *)hz16,(uchar *)hz24 , (uchar *)hz32};
pfont=(uchar *)fonttable[size]; //得到不同数组首地址·
if(size==0)
{
ncols =16-1;
nrows =16-1;
nbytes =32; //(16*16)/8 占用的字节数
}
else if(size==1)
{
ncols =24-1;
nrows =24-1;
nbytes =72; //(24*24)/8 占用的字节数
}
else if(size==2)
{
ncols =32-1;
nrows =32-1;
nbytes =132; //(32*32)/8 占用的字节数
}
pchar=pfont + (nbytes*(c-1)); //计算需要显示的汉字在数组中的偏移
//也即指针指向要显示的汉字的首地址
Address_set(x, y, x+nrows,y+ncols); //行列地址设置
for(i=0;i
>j)&0x01)
{
LCD_Write_DATA(For_color>>8 , For_color ); //textcolor
}
else
{
LCD_Write_DATA( Bk_color>>8 , Bk_color); //backcolor
}
}
}
}
说明:函数中出现的其他宏定义或者函数在其他地方已经定义或者实现,此处的主要目
的只是说明如何显示一个汉字。
说明:文中涉及到的资料有《2.4寸 TFT原理图.pdf》、《LMS241GF31_PI_Rev000_090210(1)
(图纸).pdf》和《S6D04H0驱动 IC手册.pdf》,已经上传到百度文库和新浪爱问共享资料。
下载地址:http://ishare.iask.sina.com.cn/f/35461926.html
晓雅数码在此也只是抛砖引玉,难免有不足或者错误的地方,欢迎大家提出,可以发邮
件:2652599905@qq.com联系,特此声明!晓雅数码,与你同行!
为了编排时候页数不过于太多,文中引用文字或图片截图可能看的不清楚,不过文中引
用资料里面的文字或图片在本文中已经详细说明了出处,可以打开原文档进行阅读!
晓雅数码,与你同行!