




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
51单片机综合学习
12864液晶原理分析1
辛勤学习了好几天,终于对12864液晶有了些初步了解~没有视频教程学起来真有些累,基本上内部程序写入顺序都是根据程序自我变动,然后逆向反推出原理……芯片:YM12864RP-1控制芯片:ST7920A
带中文字库初步小结:1、
控制芯片不同,寄存器定义会不同
2、
显示方式有并行和串行,程序不同
3、
含字库芯片显示字符时不必对字符取模了
4、
对芯片的结构地址一定要理解清楚
5、
显示汉字时液晶芯片写入数据的顺序(即显示的顺序)要清楚
6、
显示图片时液晶芯片写入数据的顺序(即显示的顺序)要清楚
7、
显示汉字时的二级单元(一级为八位数据写入单元)要清楚
8、
显示图片时的二级单元(一级为八位数据写入单元)要清楚
12864点阵液晶显示模块(LCM)就是由128*64个液晶显示点组成的一个128列*64行的阵列。每个显示点对应一位二进制数,1表示亮,0表示灭。存储这些点阵信息的RAM称为显示数据存储器。要显示某个图形或汉字就是将相应的点阵信息写入到相应的存储单元中。图形或汉字的点阵信息由自己设计,问题的关键就是显示点在液晶屏上的位置(行和列)与其在存储器中的地址之间的关系。由于多数液晶显示模块的驱动电路是由一片行驱动器和两片列驱动器构成,所以12864液晶屏实际上是由左右两块独立的64*64液晶屏拼接而成,每半屏有一个512*8bits显示数据RAM。左右半屏驱动电路及存储器分别由片选信号CS1和CS2选择。显示点在64*64液晶屏上的位置由行号(line,0~63)与列号(column,0~63)确定。512*8bitsRAM中某个存储单元的地址由页地址(Xpage,0~7)和列地址(Yaddress,0~63)确定。每个存储单元存储8个液晶点的显示信息。
为了使液晶点位置信息与存储地址的对应关系更直观关,将64*64液晶屏从上至下8等分为8个显示块,每块包括8行*64列个点阵。每列中的8行点阵信息构成一个8bits二进制数,存储在一个存储单元中。(注意:二进制的高低有效位顺序与行号对应关系因不同商家而不同)存放一个显示块的RAM区称为存储页。即64*64液晶屏的点阵信息存储在8个存储页中,每页64个字节,每个字节存储一列(8行)点阵信息。因此存储单元地址包括页地址(Xpage,0~7)和列地址(Yaddress,0~63)。例如点亮128*64的屏中(20,30)位置上的液晶点,因列地址30小于64,该点在左半屏第29列,所以CS1有效;行地址20除以8取整得2,取余得4,该点在RAM中页地址为2,在字节中的序号为4;所以将二进制数据00010000(也可能是00001000,高低顺序取决于制造商)写入Xpage=2,Yaddress=29的存储单元中即点亮(20,30)上的液晶点。
芯片的结构一定要清楚!点阵LCD的显示原理
在数字电路中,所有的数据都是以0和1保存的,对LCD控制器进行不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有6000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。
那么,得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模的记载方式如图1所示:
图1“A”字模图而中文的“你”在字模中的记载却如图2所示:
图2“你”字模图
图3
图4字符二级单元(图3中阴影部分)
一个汉字的二级单元是一个16*16的区域,因些128*64液晶可以显示4行8列共32个汉字(如图3)。而它的一个二级单元如图4(在无字库时,对汉字的取模有横向跟纵向两种,要注意),对于并行含有子库芯片的显示,只要设定好这个二级单元的地址(如0X80+i,这样设定i的范围为0~31,这里注意第一行会直接跳到第三行;或者根据自己需要如第二行0X90+i,i范围为0~7;第三行0X88+i,i范围为0~7;),然后直接把汉字写入就OK了~(串行无字符库的后面再做分析)
图5:垂直坐标:上半屏00~1F,总共为32
水平坐标:上半屏水平坐标分别为0X80+(00~07)
下半屏00~1F,总共为32
下半屏水平坐标分别为0X88+(00~07)
图片显示芯片结构分块与汉字显示不一样
图象显示过程是这样的:首先设置垂直地址,再设水平地址(连续写入两个字节的资料来完成垂直与水平的坐标地址,然后在每个地址里写入16位数据)。垂直地址范围AC5...AC0
水平地址范围AC3…AC0
绘图RAM的地址计数器(AC)只会对水平地址(X轴)自动加一,当水平地址=0FH时会重新设为00H
但并不会对垂直地址做进位自动加一,故当连续写入多笔资料时,程序需自行判断垂直地址是否需重新设定。GDRAM的坐标地址与资料排列顺序如图5:分上下屏写入。for(i=0;i<32;i++)
//上半屏32个垂直地址
{
write_com(0x80+i);
//
垂直地址write_com(0x80);
//
水平地址
for(j=0;j<16;j++)
{
write_data(*adder);
adder++;
}}
带中文字库的128X64显示模块时应注意以下几点:
①欲在某一个位置显示中文字符时,应先设定显示字符位置,即先设定显示地址,再写入中文字符编码。
②显示ASCII字符过程与显示中文字符过程相同。不过在显示连续字符时,只须设定一次显示地址,由模块自动对地址加1指向下一个字符位置,否则,显示的字符中将会有一个空ASCII字符位置。
③当字符编码为2字节时,应先写入高位字节,再写入低位字节。
④模块在接收指令前,向处理器必须先确认模块内部处于非忙状态,即读取BF标志时BF需为“0”,方可接受新的指令。如果在送出一个指令前不检查BF标志,则在前一个指令和这个指令中间必须延迟一段较长的时间,即等待前一个指令确定执行完成。指令执行的时间请参考指令表中的指令执行时间说明。⑤“RE”为基本指令集与扩充指令集的选择控制位。当变更“RE”后,以后的指令集将维持在最后的状态,除非再次变更“RE”位,否则使用相同指令集时,无需每次均重设“RE”位。
程序———————并行(串行后面再分析)——————————————————————————#include<stdio.h>
#include<reg52.h>
#include<intrins.h>
#include<string.h>#defineucharunsignedchar
#defineuintunsignedintucharcodeLCD_data1[];
ucharcodeLCD_data2[];
ucharcodeLCD_picture1[];
ucharcodeLCD_picture2[];sbitRS=P2^4;
sbitRW=P2^5;
sbitEN=P2^6;
sbitPSB=P2^1;
sbitRES=P2^3;sbitDataport=P0;
sbitBusyport=P0^7;//////////////////////////////////////////////////////////////
void
delay_ms(unsignedintn)
//延时10×n毫秒程序
{
unsignedinti,j;
for(i=0;i<n;i++)
for(j=0;j<2000;j++);
}void
delay(unsignedintm)
//1US延时程序
{
unsignedinti,j;
for(i=0;i<m;i++)
for(j=0;j<10;j++);
}
///////////////////////////////////////////////////////////////
//判LCM忙子函数voidcheck_LCD_busy(void)
{
Dataport=0xff;
RS=0;
RW=1;
EN=1;
while(Busyport);
EN=0;
}
///////////////////////////////////////////////////////////////
//写命令子函数voidwrite_com(ucharCommand)
{
check_LCD_busy();
RW=0;
RS=0;
delay(1);
P0=Command;
EN=1;
delay(1);
EN=0;
}
////////////////////////////////////////////////////////////////
//写数据子函数voidwrite_data(ucharData)
{
check_LCD_busy();
RW=0;
RS=1;
delay(1);
P0=Data;
EN=1;
delay(1);
EN=0;
}
/////////////////////////////////////////////////////////////////
//LCM清屏函数voidlcdClear(void)
{
write_com(0x01);
}
////////////////////////////////////////////////////////////////
//LCM复位函数voidreset()
{
RES=0;
//复位
delay(1);
//延时
RES=1;
//复位置高
delay(10);
}
///////////////////////////////////////////////////////////////
//显示汉字voiddispString(ucharX,Y,uchar*msg)
//X为哪一行,Y为哪一列。msg为汉字
{
if(X==0)
X=0x80;
//第一行,汉字显示坐标
elseif(X==1)X=0x90;//第二行
elseif(X==2)X=0x88;//第三行
else
X=0x98;//第四行
Y=X+Y;
//Y为1往右移一位
write_com(Y);
//写入坐标
while(*msg)
{
write_data(*msg++);//显示汉字
}
}
///////////////////////////////////////////////////////////////
//显示图象
voiddisppicture(ucharcode*adder)
{
uinti,j;
//*******显示上半屏内容设置
for(i=0;i<32;i++)
//上半屏32个列地址
{
write_com(0x80+i);
//SET
垂直地址VERTICALADD
write_com(0x80);
//SET
水平地址HORIZONTALADD
for(j=0;j<16;j++)
{
write_data(*adder);
adder++;
}
}
//*******显示下半屏内容设置
for(i=0;i<32;i++)
//
{
write_com(0x80+i);
//SET垂直地址VERTICALADD
write_com(0x88);
//SET水平地址HORIZONTALADD
for(j=0;j<16;j++)
{
write_data(*adder);
adder++;
}
}
}///////////////////////////////////////////////////////////////
//LCD字库初始化函数voidlcdinit_str(void)
{
delay(40);
//大于40MS的延时程序
PSB=1;
//设置为8BIT并口工作模式
delay(1);
//延时
reset();
//复位
write_com(0x30);
//ExtendedFunctionSet:8BIT设置,RE=0:basicinstructionset,G=0:graphicdisplayOFF
delay(100);
//大于100uS的延时程序
write_com(0x30);
//FunctionSet
delay(37);
////大于37uS的延时程序
write_com(0x08);
//DisplayonControl
delay(100);
//大于100uS的延时程序
write_com(0x10);
//CursorDisplayControl光标设置
delay(100);
//大于100uS的延时程序
write_com(0x0C);
//DisplayControl,D=1,显示开
delay(100);
//大于100uS的延时程序
write_com(0x01);
//DisplayClear
delay(10);
//大于10mS的延时程序
write_com(0x06);
//EnryModeSet,光标从右向左加1位移动
delay(100);
//大于100uS的延时程序
}
//////////////////////////////////////////////////////////////////
//LCD图片(扩展)初始化函数voidlcdinit_pic(void)
{
delay(40);
//大于40MS的延时程序
PSB=1;
//设置为8BIT并口工作模式
delay(1);
//延时
reset();
write_com(0x36);
//ExtendedFunctionSetRE=1:extendedinstruction
delay(100);
//大于100uS的延时程序
write_com(0x36);
//ExtendedFunctionSet:RE=1:extendedinstructionset
delay(37);
////大于37uS的延时程序
write_com(0x3E);
//EXFUNCTION(DL=8BITS,RE=1,G=1)
delay(100);
//大于100uS的延时程序
write_com(0x01);
//CLEARSCREEN
delay(100);
//大于100uS的延时程序
}
/////////////////////////////////////////////////////////////////voidmain()
{
while(1)
{
lcdinit_str();
delay_ms(10);//此延时如果没有的话第一行会一直在第一列
dispString(0,1,"祖国江山好");
delay_ms(10);
dispString(1,1,"爱情少不了");
delay_ms(10);
dispString(2,1,"为了下一代");
delay_ms(10);
dispString(3,1,"赶紧谈恋爱");
delay_ms(200);
delay_ms(200);
lcdClear();
delay_ms(10);
dispString(0,1,"大名吴建峰");
delay_ms(10);
dispString(1,1,"性别为非女");
delay_ms(10);
dispString(2,1,"芳龄二十二");
delay_ms(10);
dispString(3,1,"海拔一百六");
delay_ms(200);
delay_ms(200);
lcdinit_pic();
lcdClear();
delay_ms(10);
disppicture(LCD_picture1);
delay_ms(300);
delay_ms(300);
}
}
图象代码库见最后!~
成果——————————————————————————————————
图形取模方法(转):128*64的像素能显示的内容就有限,也无法要求它能多清楚,如果将一个彩色的图片转换为单色位图,效果就更差了,个人不建议用它来显示彩色的图片,如果真要用128*64的液晶显示,建议如下:
1.尽量选择颜色比较单一的图片,当然一种颜色的效果最好不过了;
2.图片不能选择的太大,要不缩小了就看不清楚了;
3.图片的调整可以这样(仅供参考):
1>调整图片的宽高比大致为2:1;
2>将图片缩小到128*64像素;
3>保存为单色位图;
图片的大小缩放不太好操作,我通常是这样做的:你用画图程序打开你要显示的图片后,首先要操作的查看属性(点击菜单栏的图像->属性,单位选择为像素后,宽高值就出来了),比如:宽:603,高:444,这显然宽高比不是2:1,你就要调整了,444*2=888,现在为603,所以888/603=1.47,所以宽要放大为147%(点击菜单栏的图像->拉伸/扭曲,在拉伸里面的水平处改为147),现在就调整为2:1了;接下来就要将图片缩小到128*64像素,先计算缩放的比例,128/888=0.144,所以相同的操作(点击菜单栏的图像->拉伸/扭曲,在拉伸里面的水平处改为14,垂直里面也要改为14);最后就是保存为单色位图(文件->另存为->文件类型选择为:单色位图(.bmp))?试过颜色比较单一的,效果还可以,复杂的彩色图片效果就很不理想了...
说明:在调整图片的宽高比大致为2:1的过程中图片会被拉伸变形,不过缩小到128*64像素后也不是太明显...
图片取模
图片代码——————————————————————————————————
ucharcodeLCD_picture1[]=
{
0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x7F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,
0x00,0x00,0x07,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,
0x03,0x00,0x07,0xEC,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x37,0x80,
0x03,0x00,0x00,0xEC,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x18,0x3F,0xC0,
0x03,0x00,0x0F,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x18,0x79,0x80,
0x03,0x00,0x0F,0x6B,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x18,0x7F,0x00,
0x1F,0xF4,0x01,0xE9,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0xE0,0x18,0xFF,0x80,
0x1F,0xFC,0x00,0xFB,0x30,0x00,0x00,0x00,0x00,0x00,0x01,0xC6,0x70,0x1B,0x1E,0xC0,
0x03,0x38,0x01,0xB3,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x86,0x38,0xDB,0xFF,0xE0,
0x03,0x70,0x07,0x9E,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x26,0x18,0xDB,0x8C,0x70,
0x7F,0xFF,0x87,0x27,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x01,0xFF,0xFF,0xB8,
0x7F,0xFF,0x80,0x3F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x00,0x0C,0x18,
0x07,0x80,0x00,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0xFF,0xE0,
0x0F,0x00,0x00,0xFB,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xF0,0xFF,0xE0,
0x1F,0x30,0x01,0xCF,0xFF,0xFF,0x09,0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0x0C,0x00,
0x3B,0x36,0x03,0x07,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xCC,0x00,
0x73,0x76,0x03,0x3F,0xFF,0xFF,0xF7,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFC,0x00,
0x63,0xE6,0x00,0x3F,0xFF,0xFF,0xDC,0x80,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFC,0x00,
0x03,0xFE,0x00,0x7F,0xFF,0xFF,0xAF,0x60,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFC,0x00,
0x03,0xFE,0x00,0xFF,0xFF,0xFF,0xF5,0xC0,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFC,0x00,
0x00,0x00,0x01,0xFF,0xFF,0xFF,0x23,0x20,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFE,0x00,
0x00,0x00,0x03,0xFF,0x8F,0xE3,0xEC,0xA0,0x00,0x00,0x03,0xFF,0x1F,0xC7,0xFF,0x00,
0x00,0x00,0x03,0xFF,0x07,0xC1,0x92,0xC0,0x00,0x00,0x07,0xFE,0x0F,0x83,0xFF,0x80,
0x00,0x00,0x07,0xFF,0x03,0xC0,0xE9,0xC0,0x00,0x00,0x0F,0xFE,0x07,0x81,0xFF,0x80,
0x00,0x00,0x07,0xFE,0x03,0x80,0xED,0xE0,0x00,0x00,0x0F,0xFC,0x07,0x01,0xFF,0xC0,
0x00,0x00,0x0F,0xFE,0x1B,0xB0,0xDD,0xE0,0x00,0x00,0x1F,0xFC,0x37,0x61,0xFF,0xC0,
0x00,0x00,0x0F,0xFE,0x1B,0xB0,0xFF,0xE0,0x00,0x00,0x1F,0xFC,0x37,0x61,0xFF,0xC0,
0x00,0x00,0x0F,0xFE,0x1B,0xB0,0xFF,0xF0,0x00,0x00,0x1F,0xFC,0x37,0x61,0xFF,0xE0,
0x00,0x00,0x1F,0xFE,0x1B,0xB0,0xFF,0xF0,0x00,0x00,0x3F,0xFC,0x37,0x61,0xFF,0xE0,
0x00,0x00,0x1F,0xFF,0x03,0xC0,0xFF,0xF0,0x00,0x00,0x3F,0xFE,0x07,0x81,0xFF,0xE0,
0x00,0x00,0x1F,0xFF,0x07,0xC1,0xFF,0xF0,0x00,0x00,0x3F,0xFE,0x0F,0x83,0xFF,0xE0,
0x00,0x00,0x1F,0xFF,0x8C,0x63,0xFF,0xF0,0x00,0x00,0x3F,0xFF,0x1F,0xC7,0xFF,0xE0,
0x00,0x00,0x1F,0xDF,0xFC,0x7F,0xF7,0xF0,0x00,0x00,0x3F,0xFF,0xF0,0x7F,0xFF,0xE0,
0x00,0x00,0x1F,0x07,0xFF,0xFF,0xD1,0xF0,0x00,0x00,0x3F,0xFF,0xE0,0x3F,0xFF,0xE0,
0x00,0x00,0x1E,0x03,0xFF,0xFF,0x80,0xF0,0x00,0x00,0x3F,0xC0,0x00,0x00,0x07,0xE0,
0x00,0x00,0x1E,0x03,0xFE,0xFF,0xC0,0xF0,0x00,0x00,0x3F,0xE0,0x00,0x00,0x0F,0xE0,
0x00,0x00,0x0C,0x01,0xF8,0x3F,0x80,0xE0,0x00,0x00,0x1F,0xE0,0x00,0x00,0x1F,0xC0,
0x00,0x00,0x0E,0x03,0xF0,0x1F,0xC0,0xE0,0x00,0x00,0x1F,0xF0,0x0F,0xC0,0x1F,0xC0,
0x00,0x00,0x1E,0x03,0xF0,0x1F,0x80,0xE0,0x00,0x00,0x1F,0xFC,0x0B,0x40,0x7F,0xC0,
0x00,0x00,0x7F,0x1F,0xF0,0x1F,0xC3,0xE0,0x00,0x00,0xFF,0xFF,0x0B,0x41,0xFF,0xC0,
0x00,0x00,0xFF,0xFF,0xF0,0x1F,0xF7,0xF0,0x00,0x01,0xFF,0xFF,0xC0,0x0F,0xFF,0xF0,
0x00,0x01,0xFF,0xFF,0xF8,0x3F,0xFF,0xFC,0x00,0x03,0xFF,0xFF,0xF8,0x7F,0xFF,0xF8,
0x00,0x03,0xFE,0x7F,0xFE,0xFF,0xFF,0xFE,0x00,0x07,0xFC,0xFF,0xFF,0xFF,0xFF,0xFC,
0x00,0x07,0xFC,0x1F,0xFF,0xFF,0xF8,0xFE,0x00,0x0F,0xF8,0x3F,0xFF,0xFF,0xF1,0xFC,
0x00,0x0F,0xF8,0x07,0xFF,0xFF,0xE0,0xFF,0x00,0x1F,0xF0,0x0F,0xFF,0xFF,0xC0,0xFE,
0x00,0x0F,0xF8,0x00,0xFF,0xFF,0x00,0x7F,0x80,0x1F,0xF0,0x01,0xFF,0xFE,0x00,0xFF,
0x00,0x1F,0xF0,0x00,0x02,0x00,0x00,0x7F,0x80,0x3F,0xE0,0x00,0x00,0x00,0x00,0x7F,
0x00,0x1F,0xF0,0x00,0x00,0x00,0x00,0x3F,0xC0,0x3F,0xE0,0x00,0x00,0x00,0x00,0x7F,
0x00,0x3F,0xF0,0x00,0x00,0x00,0x00,0x3F,0xC0,0x7F,0xE0,0x00,0x00,0x00,0x00,0x7F,
0x00,0x3F,0xE0,0x00,0x00,0x00,0x00,0x1F,0xE0,0x7F,0xC0,0x00,0x00,0x00,0x00,0x3F,
0x00,0x3F,0xE0,0x00,0x00,0x00,0x00,0x1F,0xE0,0x7F,0xC0,0x00,0x00,0x00,0x00,0x3F,
0x00,0x7F,0xE0,0x01,0xC0,0xE0,0x00,0x1F,0xE0,0xFF,0xC0,0x00,0x70,0xE0,0x00,0x3F,
0x00,0x7F,0xE0,0x03,0xF3,0xF0,0x00,0x1F,0xE0,0xFF,0xC0,0x00,0xF9,0xF0,0x00,0x3F,
0x00,0x7F,0xE0,0x07,0xFF,0xF8,0x00,0x1F,0xE0,0xFF,0xC0,0x01,0xFF,0xF8,0x00,0x3F,
0x00,0x7F,0xE0,0x07,0xFF,0xF8,0x00,0x1F,0xE0,0xFF,0xC0,0x01,0xFF,0xF8,0x00,0x3F,
0x00,0x7C,0xE0,0x07,0xFF,0xF8,0x00,0x1B,0xE0,0xF9,0xC0,0x01,0xFF,0xF8,0x00,0x37,
0x00,0x38,0xF0,0x03,0xFF,0xF0,0x00,0x39,0xE0,0xF1,0xE0,0x00,0xFF,0xF0,0x00,0x73,
0x00,0x30,0x70,0x01,0xFF,0xE0,0x00,0x30,0xC0,0x60,0xE0,0x00,0x7F,0xE0,0x00,0x61,
0x00,0x00,0x78,0x00,0xFF,0xC0,0x00,0x30,0x00,0x00,0xF0,0x00,0x3F,0xC0,0x00,0x60,
0x00,0x00,0x38,0x00,0x7F,0x80,0x00,0x60,0x00,0x00,0x70,0x00,0x1F,0x80,0x00,0xC0,
0x00,0x00,0x1C,0x00,0x3F,0x00,0x00,0xC0,0x00,0x00,0x38,0x00,0x0F,0x00,0x01,0x80,
0x00,0x00,0x0E,0x00,0x1E,0x00,0x00,0x80,0x00,0x00,0x1C,0x00,0x06,0x00,0x01,0x00,
0x00,0x00,0x07,0x00,0x0C,0x00,0x01,0x80,0x00,0x00,0x0E,0x00,0x06,0x00,0x03,0x00,
};12864液晶原理分析2专业—51单片机2010-02-2414:58:05阅读165评论5字号:大中小[转自本人QQ空间发表于2009年09月04日21:52]一、接口引脚(注意并口与串口)
二、接线方式
1、并口直接访问
2、并口间接访问
3、串口访问
三、文本(汉字,字符)输入1、文本显示RAM(DDRAM)文本显示RAM提供8个×4行的汉字空间,当写入文本显示RAM时,可以分别显示CGROM、HCGROM与CGRAM的字型;
根据汉字显示坐标可以很容易地显示汉字以及其它字符~
四、图象输入
1、绘图RAM(GDRAM)
绘图显示RAM提供128×8个字节的记忆空间,在更改绘图RAM时,先连续写入水平与垂直的坐标值,再写入两个字节的数据到绘图RAM,而地址计数器(AC)会对水平地址(X地址)自动加一,当水平地址为0XFH时会重新设为00H;不会对垂直地址做进位自动加1.。在写入绘图RAM的期间,绘图显示必须关闭,整个写入绘图RAM的步骤如下:
1、关闭绘图显示功能。
2、先将水平的位元组坐标(X)写入绘图RAM地址;
再将垂直的坐标(Y)写入绘图RAM地址;
将D15——D8写入到RAM中;
将D7——D0写入到RAM中;
打开绘图显示功能。
绘图显示的缓冲区对应分布请参考“GDRAM坐标”
GDRAM地址坐标对于图象显示,这个地址表才是王道
水平方向X—以字节单位(2字节16位)
垂直方向Y—以位为单位
屏幕分上下两屏,垂直坐标上下屏都为Y:00—1F(也即0X80+Y),以位为单位;水平坐标上半屏为X1:00—07(也即0X80+X1);下半屏为X2:08—0F(也0X80+X2)
由图可以看到水平坐标一个单位是两字节(即16位D15~D0),X地址会自动加1,是直接加一个单位(即两字节16位),比如00—》01(也即0X80+00—》0X80+01),从第一行第一列跳到第一行第二列。
(1)、整屏图象显示程序:voiddisppicture(ucharcode*adder)
{
uinti,j;
//*******显示上半屏内容设置
for(i=0;i<32;i++)
{
write_com(0x80+i);//垂直地址VERTICALADD
write_com(0x80);
//
水平地址HORIZONTALADD
for(j=0;j<16;j++)
//X坐标方向以2字节为单位,Y坐标方向以1位为单位,先连续写入垂直与水平坐标,
{
//再写入两字节数据到GDRAM。这里是这样进行的:i=0时,j=0,1时,写入两字节到垂直(0X80+00)水平(0X80+00)这格(D15~D0)里;然后X坐标地址自增1,地址变为垂直(0X80+00)水平(0X80+01)这格,在j=2,3时写入两字节,………一直到垂直(0X80+00)水平(0X80+07)这格,在j=14,15时写入两字节,此时循环for(j=0;j<16;j++)结束跳出,刚好第一行128位写完数据;然后i++,开始写第二行…
write_data(*adder);
adder++;
}
}
//*******显示下半屏内容设置
for(i=0;i<32;i++)
//
{
write_com(0x80+i);
//SET垂直地址
下半屏的垂直地址中上半屏一样是0X80+Y(Y:00~1F)
write_com(0x88);
//SET水平地址
下半屏的水平地址是从0X80+08=0X88开始的
for(j=0;j<16;j++)
{
write_data(*adder);
adder++;
}
}
}
整屏图形:
……(2)分块图形显示
程序:
voidanti_nor_pic(ucharcpl_sign,ucharmenu_num)
{
uchari,j,x,y;
x=menu_num*3;
//计算图片显示坐标,由坐标图知图片0/1/2/3/4/5的X坐标分别
if(x>6)x--;
//为0X80+(00,03,06,08,0B,0E)
if(menu_num<3)y=16;
//0、1、2号图片Y坐标起始为0X80+16(上半屏从上往下第16行)
elsey=8;
//3、4、5号图片Y坐标起始为0X80+8(下半屏从上往下第8行)
if(cpl_sign==1)display_cnasc(0x82,4,menu_cn[menu_num]);
for(j=0;j<24;j++)
//图片32*24(宽*高),即有24行
{
for(i=0;i<2;i++)
//一张图片在X方向上占两个单位(一个单位即16位两字节)在写
{
//完一个单位后要向下一个单位写,因为这里不是全屏显示,要设定
wr_lcd(comm,0x34);
//关闭绘图显示功能
wr_lcd(comm,0x80+y);
//垂直地址
wr_lcd(comm,0x80+x+i);
//水平地址,事实上这里i可以不要,因为水平地址会自动加1,
wr_lcd(comm,0x30);
//但因为是分块,要有个for(i=0;i<2;i++)的循环。
if(cpl_sign==1)
//图片反选
{
wr_lcd(dat,~menu_pic[menu_num][j*4+i*2]);
//写入一字节
wr_lcd(dat,~menu_pic[menu_num][j*4+i*2+1]);
//再写入一字节
}
else
//正常显示
{
wr_lcd(dat,menu_pic[menu_num][j*4+i*2]);
wr_lcd(dat,menu_pic[menu_num][j*4+i*2+1]);
}
}
y++;
//垂直地址要由软件设定自动加1
if(y==32&&menu_num<3){x+=8;y=0;}
//上下屏切换。0/1/2三幅图Y坐标由16加了
}
//16行,跳入下半屏,水平坐标X变成0X80+08,垂直坐标变成0X80+00
wr_lcd(comm,0x36);
}
分块图形(旁边还未处理)待续……一、ST7920控制IC的LCD12864实现反白显示
从使用手册上可知,扩展指令里的0x03+行号即可实现反白对应行。但是ST7920控制器的128×64点阵液晶其实原理上等同256×32点阵,第三行对应的DDRAM地址紧接第一行;第四行对应的DDRAM地址紧接第二行。所以128×64点阵的液晶执行反白功能时实用意义不大,因为用户对第一行执行反白显示操作时,第三行必然也反白显示;第二行反白,第四行也必然反白。
其实还是有办法做到单行反白的,解决方法就是混用图形显示和字符显示。其理论支持在于:在ST7920中,字符显示的DDRAM和图形的GDRAM是相互独立的,而最后显示到液晶上的结果,是两个RAM中数据的异或。
具体来说:假如某个点上,绘图RAM的没有绘图(数据为0),而字符RAM上有点阵(数据为1),那么异或的结果就是1,也就是说正常显示字符;当字符上RAM没有点阵的时候,异或的结果是0,自然也就不显示了。假如该点上绘图RAM绘图了(数据为1),当字符RAM上有点阵(数据为1时),异或的结果为0,效果就是反白显示;如果字符RAM没有点阵(数据为0时),异或结果为1,效果就是显示绘图的背景。
所以,如果要在某个地方反白显示,那么就在该点绘图并且写字,如果要取消反白,就重新用全0擦掉那个地方的绘图!这样一来可以实现任何地方、任意大小的反白显示,反而比原指令中的单行反白的功能更好更强大。
二、对于整屏既有图象又有文本,则可以用两种方式实现:
1、
首先文本DDRAM写入要写的字符,其余全部空格(即0X00),然后再在没有字符的地方(即非点亮的晶格中,0X00)绘入图象。DDRAM与GDRAM异或后就可以整屏实现图象与文本。参见程序实例1。
2、
首先图象GDRAM绘入要绘的图象,其余全部用con_disp()反白(或显示图象)函数(见程序实例1)写入0X00,然后再在没有图象的地方(即0X00)处写入文本。同样DDRAM与GDRAM异或后就可以整屏实现图象与文本。参见程序实例2.注意:根据最后显示到液晶上的结果,是两个RAM中数据的异或结果,我们可以知道,con_disp()反白(或显示图象)函数只能对文本字符进行反白,而不能对图形进行反白,因为con_disp()反白(或显示图象)函数本身是一个绘图函数,数据是写到GDRAM中去,只能与DDRAM(文本)异或,而不能与GDRAM(图象)异或。那么图象如何反白呢?我们在绘入图象时可以用按位取反符号“~”,如write_data(~date),这样就可以对你要绘入的图象进行取反了!如果用con_disp()反白(或显示图象)函数对GDRAM进行反白,就会出现重叠覆盖现象,如下图:
。。。第一幅图被反白函数覆盖了
//////////////////////////////////////////////////
程序实例1:(con_disp()反白(或显示图象)函数)//反白或显示图片参数格式:(H)8bit数据,(L)8bit数据,X0坐标(16bit),Y0坐标(1bit),X坐标(16bit),Y坐标(1bit)*/
voidcon_disp(uchardata1,uchardata2,ucharx0,uchary0,ucharxl,ucharyl)
{
uchari,j;
for(j=0;j<yl;j++)
{
for(i=0;i<xl;i++)
{
write_com(0x34);
//扩展功能
write_com(y0+j);
//写Y坐标
write_com(x0+i);
//写X坐标
write_com(0x30);
//普通功能
write_data(data1);
write_data(data2);
}
}
write_com(0x36);
//开绘图显示
}
1、这个函数,X0,Y0是左上角坐标,X1,Y1分别是列数(水平坐标)和行数(垂直坐标)。因为水平坐标是以二字节(16位)为单位,一次性要写入两字节(data1,data2),因此如果要反白则(data1,data2都为0XFF),如果要绘图(data1,data2可以为其它,此绘图函数主要用来绘制导航标头的)。
2、写入资料到内部RAM(包括DDRAM、GDRAM等)是基本操作指令,因此之前
要写write_com(0X30);
写DDRAM地址是基本操作指令,因此之前要写write_com(0X30);
写GDRAM地址是扩展操作指令,因此之前要写write_com(0X34);(此时要关绘图显示),然后写完GDRAM数据,最后要开绘图显示write_com(0X36);/////////////////////////////////////////////////////////
程序实例2:(先文本再绘图)///////////////////////////////////////////////////////////
//图片菜单标头
voiddis_title_pic()
{
display_cnasc(0x80,"〓〓");
display_cnasc(0x82,"调
整");
display_cnasc(0x86,"〓〓");
//第一行为文本
display_cnasc(0x90,"
");
//第二行空格(即0X00)
display_cnasc(0x88,"
");
//第三行空格(即0X00)
display_cnasc(0x98,"
");
//第四行空格(即0X00)
}voidmain()
{
init_lcd();
dis_title_pic();
//首先显示图片菜单标头,即先全屏覆盖文本
for(d=0;d<6;d++)
//然后再绘入六幅图片
{
if(d==0)disppicture(1,d);
//disppicture()函数见个人资料12864分析2
else
disppicture(0,d);
}
}
~~~
////////////////////////////////////////////
程序实例3:(先绘图再文本)
/////////////////////////////////////////////
//图片菜单标头
voiddis_title_pic()
{
display_cnasc(0x80,"〓〓");
display_cnasc(0x82,"调
整");
display_cnasc(0x86,"〓〓");
}voidmain()
{
Init_lcd();
for(d=0;d<6;d++)
//绘入图象
{
if(d==0)disppicture(1,d);
//第一幅图反白
else
disppicture(0,d);
//其余不反白
}
con_disp(0x00,0x00,0X80,0x80,8,16);
con_disp(0x00,0x00,0X82,0x80+16,1,16);
con_disp(0x00,0x00,0X85,0x80+16,1,16);
con_disp(0x00,0x00,0X8a,0x80,1,32);
con_disp(0x00,0x00,0X8d,0x80,1,32);
dis_title_pic();
//写入文本}
~~~/////////////////////////////////////////////
程序实例4:对于for(d=0;d<6;d++),我想也可以一个一个拆出来写,试验下反白结果
voiddis_title_pic()
{
display_cnasc(0x80,"〓〓");
display_cnasc(0x82,"调
整");
display_cnasc(0x86,"〓〓");
}voidmain()
{
init_lcd();
disppicture(1,0);
//第一幅图反白显示
disppicture(0,1);
//第二幅图正常显示
disppicture(1,2);
//第三幅图反白显示
disppicture(0,3);//第四幅图正常显示
disppicture(1,4);//第五幅图反白显示
disppicture(0,5);//第六幅图正常显示
con_disp(0x00,0x00,0X80,0x80,8,16);
//GDRAM其余地方写入0X00
con_disp(0x00,0x00,0X82,0x80+16,1,16);
con_disp(0x00,0x00,0X85,0x80+16,1,16);
con_disp(0x00,0x00,0X8a,0x80,1,32);
con_disp(0x00,0x00,0X8d,0x80,1,32);
dis_title_pic();
//写入文本
}
~~1、3、5图反白显示~至此,通过以上绘图原理以、反白原理和四个例程,就可以在12864液晶上任何位置显示图象或文本,可以随意对液晶上任意块块进行反白显示,所以,可以通过12864液晶完成类似MP3显示屏上的各种操作:进入菜单页面,通过按键选择,被选择的模块反白,若MEU键按下刚进入此菜单(比如时钟)下面的页面,然后再进行各种设置……
当然,还有很多问题尚未解决,其中一个:就是单单写入文本(不占全屏),不出现花屏;而单单绘入图象(不占全屏)时,就会出现花屏,见下图……(可能是:绘图GDRAM要写入全屏数据,若只有部分数据,则其余地方芯片不知道写入什么就会随机写入,然后出现花屏;而文本DDRAM本身芯片已经有了一个分块控制。而12864液晶不同的控制芯片具体情况不一样),当然我还不确定,有待以后继续分析……
~~那么右边这块没有花屏的显示是根据程序实例2,3作出来的,运用GDRAM与DDRAM相异或原理,就是把左边花屏处用con_disp()反白(或显示图象)函数全部绘0X00.~~~……好吧,暂时告一段落先……理解到这程度已经死了好大一批脑细胞了……看到工具箱旁边那个LCD12864很久没用了(当初买回来用的时候只是简单地测试了一下),于是萌生了重新写一次接口程序的想法(而且这次要给它加个图片显示的功能),好,说做就做,就用Atmega16和ICCAVR来做吧,最近这MCU和平台用得比较熟练。
马上从书堆里把当初打印出来的中文datasheet给翻了出来,依葫芦画瓢地写了个初始化程序。好,OK。编译通过。于是又写了一个可以自定义从XY坐标值开始输出显示的函数,再次编译,也通过,OK。于是呼马上写了四行简单的字符烧到单片机上试了一下,嘿嘿,一次通过。如下图:
后来在进一步测试的时候也出了点小问题。就是我是使用USBISP烧写器把程序烧写进AVR的(此时实验板由USBISP烧写器供电),想要实现从第一行的第一个字符开始连续显示"0123456789"。刚烧写完程序后能看到LCD12864上正常显示"0123456789",但是把烧写器从实验板上断开连接,单独用USB给实验板供电的时候,LCD的第一行只是显示"123456789",第一个字符消失了……,左思右想地弄了一个多小时后,终于把问题给解决了,就是把初始化程序的延时适当增加了些,真是奇怪。刚开始一直想不通为什么在烧写器供电的情况下就正常显示,而换到USB供电后就出了问题。后来再想想,估计是跟供电有关。在使用USBISP烧写器供电的时候,LCD的背光灯明显比用USB供电的时候来得亮,而且对比度也高很多,看来是因为换到USB供电后,供电不怎么充足,以至于LCD在上电初始化的时候花上了更多的时间去初始化(因为供电低了,功率小了,跑起来有点力不从心,用的时间就久了嘛……我是觉得可以这样去理解的)
接下来呢,就到了有点难度的画图了。当初刚买到12864的时候只是简单测试了字符显示功能,除了因为画图还不需要用到,另外一个原因就是那datasheet上关于画图那部分的内容不怎么看得懂……。现在重新拿起来看,依然一头雾水……。马上上网百度了一下“128647920显示图片”,看到了不少的例子程序,可是……就是没看到有关于这部分功能实现的详细思路和讲解……下载下来的那些程序,基本上没注释,不是说晦涩难懂,但是至少看起来一团糟,让人家不想继续看下去……于是还是硬着头皮去啃那datasheet。上面对于画图这部分的内容是这样讲解的:在仔细研究了上面关于它的X啊Y啊那些坐标的定位啊写满了哪些地址会自增啊哪些不会啊什么的,最后感觉脑袋里有了一种朦胧的概念……哟西,反正不会弄坏,就先随便写个程序试试。
于是乎,嘀咕嘀咕……捣鼓捣鼓……反反复复又弄了一个多小时后,终于摸清了它显示的规律……
LCD12864实现画图功能的思路:
首先,画图指令属于扩充指令集,要使用这些指令必须在12864初始化之后写命令字(0x34????36吧)进入扩充指令集设定状态。
接着要做的事就是指定我们的图片要从哪里写入(即写入的XY坐标,这个是最关键,也是最难理解的部分)。因为我们这里是显示一整个画面的图片,所以我们就从12864的第一个点开始显示。那这个点的坐标是怎么定位的呢?我们往这个点写入数据后,要是接着再写数据,那坐标值会怎样变化呢?首先我们要弄清楚12864究竟是怎么把数据写入到GDRAM(绘图显示RAM)中去的。12864(ST7920驱动芯片)把屏幕分成上下两部分(如上图中把垂直坐标分成了两部分的00~1F)。当我们把坐标值写给LCD后(怎么写后面会说),ST7920控制芯片对LCD屏幕的控制过程可以用下面的图片来表示:(后来发现下面那幅图片有点问题……它这里在水平坐标上的00到0F,应该理解为是同一面的,也就是在12864上,水平坐标00到0F处于同一面,而不是上下屏的关系,[看00行]其实大家只要看箭头,明白控制芯片是按什么顺序写GDRAM的就可以了^_^)
如图片上所标注,在向GDRAM中写入要显示的图片时,我们先指定从X:00、Y:00处(也就是第①处)开始写入数据(如何指定后面会说明),我们先在第①处写图形数据(按照图片所标注,第15位在最左边,第0位在最右边,即在写入的时候LCD会先写高位字节,接着再写低位字节),接着LCD会自动把坐标定位到同一行第②处的开头,此时我们可以接着告诉LCD在这里写入图形数据,依此类推,当我们写满16次后,第00行(包括上半屏和下半屏的)就全写满了。那么我们接下去写入数据会出现什么情况呢?答案是LCD又自动从第00行的第
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- “血氧饱和度”知多少
- 水玻璃花盆行业深度研究报告
- 绩效评价报告审核内容
- 中国五星级酒店行业市场运行态势及投资战略咨询研究报告
- 配音签约合同范本
- 2025年塑料制品项目可行性研究报告
- 露营采购麦德龙合同范本
- 知识产权保护意识在企业中的培养
- 42个微单倍型复合检测体系的构建及法医学应用
- 枣庄市山丘区中小河流洪水淹没模拟及风险分析
- 抗震支架安装工程施工方案范文
- GB/T 45071-2024自然保护地分类分级
- 农业托管合同范例
- 食品中阿维菌素等55种农药最大残留限量
- 保洁部消杀培训
- 口服轮状疫苗知识课件
- 中国脑小血管病诊治指南2023版
- 中国聚乙烯催化剂行业发展状况及需求规模预测研究报告(2024-2030版)
- 新能源汽车驱动电机及控制系统检修课件 学习情境4:电的转换
- 车辆实际使用权协议书范文模板
- 新版加油站全员安全生产责任制
评论
0/150
提交评论