【转载】12864带字库(ST7920控制器)液晶学习
本帖最后由 paradisespace 于 2012-5-21 10:36 编辑关于ST7920控制器的12864液晶,网上资料有很多,但是大部分感觉都有漏洞或者说是错误。本文转载网上zhaoshan413之手,感谢他的无私贡献。真心觉得这篇文章有其分量,在阿莫论坛上貌似没有看到,所以想分享给各位,有不得当之处还望指点。
废话少说,正题吧!
关于ST7920的芯片说明书网上有很多这里就不占有阿莫的资源了,呵呵
一、首先说一下关于驱动函数的书写,这些是液晶显示的基础
一般包括四个函数:
1、写命令函数;
2、写数据函数;
3、读状态函数;
4、读数据函数;
这四个函数并不是必须全部写的,具体要看你实现的功能,如果只是单纯的显示汉字和字符,写命令、写数据、读状态这三个函数就够了,如过你还需要进行一些绘图的操作,那读数据函数也必须书写。
另外关于读状态函数,其实也就是用于判忙操作,我看郭天祥的书里面是这样说的:原则上每次对控制器进行读写操作之前,都必须进行读写检测,由于单片机的操作速度慢于液晶控制器的反应速度,因此可不进行读写检测,或者只进行简短的延时即可。因此,读状态函数也可以不写,只用简短的延时函数替换即可。
1、写操作的编写:
首先看一下时序图
由图可见操作很简单:
1>RS=1(写数据操作);或者RS=0(写命令操作);
2>RW=0;//指明为写操作
3>E=1;
4>DB=data;//data为你要写入的命令或数据值
5>E=0;
以下是我的驱动函数,仅供参考:
/********************************液晶端口定义**************************/
#definelcd_data P0 //数据口
sbitRS = P2^4; //选择寄存器(并行) 0:指令寄存器 1:数据寄存器;
sbitRW = P2^5; //读写控制脚(并行) 0:写入 1:读出
sbitE = P2^6; //读写数据启始脚(并行)
sbitPSB = P2^1; //串并方式选择引脚,0为串行模式,1为8/4位数据口模式
sbitRST = P2^3; //复位引脚
//********************************************************
//延时函数
//********************************************************
void delay(unsigned int k)
{
unsigned int i;
unsigned char j;
for(i=0;i<k;i++)
{
for(j=0;j<10;j++);
}
}
//********************************************************
//延时1ms函数
//********************************************************
void delay_ms(unsigned int k)//延时0.994us,晶振12M
{
unsigned int x,y;
for(x=k;x>0;x--)
for(y=121;y>0;y--);
}
//********************************************************
//写命令函数
//********************************************************
void LcdWcom(unsigned char WCom)
{
delay(1);
RS=0;//指明操作对象为指令寄存器
RW=0; //指明为写操作
E=1;
lcd_data=WCom; //将命令写入总线
E=0;
}
//********************************************************
//写数据函数
//********************************************************
void LcdWdata(unsigned char WData)
{
delay(1);
RS=1; //指明操作对象为数据寄存器
RW=0; //指明为写操作
E=1;
lcd_data=WData; //将数据写入总线
E=0;
}
二、初始化操作
以8位并行操作为例,操作流程图如下:
初始化操作如下:
1>芯片上电;
2>延时40ms以上;
3>复位操作:RST出现一个上升沿(RST=1;RST=0;RST=1;);
4>功能设定;
5>延时100us以上;
6>再次进行功能设定;
7>延时37us;
8>显示开关控制;
9>延时100us以上;
10>清除显示;
11>延时10ms以上;
12>进入点设置;
13>初始化结束;
这里我遇到了一个小问题,我的液晶按照这个顺序进行初始化结果不正确,无法显示,最后我把调整了一下就可以了,调整后的顺序为:清除显示进入点设置显示开关控制,不知道是什么原因,知道的告诉我一声…
//********************************************************
//显示初始化函数
//********************************************************
void Display_Init(void)
{
delay_ms(45); //延时45ms
//PSB=1; //8位并行口
//复位操作
RST=1;
delay(1);
RST=0;
delay(1);
RST=1;
delay(1);
//功能设定
LcdWcom(0x30); //设置为8位并行口,基本指令集
delay(10);
LcdWcom(0x30); //再次设置为8位并行口,基本指令集
delay(5);
// //显示开关控制
// LcdWcom(0x0c); //游标显示关,正常显示,整体显示开
// delay(10);
//清除显示
LcdWcom(0x01);
delay_ms(12); //延时12ms
//进入点设置
LcdWcom(0x06); //设置为游标右移,DDRAM位地址加1,画面不移动
delay(5);
LcdWcom(0x0C); //开显示
}
三、显示基本的字符和汉字
1、要想显示汉字或字符,首先要确定显示的位置,看看芯片说明书上关于屏幕地址的分配:
由于此液晶为128*64,即是横向128个点,竖向64个点,由于该液晶控制器支持的字符为8*16,汉字为16*16,因此只能显示四行,如果是汉字,为每行显示8个,如果是字符,每行显示16个。
由上图设置DDRAM地址的指令可知,最高位为1,余下7位为地址值,因此就对应了为什么起始地址为80H的原因(即对应的写地址指令为1000 0000);
因此如果你要设定显示的地址为第一行的第一个位置,只需要调用写指令函数,写入0x80即可。
存在的问题:参考网上的程序及在试验过程中发现,实际能显示出来的地址分布式这样的
0x800x810x820x830x840x850x860x87 //第一行汉字位置
0x900x910x920x930x940x950x960x97 //第二行汉字位置
0x880x890x8a0x8b0x8c0x8d0x8e0x8f //第三行汉字位置
0x980x990x9a0x9b0x9c0x9d0x9e0x9f //第四行汉字位置
设定DDRAM地址参考程序:
//********************************************************
//设置光标函数
//参数说明:x为行号,y为列号
//********************************************************
void Set_Cursor(unsigned char x, unsigned char y)
{
unsigned char i;
switch(x)//确定行号
{
case 0x00: i=0x80; break;//第一行
case 0x01: i=0x90; break;//第二行
case 0x02: i=0x88; break;//第三行
case 0x03: i=0x98; break;//第四行
default : break;
}
i = y+i;//确定列号
LcdWcom(i);//写地址
}
2、显示字符
由数据手册可查看可以显示的字符及其显示码:
//********************************************************
//设置光标函数
//参数说明:x为行号,y为列号
//********************************************************
void Set_Cursor(unsigned char x, unsigned char y)
{
unsigned char i;
switch(x)//确定行号
{
case 0x00: i=0x80; break;//第一行
case 0x01: i=0x90; break;//第二行
case 0x02: i=0x88; break;//第三行
case 0x03: i=0x98; break;//第四行
default : break;
}
i = y+i;//确定列号
LcdWcom(i);//写地址
}
因此,当你设置好所要显示的光标位置后,即可调用写数据函数,写入对应相应字符的显示码,比如要显示!就应该写入0x21。
//********************************************************
//显示字符函数
//********************************************************
void Disp_Char(unsigned char Alphabet)
{
delay(1);
LcdWdata(Alphabet); //写入需要显示字符的显示码
}
显示!实例:
/**********************显示单个字符*************************/
Set_Cursor(0,0); //光标地址设定
Display_Char(0x21); //显示字符!
扩展程序:在指定位置显示字符串
//********************************************************
//指定位置显示字符串函数
//参数说明:x为行号,y为列号
//********************************************************
void Display_String(unsigned char x,unsigned char y,unsigned char *Alphabet)
{
unsigned char i=0;
Set_Cursor(x,y); //设置显示的起始地址
while(Alphabet!='\0')
{
LcdWdata(Alphabet); //写入需要显示字符的显示码
i++;
}
显示字符串实例:
/***********************显示字符串*************************/
Display_String(1,0,"WWW.CEPARK.COM"); //显示字符串
3、显示汉字
因为一个汉字占用两个字节的大小,因此要想显示一个汉字,需要进行两个数据写入操作。
所支持的8192个16*16的汉字详见数据手册附录中的ST7920GB中文字型码表。
参考程序:
//********************************************************
//指定位置显示汉字函数
//参数说明:x为行号,y为列号
//********************************************************
void Disp_HZ(unsigned char x,unsigned char y,unsigned char *HZ)
{
DispSetCursor(x,y); //设置显示的起始地址
LcdWdata(HZ); //写入需要显示汉字的高八位数据
LcdWdata(HZ); //写入需要显示字符的低八位数据
}
显示汉字实例:
/************************显示汉字*************************/
Display_HZ(0,1,"电"); //显示电
Display_HZ(0,2,"子"); //显示子
Display_HZ(0,3,"园"); //显示园
效果图:
扩展程序:
//********************************************************
//指定位置显示一行汉字函数,可自动换行
//参数说明:x为行号,y为列号
//********************************************************
void Disp_HZ_line(unsigned char x,unsigned char y,unsigned char *HZ)
{
unsigned char i=0;
DispSetCursor(x,y); //设置显示的起始地址
while(HZ!='\0')
{
LcdWdata(HZ); //写入需要显示汉字的高八位数据
LcdWdata(HZ); //写入需要显示字符的低八位数据
if((y+i)%16= =0) //如果满一行
{
x++;
if(x= =4) //如果满一屏
x=0;
DispSetCursor(x,0); //重新设置显示的起始地址
}
}
}
显示一行汉字实例:
/************************显示一行汉字*********************/
Display_HZ_Line(2,0,"欢迎转载,转载请注明出处,谢谢!");//显示一行汉字
效果图:
再来一个整体的现实效果
//**************************************************************************
//说明:程序主函数
//**************************************************************************
void main(void)
{
/***********************液晶初始化***************************/
Display_Init();
/**********************显示单个字符*************************/
Set_Cursor(0,0); //光标地址设定
Display_Char(0x21); //显示字符!
/***********************显示字符串*************************/
Display_String(1,0,"WWW.CEPARK.COM"); //显示字符串
/************************显示汉字*************************/
Display_HZ(0,1,"电"); //显示电
Display_HZ(0,2,"子"); //显示子
Display_HZ(0,3,"园"); //显示园
/************************显示一行汉字*********************/
Display_HZ_Line(2,0,"欢迎转载,转载请注明出处,谢谢!");//显示一行汉字
while(1);
}
函数呢,去那里了。 本帖最后由 paradisespace 于 2012-5-21 10:37 编辑
四、关于CGRAM的使用:
可以参考这个网站的程序: http://bbs.友好站点,请勿转贴.com/ShowTopic.aspx?id=81220 ST7920自行产生RAM提供使用者图像定义(造字)功能,可以提供四组16*16点的自定义图像空间,使用者可以将内部自行没有提供的图像自行定义到CGRAM中,便可以通过DDRAM显示在液晶屏上。注意:网上介绍说ST7920芯片同屏幕不能显示4个以上自定义汉字(用CGRAM)。显示CGRAM字型:将16位元资料写入DDRAM中,一共有0000H,0002H,0004H,0006H四种编码。
操作步骤:
1> 设置为扩充指令集;
2> 设置SR=O,允许设定CGRAM地址;
3> 设置为基本指令集;
4> 循环执行以下操作写入16个字节数据(设定CGRAM的存储地址;写入自定义数据);
5> 设置DDRAM地址
6> 写入显示CGRAM显示码
五、关于GDRAM绘图模式的操作
ST7920提供64×32 个字节的空间(由扩充指令设定绘图RAM 地址),最多可以控制256×64 点阵的二维绘图缓冲空间,在更改绘图RAM时,由扩充指令设置GDRAM地址先垂直地址后水平地址(连续2个字节的数据来定义垂直和水平地址),再2个字节的数据给绘图RAM(先高8位后低8 位)。地址分布如下:
操作步骤:1>设置为扩充指令集,关闭绘图模式;2>写两字节的GDRAM地址,先写垂直地址,后写水平地址地址;3>写入两字节的数据,先写高八位数据,后写低八位数据;4>打开绘图模式;5>设置回基本指令集;
应用实例: /*************************GUI全屏填充********************/
GUI_Fill_GDRAM(0xcc); //竖条显示实物图:
1、打点
打点操作是作图的基础,众所周知,画任何图形均可以由画一个个点来实现。具体打点的操作步骤:1>确定打点的位置;2>读出该点所在的数据值;3>修改该点相应的位的值,对于单色液晶来说,只有两种操作,已是点亮该点,二是熄灭该点;4>将修改后的数据值写入对应的地址;
由于打点首先需要进行读操作,因此需要编写读数据的驱动函数:读操作的编写:时序图:
操作如下:1>释放总线:DB=0;2>RS=1(读数据操作);或者RS=0(读状态操作);3>RW=1;//指明为读操作4> E=1;5>data=DB;//data为存储读回数据的变量6>E=0;读操作参考程序:
打点参考程序:
应用实例:/***************************GUI作图操作**********************/
GUI_Point(64,32,1); //打点操作
应用例子: GUI_HLine(10,120,10,1); //画水平线操作
GUI_RLine(10,10,60,1); //画垂直线操作
任意两点画线:
应用例子: GUI_Line(0,0,127,63,1); //画线操作
画矩形:
应用例子:GUI_Rectangle(5,5,122,58,1); //画矩形操作
填充矩形:
应用例子:GUI_Rectangle_Fill(5,5,122,58,1); //填充矩形操作
画正方形和填充正方形:
应用例子: GUI_Square(10,10,50,1); //画正方形操作
GUI_Square_Fill(20,20,20,1); //填充正方形操作
再来个画圆的程序:
应用例子:GUI_Circle(32,32,30,1); //画圆操作
raymond2011 发表于 2012-5-21 10:01 static/image/common/back.gif
函数呢,去那里了。
在呢,看不到吗?
下面贴出我学习12864液晶后做的一个小综合练习----制作一个模拟电子钟,请大家多提宝贵意见!
这个好,比较全面.顶一个!我一般情况也是这么来的,但不是我的原创,一个朋友给的. 很好,学习收藏了、、 很好,谢谢 很好,顶一下 本帖最后由 jetli 于 2012-5-21 16:19 编辑
{:victory:} bucuo {:handshake:}
--------------------------------------------------
看了下,是并行读写st7920的,没有发挥它仅要2根数据线的 的串行模式优势。
有米有,串行模式的,点、线、圈等基本函数使用? jetli 发表于 2012-5-21 16:04 static/image/common/back.gif
bucuo
--------------------------------------------------
看了下,是并行读 ...
嗯嗯嗯,是并行的 收藏了,楼主有没有串行的啊? 留着有空看看 我就看看,不说话 谢谢楼主的无私分享啊 非常全面,谢谢LZ辛苦搬运,其实网上有的牛人的博客等是非常有分量的,很详细,可以让我们这些晚辈少走很多弯路 工作需要了解ST7920,这帖子不错~! narcissus8912 发表于 2012-8-31 16:56 static/image/common/back.gif
工作需要了解ST7920,这帖子不错~!
好东西必须分享,哈哈哈 学习了,谢谢! 好 顶起! 多谢分享! paradisespace 发表于 2012-5-21 10:42 static/image/common/back.gif
下面贴出我学习12864液晶后做的一个小综合练习----制作一个模拟电子钟,请大家多提宝贵意见!
比较详细喔! 开不错!!!!!!! 很好,学习收藏了、、 感谢楼主 ,,, 因为工作关系 我也经常用到各种各种LCD屏 很多时候买回来的屏 他附送的PDF文档里面范例程序都是有问题的,,要不就是时序有问题 要不就是读写的子函数有问题,,反正各种各种的纠结我都遇到过,,,,,所以在这里提醒各位 ,,写LCD屏的时候不要全信PDF上面的范例啊 一定要自己对照一遍,,,,血的教训啊,,,,,,根据经验来看 我们写LCD的时候完全不用去判忙,,判忙很多时候都会出现问题的,程序很多时候会死在读忙那里,,其实完全没有必要这样,,读写的时候在前面加一个短延时 完全可以代替判忙,,测试过完全没有问题 lcd显示不会出现错误 而且很稳定 lihebb 发表于 2012-9-23 11:03 static/image/common/back.gif
感谢楼主 ,,, 因为工作关系 我也经常用到各种各种LCD屏 很多时候买回来的屏 他附送的PDF文档里面范例程 ...
范例程序网上泛滥的同时也导致了各种蛋疼,理性分析,感谢分享心得 12864这块屏用得真的是挺多的!多谢转载 正在学习中…… 收藏,学习 mark!谢谢楼主分享 有木有反白的? 我有两只,由于不会用,扔了,为何我不早点看到这贴? 很好,很强大!值得学学 谢谢楼主了 标记学习 谢谢楼主的无私分享,正是新手们所需要的。向楼主致敬 在学习,向牛人们致敬! 叫厂家做的LCD屏,还没有提供驱动,驱动还要自己写,就算他们提供的东西,其实有时也不能用,只能自己搞 {:smile:}
不知道串口可不可以读数据? 很好的资料,学习正好需要,谢谢楼主分享! 楼主的这个对我很有帮助!必须顶 学习中。。。 继续学习 这个好~~功能强大 谢谢楼主的分享。不错~ 很不错,收藏了!!!! paradisespace 发表于 2012-5-21 10:42
下面贴出我学习12864液晶后做的一个小综合练习----制作一个模拟电子钟,请大家多提宝贵意见!
谢谢分享学习资料。另外请教一下单字符在任意位置显示怎么做(比如0x80位置显示一个汉字,此位置可以显示两个字符,显示第一个字符的地址是0x80,第二个字符的位置地址是多少)?或者是画图从任意位置开始怎么做? 好东西,谢谢分享! 指端轻语 发表于 2013-6-8 16:06 static/image/common/back.gif
谢谢分享学习资料。另外请教一下单字符在任意位置显示怎么做(比如0x80位置显示一个汉字,此位置可以显示 ...
指端轻语 你好
我现在也碰到这个问题,想任意位置显示数字,却实现不了,这个问题你解决了吗? tuowai 发表于 2013-7-19 22:46 static/image/common/back.gif
指端轻语 你好
我现在也碰到这个问题,想任意位置显示数字,却实现不了,这个问题你解决了吗? ...
没有解决,但是我有一个想法只是没有试过。液晶有读指令,可不可以随时读出地址然后再在这个地址写数据···· 很详细的资料,感谢楼主分享~~~ 谢谢分享 这个真心不错啊 学到很多。谢LZ MARK jetli 发表于 2012-5-21 16:04 static/image/common/back.gif
bucuo
--------------------------------------------------
看了下,是并行读 ...
都是一样的,只不过是吧连接方式改成串行驱动罢了。 很详细具体啊,收藏了,手里正好有ST7920的,回头用串口,图形方式试试 好帖,找了好久才看见这么详细的,学习中。{:smile:} 很实用,好好学习一下。
非常不错,,,,极品哦!!!!!!!赶紧收藏了吧,弱弱的问下,有没有st7565或者uc1701x这种控制器的画点画线函数?? 很好,如果是串行的驱动就更好了 想当年也是这样学习下来的啊 非常感谢LZ 学习了 手机标记,回头学习! paradisespace 发表于 2012-5-21 10:42
下面贴出我学习12864液晶后做的一个小综合练习----制作一个模拟电子钟,请大家多提宝贵意见!
谢谢。。。。。 很详细的资料,学习一下。 lswhome 发表于 2014-1-27 15:40
非常不错,,,,极品哦!!!!!!!赶紧收藏了吧,弱弱的问下,有没有st7565或者uc1701x这种控制器的画 ...
浙江李啊,有的,哈哈 不错,谢谢楼主无私分享 感谢!学习了! 收藏了,感谢楼主的分享,最近正要研究12864 很好的资料,多谢楼主分享! 做个标记,电脑再看 这个好,比较全面 驱动很全,收藏了! 128 64标记下
对我起到了帮助,非常感谢! 好東西!!收下了~~~~ 好全面,果断收藏 很好地学习12864了。 好东西啊!!!!!! 谢谢了东西收下了 很好,谢谢 做个标记,慢慢看。
留着有空看看 很详细的资料,学习一下。
页:
[1]