LCD12864驱动程序.docx
《LCD12864驱动程序.docx》由会员分享,可在线阅读,更多相关《LCD12864驱动程序.docx(21页珍藏版)》请在冰豆网上搜索。
![LCD12864驱动程序.docx](https://file1.bdocx.com/fileroot1/2023-4/16/0619b4af-673b-4906-84ec-93c1414e1935/0619b4af-673b-4906-84ec-93c1414e19351.gif)
LCD12864驱动程序
LCD12864(T6963)驱动程序(总20页)
液晶显示模块的应用
一、结构特点
内藏T6963C的液晶显示模块上已经实现了T6963C与行、列驱动器及显示缓冲区RAM的接口,同时也已用硬件设置了液晶屏的结构(单双屏、数据传输方式、显示窗口长度、宽度等等。
我们常用的液晶显示模块一般都是单屏结构,因此我们这里只讨论单屏结构的液晶显示模块。
内藏T6963C的单屏结构点阵图形液晶显示模块的方框图如下:
二、T6963C的特点
(1)T6963C是点阵式液晶图形显示控制器它能直接与8位微处理器接口;
(2)T6963C的字符字体可由硬件或软件设置,其字体有4种5X8、6X8、7X8、8X8;
(3)T6963C的占空比可从1/16到1/128;
(4)T6963C可以图形方式、文本方式及图形和文本合成方式进行显示,以及文本方式下的特征显示,还可以实现图形拷贝操作等等;
(5)T6963C具有内部字符发生器CGROM,共有128个字符。
T6963C可管理64K显示缓冲区及字符发生器CGRAM,并允许MPU随时访问显示缓冲区,甚至可以进行位操作。
三、该类液晶模块的管脚定义见下表:
说明:
对于单电源模块,标志为V0/POFF。
当该管脚为高或悬空时,内部DC/DC功能开启;为低时,内部DC/DC功能关闭。
该功能可用作屏幕保护和休眠方式。
如果用其直接替代双电源模块,该管脚直接悬空即可。
四、液晶显示模块的供电说明
1.如果您所选用的液晶模块是双电源(VDD/V0)供电的就需要提供一个负电压(液晶驱动电压V0/VEE),用以调节对比度,接在液晶模块的V0引脚上。
因为液晶材料的物理特性,液晶的对比度会随着温度的变化而相应变化,所以,您加的负电压值应该随温度作相应的调整,大致是温度变化10°C电压变化1伏左右。
为满足这一要求您要选择较大值的负电源,然后做一个温度补偿电路,或者安排一个电位器调整负电压值。
例如对于QH12864T-HT-LED04,当室温(VDD=5V)时,V0=,如果要用到-20°C,液晶驱动电压将要变到V0=,再考虑到负载消耗所以您提供的负电源应该为-16V左右。
但如果超过此值太多或说超过了液晶驱动电源的极限值的话应该考虑保护电路。
2.常用负电源产生办法
1)采用79系列三端集成稳压器可产生-18v(7918)-24v(7924)等电源
2)采用DC-DC模块市场上常见的5D**系列型号可选择使用
3)采用DC-DC集成电路制作负电源如MAX749、MAX680、MC34063等。
3.液晶模块可选用带背光的型号大部分为LED背光方式,供电为~直流电源,严格限制5V电源直接供电,否则不仅会增加您的功耗,更会增加损坏背光灯的可能性和缩短液晶模块的使用寿命。
推荐电压如下:
当背光方式为LED04即底背光时VLED<;
当背光方式为LED03即边背光时VLED。
五、T6963C与MPU的接口时序:
T6963C与MPU接口时序如图:
六、液晶显示模块指令系统
该类液晶模块的系统指令集其实就是T6963C控制器的指令集。
模块的初始化设置一般都由管脚设置完成,因此其指令系统将集中于显示功能的设置上。
T6963C的指令可带一个或两个参数,或无参数。
每条指令的执行都是先送入参数(如果有的话),再送入指令代码。
每次操作之前,最好先进行状态字检测。
T6963C的状态字如下所示:
由于状态位作用不一样,因此执行不同指令必须检测不同状态位。
在MPU每一次读写指令和数据时,STA0和STA1要同时有效――处于"准备好"状态。
当MPU读写数组时,判断STA2或STA3状态。
屏读、屏拷贝指令使用STA6。
STA5和STA7反映T6963C内部运行状态。
T6963C指令系统的说明:
1、指针设置指令,格式如下:
D1,D2为第一和第二个参数,后一个字节为指令代码,根据N0,N1,N2的取值,该指令有三种含义(N0,N1,N2不能有两个同时为1)
(1)光标指针设置:
D1表示光标在实际液晶屏上离左上角的横向距离(字符数),D2表示纵向距离(字符行)
(2)CGRAM偏置地填寄存器设置:
设置了CGRAM在显示64KRAM内的高5位地址,CGRAM的实际地址为:
(3)地址指针设置:
设置将要进行操作的显示缓冲区(RAM)的一个单元地址,D1、D2为该单元地址的低位和高位地址。
2、显示区域设置,指令格式为:
根据N1,N0的不同取值,该指令有四种指令功能形式:
文本区和图形区首地址为对应显示屏上左上角字符位或字节位,修改该地址可以产生卷动效果。
D1,D2分别为该地址的低位和高位字节。
文本区宽度(字节数/行)设置和图形区宽度(字节数/行)设置用于调整一行显示所占显示RAM的字节数,从而确定显示屏与显示RAM单元的对应关系。
T6963C硬件设置的显示窗口宽度是指T6963C扫描驱动的有效列数。
需说明的是当硬件设置6×8字体时,图形显示区单元的低6位有效,对应显示屏上6×1显示位。
3、显示方式设置,指令格式为:
N3:
字符发生器选择位。
N3=1为外部字行发生器有效,此时内部字符发生器被屏蔽,字符代码全部提供给外部字符发生器使用,字符代码为00H-FFH。
N3=0为CGROM即内部字符发生器有效,由于CGROM字符代码为00H~7FH。
因此选用80H~FFH字符代码时,将自动选择CGRAM。
N2~N0:
合成显示方式控制位,其组合功能如下表:
当设置文本方式和图形方式无能打开时,上述合成显示方式设置才有效。
其中的文本特征方式是指将图形区改为文本特征区。
该区大小与文本区相同,每个字节作为对应文本区的每个字符显示的特征,包括字符显示与不显示、字符闪烁及字符的“负向”显示。
通过这种方式,T6963C可以控制每个字符的文本特征。
文本特征区内,字符的文本特征码由一个字节的低四位组成,即:
d3:
字符闪烁控制位,d3=1为闪烁,d3=0为不闪烁;
d2~d0的组合如下:
启用文本特征方式时可在原有图形区和文本区外用图形区域设置指令另开一区作为文本特征区,以保持原图形区的数据。
显示缓冲区可划分如下:
4、显示开关,指令格式如下:
N0:
1/0,光标闪烁启用/禁止
N1:
1/0,光标显示启用/禁止
N2:
1/0,文本显示启用/禁止
N3:
1/0,图形显示启用/禁止
5、光标形状选择,指令格式如下:
光标形状为8点(列)N行,N的值为0-7H
6、数据自动读、写方式设置:
该指令执行后,MPU可以连续地读、写显示缓冲区RAM的数据,每读、写一次,地址指针自动增1。
自动读、写结束时,必须写入自动结束命令以使T6963C退出自动读、写状态,开始接受其它指令。
N1,N0组合功能如下:
7、数据一次读、写方式,指令格式如下:
D1为需要写的数据,读时无此数据。
8、屏读,指令格式为:
该指令将屏上地址指针处文本与图形合成后显示的一字节内容数据送到T6963C的数据栈内,等待MPU读出。
地址指针应在图形区内设置。
9、屏拷贝,指令格式为:
该指令将屏上当前地址指针(图形区内)处开始的一行合成显示内容拷贝到相对应的图形显示区的一组单元内,该指令不能用于文本特征方式下或双屏结构液晶显示器的应用上。
10、位操作:
该指令可将显示缓冲区某单元的某一位清零或置1,该单元地址当前地址指针提供。
N3=1置1,N3=0清零。
N2~N0:
操作位,对应该单元的D0~D7位。
至此,T6963C的指令系统全部讲述完毕。
七、液晶显示模块与MCU的接口方法
一、直接访问方式
MPU可利用数据总线与控制信号直接采用I/O设备访问形式控制T6963C类液晶显示模块。
接口电路以精电蓬远公司提供的演示板为例,如下图所示:
8031数据口P0口直接与液晶显示模块的数据口连接,由于T6963C接口适用于8080系列和Z80系列MPU,所以可以直接用8031的/RD、/WR作为液晶显示模块的读、写控制信号,液晶显示模块/RESET,/HALT挂在+5V上。
/CE信号可由地址线译码产生。
C/D信号由8031地址线A8提供,A8=1为指令口地址;A8=0为数据口地址。
指令通道地址C_ADD:
8100H
数据通道地址D_ADD:
8000H
二、间接控制方式
间接控制方式是MPU通过并行接口间接实现对液晶显示模块控制。
根据液晶模块的需要,并行接口需要一个8位的并行接口和一个3位的并行口,由上图所示。
8031的P1口作为数据总线。
P3口中3位作为读、写及寄存器选择信号。
由于并行接口只用于液晶显示模块,所以/CE信号接地就行了。
MPU通过并行接口操纵液晶显示模块,要对其时序关系有一个清楚的了解,并在程序中应明确地反映出来。
八、LCD驱动程序的设计
以直接访问方式为例,说明LCD驱动程序的编制方法。
#include<>
#include<>
#include<>
#include<>
#include<>
#defineulongunsignedlong
#defineuintunsignedint
#defineucharunsignedchar
#defineTRUE1
#defineFALSE0
#defineHIGH1
#defineLOW0
6963C6963C0CPointer
if(show)
fnPR13(0xf8|(7-column%8)); //0xf8为画点命令
else
fnPR13(0xf0|(7-column%8)); //0xf0为清点命令
}
//以指定的数据进行画点
voidLCM_show(uchar*s,intstart_line,inthow_many_line){
intaddr,i;
addr= LCM_G_BASE+start_line*16;
LCM_set_address(addr);
fnPR12(LCM_AUT_WR); //自动写模式
for(i=0;i fnPR14(s[i]);
}
fnPR12(LCM_AUT_OVR);//自动写结束
}
/***********************************************************************
画一条x1,y1到x2,y2的直线
(show=1画点,show=0清点)
***********************************************************************/
voidLCM_line(intx1,inty1,intx2,inty2,ucharshow)
{
intdy;
intdx;
intstepx,stepy,fraction;
dy=y2-y1;
dx=x2-x1;
if(dy<0)
{
dy=-dy;
stepy=-1;
}
else
{
stepy=1;
}
if(dx<0)
{
dx=-dx;
stepx=-1;
}
else
{
stepx=1;
}
dy<<=1;
dx<<=1;
LCM_pixel(x1,y1,show);
if(dx>dy)
{
fraction=dy-(dx>>1);
while(x1!
=x2)
{
if(fraction>=0)
{
y1+=stepy; fraction-=dx;
}
x1+=stepx;
fraction+=dy;
LCM_pixel(x1,y1,show);
}
}
else
{
fraction=dx-(dy>>1);
while(y1!
=y2)
{
if(fraction>=0)
{
x1+=stepx;
fraction-=dy;
}
y1+=stepy;
fraction+=dx;
LCM_pixel(x1,y1,show);
}
}
}
/***********************************************************************
以x,y为圆心,以radius为半径画贺
(show=1画点,show=0清点)
***********************************************************************/
voidLCM_circle(intx,inty,intradius,ucharshow)
{
intxc=0;
intyc;
intp;
yc=radius; p=3-(radius<<1);
while(xc<=yc)
{
LCM_pixel(x+xc,y+yc,show);
LCM_pixel(x+xc,y-yc,show);
LCM_pixel(x-xc,y+yc,show);
LCM_pixel(x-xc,y-yc,show);
LCM_pixel(x+yc,y+xc,show);
LCM_pixel(x+yc,y-xc,show);
LCM_pixel(x-yc,y+xc,show);
LCM_pixel(x-yc,y-xc,show);
if(p<0)
p+=(xc++<<2)+6;
else
p+=((xc++-yc--)<<2)+10;
}
}
//画半圆
voidLCM_circle_half(intx,inty,intradius,ucharshow)
{
intxc=0;
intyc;
intp;
yc=radius;
p=3-(radius<<1);
while(xc<=yc)
{
// LCM_pixel(x+xc,y+yc,show);
LCM_pixel(x+xc,y-yc,show);
// LCM_pixel(x-xc,y+yc,show);
LCM_pixel(x-xc,y-yc,show);
// LCM_pixel(x+yc,y+xc,show);
LCM_pixel(x+yc,y-xc,show);
// LCM_pixel(x-yc,y+xc,show);
LCM_pixel(x-yc,y-xc,show);
if(p<0)
p+=(xc++<<2)+6;
else
p+=((xc++-yc--)<<2)+10;
}
}
//画矩形
voidLCM_box(intx1,inty1,intx2,inty2,ucharshow)
{
LCM_line(x1,y1,x2,y1,show); //up
LCM_line(x1,y2,x2,y2,show); //down
LCM_line(x2,y1,x2,y2,show); //right
LCM_line(x1,y1,x1,y2,show); //left
}
//***********************************************************************
//以x,y点为原点,以degree为角度,画一条从内径到外径之间的线段
//(show=1画点,show=0清点)
//***********************************************************************
/*
voidLCM_degree_line(intx,inty,intdegree,intinner_radius,intouter_radius,ucharshow)
{
intfx,fy,tx,ty;
fx=x+(inner_radius*sin(degree*/180));
fy=y-(inner_radius*cos(degree*/180));
tx=x+(outer_radius*sin(degree*/180));
ty=y-(outer_radius*cos(degree*/180));
LCM_line(fx,fy,tx,ty,show);
}
//画上函数线段的包括线
voidLCM_degree_line_bold(intx,inty,intdegree,intinner_radius,intouter_radius,ucharshow)
{
intfx,fy,tx,ty;
fx=x+(inner_radius*sin(degree*/180));
fy=y-(inner_radius*cos(degree*/180));
tx=x+(outer_radius*sin(degree*/180));
ty=y-(outer_radius*cos(degree*/180));
LCM_line(fx,fy,tx,ty,show);
LCM_line(fx+1,fy+1,tx+1,ty+1,show);
LCM_line(fx-1,fy-1,tx-1,ty-1,show);
}
*/
//画进度条函数
/*
voidLCM_fill(intx1,inty1,intx2,inty2,ucharpersent,charfirst)
{
charM,horizon_line,horizon_line2,i,str1[10];
if(persent>100)return;
if(!
first)
{
LCM_line(x1,y2,x2,y2,1); //down
LCM_line(x2,y1,x2,y2,1); //right
LCM_line(x1,y1,x1,y2,1); //left
first=1;
}
M=100/abs(y2-y1);
horizon_line=persent/M;
for(i=0;i LCM_line(x1+2,y2-2-i,x2-2,y2-2-i,1);
horizon_line2=100/M;
for(i=horizon_line;i LCM_line(x1+2,y2-2-i,x2-2,y2-2-i,0);
sprintf(str1,"%02d%%",persent);
LCM_print_ram((x2+x1)/16-1,(y2+y1)/16,str1);
}
*/
/**************************************************************************
延时ms:
延时的毫秒数
***************************************************************************/
voidDelayMs(unitms)
{
unitiq0,iq1;
for(iq0=ms;iq0>0;iq0--)
for(iq1=1000;iq1>0;iq1--);
}
voidmain(void)//测试用
{
LCM_init();
LCM_clear_ram();
LCM_circle(120,64,20,1);
LCM_circle_half(60,64,20,1);
LCM_box(150,20,180,60,1);
}