上一回:通俗话教你单片机之【串口】篇,有蓝牙控制技术哦:
http://bbs.mydigit.cn/read.php?tid=534747
这次讲点什么好呢?讲个 1602 液晶显示器吧。
1602液晶显示器指的是一种可以显示2行且每行可以显示16个字符的一种液晶显示器,所以1602最多能显示
16*2=32 个字符
至于其工作原理小七就不说了,大家可以自己查询百度来深入研究(百科:
http://baike.baidu.com/view/5881209.htm),在这里我只做个简单的例子,让大伙能够使用它,至于如何更深入,更高级的应用它,这就由大家以后深入去研究啦!
我们一般买来的时候是这个样子,简单的说,1602 就像一块黑板,它有两种操作,一种是对黑板本身进行操作,比如檫黑板,设置黑板的显示方式,另一种是显示操作,即在黑板上写字并显示出来。我们先看这玩意儿怎么接线先:
从右边数到左边,接线的定义一般如下(具体要看店家给的说明书哦)
第③脚是调节液晶屏的对比度的。
第④脚 RS 是用来判断传给它的数据是用来控制它呢(RS=0 低电平),还是要用来显示的(RS=1 高电平)。 第⑤脚是读写控制,一般我们不需要从液晶读取数据,所以我们把它
接地即可。
第⑥脚是 使能引脚 EN ,当其引脚由高电平变成低电平时读取外部传过来的数据,也就是先让 en = 1,再 en=0,LCD就会从外部读取数据,并执行它。
第⑦-⑩引脚是用来传输数据的8位数据总线,我们要传给它的命令和数据都是通过这条通道传给它的。
我们对1602的操作基本上就这两种: 在
命令模式下写入控制命令对1602进行设置 和 在
显示模式下传入要显示的数据给它显示。首先先看显示模式,我们把1602 看成是一个拥有两层,每层有16个格子的展示板,我们把每个格子都编上编号,如下表:
假如我们要在 1602 的第1行第1列的位置上(如上表的00H位置,H代表这个是十六进制的数据,即00H就代表0x00)显示一个 “7” ,那么我们是不是只需要往 00H 这个格子送入“7”的数据就可以显示啦?理论上说是对的,但实际上我们需要在 00H的位置上再加上 80H 才是显示在第1行第1列的位置(即第1行第1列的真正位置是
0x00+0x80=0x80),这是因为某些原因导致的,我们暂时不需要知道这些,其他的用到的时候再去研究。同理,我想在第2行的第1列显示一个7,那么我就要往
0x40+0x80=C0H 的地址送入“7”的数据就可以啦。
是不是很晕?其实你只要记住下面的东西就OK了:
第1行第1列的地址为 0x80 ,第2,3……列的地址为0x80 +1 ,+2,+3 ……
第2行第1列的地址为 0xc0 ,同上 0xc0 + 1,+2,+3……
接下来我们研究改如何控制这个 1602 ,让它执行我们给他的指令,首先是擦黑板(清屏,清空所有内容),在 1602 里面,我们传给它的命令是放在一个小格子里面的,在厂家给的说明书里面有这么一个表格,其中有“清屏”这个命令,我们发现除了DB0 那个格子是1外,其他的都是零,即二进制的 00000001,转换成16进制就是 0x01 ,那么我们只要把 0x01 在命令模式的时候传给它,它就会清空屏幕。
除此之外,还有
0x38 是把1602设置为 8位数据,双列,5*7字形 的显示模式;
0x0c 是关闭光标功能;
0x06 是自动递增显示地址(即我这次给40H传入“1”,下次传“2”的时候就不用设置地址 41H 了,它会自动帮你设置为下一个),除了这些,还有很多命令,大家可以通过百度或者在说明书中找到。
好啦,讲了那么多,下面该是实践得真知的时候了。比如我们要用它的第1行第1列显示一个字母“A”,该怎么做呢?首先我们要对1602进行设置,打开命令模式,传入指令让它初始化,完成后再传入要显示的数据:
① 设置为8位数据,双列,5*7字形 的显示模式;
② 设置为关闭光标功能;
③ 清空屏幕,完成初始化;
④ 传入要显示的数据 A,并显示出来。
那么程序该如何写呢?我们先来写一个专门向 1602 写控制命令或者显示数据的函数。我们发现当 RS =0时,传给它的数据就是控制液晶的,当RS=1时,传给它的数据就是用来显示的,因此我们可以让它们共用一个函数,如果是要写入控制命令,就让RS=0即可,如果是写入显示数据,就让RS=1,所以程序可以这样写:
根据上面画的接线图,在程序里定义lcd的控制引脚所接的位置,由于小七忘记把面包板连线带回家了,所以这次就只能用开发板来实验了,这个rs 和en是小七的开发板上接好的,大家可以根据实际情况进行更改,8位数据脚小七接在P0口,大家也可以改为其他的,比如P1。
- #include <reg52.h>
- sbit lcd_rs = P3^5; //定义 数据/命令 写入模式控制引脚 RS
- sbit lcd_en = P3^4; //定义 数据使能 控制引脚
- void delay(unsigned char n) //延时函数,lcd反应跟不上单片机,所以要单片机延时等待lcd
- {
- unsigned char x,y;
- for(x=n;x>0;x--)
- for(y=110;y>0;y--);
- }
-
- void lcd_wrt(unsigned char dat,bit rs) //向lcd写入数据,dat是数据,rs用来判断该传入的是命令还是显示数据
- {
- if(rs==1) //若 rs 的值为1,则
- lcd_rs = 1; //lcd_rs = 1 表示将要传给它的数据是用来显示的
- else //若 rs 的值不为1,则
- lcd_rs = 0; //lcd_rs = 0 表示这个数据是用来控制液晶屏的
-
- P0 = dat; //假设我们lcd的8根数据线接在单片机的 P1 口,则把传过来的 dat 的值送到P1口,即P1口的状态等于dat变量的值(16进制)
-
- delay(5); //由于lcd的反应速度比较慢,跟不上单片机,所以延时一小会儿,让单片机等它把数据写完
- lcd_en = 1; //当lcd的 en 引脚从高电平变成低电平时,lcd会接收从P1口传过来的数据
- lcd_en = 0;
- }
这样我们就可以通过这个函数向lcd写入命令来控制它,或者写入显示数据让它显示出来了,比如写入清屏命令:
lcd_wrt(0x01,0) 0x01 就是清屏命令,0就是代表写入的数据是命令
lcd_wrt(‘A’,1) A 就是要显示的字母,1就是代表写入的数据是用来显示的
是不是有点晕?没关系,我们用例子来说明。比如,我们让lcd显示一个大写字母 A
完整的代码如下:
- #include <reg52.h>
- sbit lcd_rs = P3^5; //定义 数据/命令 写入模式控制引脚
- sbit lcd_en = P3^4; //定义 数据使能 控制引脚
-
- void delay(unsigned char n) //延时函数,lcd反应跟不上单片机,所以要单片机延时等待lcd
- {
- unsigned char x,y;
- for(x=n;x>0;x--)
- for(y=110;y>0;y--);
- }
-
- void lcd_wrt(unsigned char dat,bit rs) //向lcd写入数据,dat是数据,rs是判断该数据是命令还是用来显示的数据
- {
- if(rs==1) //若 key 的值为1,则
- lcd_rs = 1; //rs = 1 表示将要传给它的数据是用来显示的数据
- else //若 key 的值不为1,则
- lcd_rs = 0; //rs = 0 表示这个数据是用来控制液晶屏的
-
- P0 = dat; //假设我们lcd的8根数据线接在单片机的 P0 口,则把数据送到P0口,即P0口的状态等于dat变量的值(16进制)
-
- delay(5); //由于lcd的反应速度比较慢,跟不上单片机,所以延时一小会儿
- lcd_en = 1; //当lcd的 en 引脚从高电平变成低电平时,lcd会接收从P1口传过来的数据
- lcd_en = 0;
- }
- void main()
- {
- lcd_wrt(0x38,0); //向lcd_rs写入 0x38 命令,0x38 命令代表设定lcd为两行显示模式,0代表写入的数据是控制命令
- lcd_wrt(0x0c,0); //设定lcd不显示光标
- lcd_wrt(0x06,0); //设定lcd自动把显示地址递增,比如第1次在第1行第2列显示了字符 A,那么下次写入字符 B ,lcd会自动把它显示在第一行第二列
- lcd_wrt(0x01,0); //清空屏幕,把黑板擦干净
- lcd_wrt(0x80,0); //设定第1个字符显示在第1行第1列,后面的会递增
- lcd_wrt(‘A’,1); //让lcd显示字母A,1表示传入的数据是显示数据
- while(1); //暂停程序,让我们看看lcd能不能显示出来
- }
编译并下载到单片机,根据代码的定义,把1602 液晶接到单片机上,我们可以看到LCD已经按我们的要求在第1行第1列的位置显示了一个字母 A 了,如果我们再向它写入一个字符 B ,那么它就会自动在第1行第2列显示一个字母 B 了。假如我们要改变显示的位置,比如第一个字母A显示在第一行第7列,那么可以这样写
lcd_wrt(0x80+7,0); //写入控制命令,改变显示的位置
lcd_wrt(‘A’,1); //写入要显示的数据
因为第1行第1列是 0x80 ,那么第7个当然就是 0x80 + 7 的位置啦!
同理,第2行第1列的地址是 0xc0 ,第七个就是 0xc0 + 7
上面的代码只能显示一个字符呀!如果我要显示一串的字符怎么办?那就for 循环语句把字符一个一个的送到lcd 让它显示。我们把上面的main 主函数改动一下,其他不变
完整代码如下:
- #include <reg52.h>
- sbit lcd_rs = P3^5; //定义 数据/命令 写入模式控制引脚 RS
- sbit lcd_en = P3^4; //定义 数据使能 控制引脚
- void delay(unsigned char n) //延时函数,lcd反应跟不上单片机,所以要单片机延时等待lcd
- {
- unsigned char x,y;
- for(x=n;x>0;x--)
- for(y=110;y>0;y--);
- }
-
- void lcd_wrt(unsigned char dat,bit rs) //向lcd写入数据,dat是数据,rs是判断该数据是命令还是用来显示的
- {
- if(rs==1) //若 key 的值为1,则
- lcd_rs = 1; //rs = 1 表示将要传给它的数据是用来显示的
- else //若 key 的值不为1,则
- lcd_rs = 0; //rs = 0 表示这个数据是用来控制液晶屏的
-
- P0 = dat; //假设我们lcd的8根数据线接在单片机的 P1 口,则把传过来的 dat 的值送到P1口,即P1口的状态等于dat变量的值(16进制)
-
- delay(5); //由于lcd的反应速度比较慢,跟不上单片机,所以延时一小会儿,让单片机等它把数据写完
- lcd_en = 1; //当lcd的 en 引脚从高电平变成低电平时,lcd会接收从P1口传过来的数据
- lcd_en = 0;
- }
- void main()
- {
- unsigned char code ss[]=" www.mydigit.cn "; //定义一个叫ss的数组,存放有16个字符
- unsigned char code kk[]=" ID:satelives ";
- int i;
-
- lcd_wrt(0x38,0); //向lcd_rs写入 0x38 命令,0x38 命令代表设定lcd为两行显示模式,0代表写入的数据是控制命令
- lcd_wrt(0x0c,0); //设定lcd不显示光标
- lcd_wrt(0x06,0); //设定lcd自动把显示地址递增,比如第一次在第一行第一列显示了字符 A,那么下次写入字符 B ,lcd会自动把它显示在第一行第二列
- lcd_wrt(0x01,0); //清空屏幕,把黑板擦干净
- /*******************这里是第一行*************************/
- lcd_wrt(0x80,0); //设定第一个字符显示在第一行第一列,后面的会递增
- for(i=0;i<16;i++) //循环16次,把数组里面的东西依次传给LCD
- {
- lcd_wrt(ss[i],1); //让lcd显示ss数组里面的第i个字符,1表示传入的数据是显示数据
- }
- /*******************这里是第二行*************************/
- lcd_wrt(0xc0,0); //设定第一个字符显示在第2行第1列,后面的会递增
- for(i=0;i<16;i++) //循环16次,把数组里面的东西依次传给LCD
- {
- lcd_wrt(kk[i],1); //让lcd显示kk数组里面的第i个字符,1表示传入的数据是显示数据
- }
- while(1); //暂停程序,让我们看看lcd能不能显示出来
- }
好了,由于找不到比较好的比喻,因此本次的介绍不是很通俗,如不能理解的请各位看官多看几遍,自己动手实践一下,相信大家都成功的玩转 1602 LCD的
下一回:让编程更简洁高效之模块化编程传送门:
http://bbs.mydigit.cn/read.php?tid=536508