切换到宽版
  • 24566阅读
  • 55回复

小七又更新啦:通俗话教你单片机之【LCD 1602】篇 [复制链接]

上一主题 下一主题
离线satelives
 

发帖
493
M币
12410
专家
106
粉丝
9432
只看楼主 倒序阅读 我要置顶 楼主  发表于: 2013-01-25
上一回:通俗话教你单片机之【串口】篇,有蓝牙控制技术哦: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。


  1. #include <reg52.h>
  2. sbit lcd_rs = P3^5;    //定义 数据/命令 写入模式控制引脚 RS
  3. sbit lcd_en = P3^4;    //定义 数据使能 控制引脚
  4. void delay(unsigned char n)    //延时函数,lcd反应跟不上单片机,所以要单片机延时等待lcd
  5. {
  6.   unsigned char x,y;
  7.   for(x=n;x>0;x--)
  8.   for(y=110;y>0;y--);
  9. }
  10.     
  11. void lcd_wrt(unsigned char dat,bit rs)    //向lcd写入数据,dat是数据,rs用来判断该传入的是命令还是显示数据
  12. {
  13.   if(rs==1)     //若 rs 的值为1,则
  14.     lcd_rs = 1;    //lcd_rs = 1 表示将要传给它的数据是用来显示的
  15.   else          //若 rs 的值不为1,则
  16.     lcd_rs = 0;    //lcd_rs = 0 表示这个数据是用来控制液晶屏的
  17.         
  18.   P0 = dat;    //假设我们lcd的8根数据线接在单片机的 P1 口,则把传过来的 dat 的值送到P1口,即P1口的状态等于dat变量的值(16进制)
  19.     
  20.   delay(5);   //由于lcd的反应速度比较慢,跟不上单片机,所以延时一小会儿,让单片机等它把数据写完
  21.   lcd_en = 1;        //当lcd的 en 引脚从高电平变成低电平时,lcd会接收从P1口传过来的数据
  22.   lcd_en = 0;
  23. }


这样我们就可以通过这个函数向lcd写入命令来控制它,或者写入显示数据让它显示出来了,比如写入清屏命令:


lcd_wrt(0x01,0)    0x01 就是清屏命令,0就是代表写入的数据是命令
lcd_wrt(‘A’,1)        A 就是要显示的字母,1就是代表写入的数据是用来显示的

  是不是有点晕?没关系,我们用例子来说明。比如,我们让lcd显示一个大写字母 A

  完整的代码如下:
  1. #include <reg52.h>
  2. sbit lcd_rs = P3^5;    //定义 数据/命令 写入模式控制引脚
  3. sbit lcd_en = P3^4;    //定义 数据使能 控制引脚
  4.   
  5. void delay(unsigned char n)    //延时函数,lcd反应跟不上单片机,所以要单片机延时等待lcd
  6. {
  7. unsigned char x,y;
  8. for(x=n;x>0;x--)
  9.    for(y=110;y>0;y--);
  10. }
  11.   
  12. void lcd_wrt(unsigned char dat,bit rs)    //向lcd写入数据,dat是数据,rs是判断该数据是命令还是用来显示的数据
  13. {
  14.  if(rs==1)         //若 key 的值为1,则
  15.    lcd_rs = 1;    //rs = 1 表示将要传给它的数据是用来显示的数据
  16. else               //若 key 的值不为1,则
  17.    lcd_rs = 0;    //rs = 0 表示这个数据是用来控制液晶屏的
  18.           
  19.  P0 = dat;            //假设我们lcd的8根数据线接在单片机的 P0 口,则把数据送到P0口,即P0口的状态等于dat变量的值(16进制)
  20.       
  21.  delay(5);            //由于lcd的反应速度比较慢,跟不上单片机,所以延时一小会儿
  22.  lcd_en = 1;        //当lcd的 en 引脚从高电平变成低电平时,lcd会接收从P1口传过来的数据
  23.  lcd_en = 0;
  24. }
  25. void main()
  26. {
  27.  lcd_wrt(0x38,0);    //向lcd_rs写入 0x38 命令,0x38 命令代表设定lcd为两行显示模式,0代表写入的数据是控制命令
  28.  lcd_wrt(0x0c,0);    //设定lcd不显示光标
  29.  lcd_wrt(0x06,0);    //设定lcd自动把显示地址递增,比如第1次在第1行第2列显示了字符 A,那么下次写入字符 B ,lcd会自动把它显示在第一行第二列
  30.   lcd_wrt(0x01,0);    //清空屏幕,把黑板擦干净
  31.  lcd_wrt(0x80,0);    //设定第1个字符显示在第1行第1列,后面的会递增
  32.   lcd_wrt(‘A’,1);        //让lcd显示字母A,1表示传入的数据是显示数据
  33.  while(1);            //暂停程序,让我们看看lcd能不能显示出来
  34.   }





  编译并下载到单片机,根据代码的定义,把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 主函数改动一下,其他不变

完整代码如下:


  1. #include <reg52.h>
  2. sbit lcd_rs = P3^5;    //定义 数据/命令 写入模式控制引脚 RS
  3. sbit lcd_en = P3^4;    //定义 数据使能 控制引脚
  4. void delay(unsigned char n)    //延时函数,lcd反应跟不上单片机,所以要单片机延时等待lcd
  5. {
  6.     unsigned char x,y;
  7.     for(x=n;x>0;x--)
  8.         for(y=110;y>0;y--);
  9. }
  10.     
  11. void lcd_wrt(unsigned char dat,bit rs)    //向lcd写入数据,dat是数据,rs是判断该数据是命令还是用来显示的
  12. {
  13.     if(rs==1)            //若 key 的值为1,则
  14.   lcd_rs = 1;        //rs = 1 表示将要传给它的数据是用来显示的
  15.     else                //若 key 的值不为1,则
  16.   lcd_rs = 0;        //rs = 0 表示这个数据是用来控制液晶屏的
  17.         
  18.     P0 = dat;    //假设我们lcd的8根数据线接在单片机的 P1 口,则把传过来的 dat 的值送到P1口,即P1口的状态等于dat变量的值(16进制)
  19.     
  20.     delay(5);    //由于lcd的反应速度比较慢,跟不上单片机,所以延时一小会儿,让单片机等它把数据写完
  21.     lcd_en = 1;        //当lcd的 en 引脚从高电平变成低电平时,lcd会接收从P1口传过来的数据
  22.     lcd_en = 0;
  23. }
  24. void main()
  25. {
  26.     unsigned char code ss[]=" www.mydigit.cn ";    //定义一个叫ss的数组,存放有16个字符
  27.     unsigned char code kk[]="  ID:satelives  ";
  28.     int i;
  29.         
  30.     lcd_wrt(0x38,0);    //向lcd_rs写入 0x38 命令,0x38 命令代表设定lcd为两行显示模式,0代表写入的数据是控制命令
  31.     lcd_wrt(0x0c,0);    //设定lcd不显示光标
  32.     lcd_wrt(0x06,0);    //设定lcd自动把显示地址递增,比如第一次在第一行第一列显示了字符 A,那么下次写入字符 B ,lcd会自动把它显示在第一行第二列
  33.     lcd_wrt(0x01,0);    //清空屏幕,把黑板擦干净
  34. /*******************这里是第一行*************************/
  35.   lcd_wrt(0x80,0);    //设定第一个字符显示在第一行第一列,后面的会递增
  36.   for(i=0;i<16;i++)    //循环16次,把数组里面的东西依次传给LCD
  37.   {
  38.       lcd_wrt(ss[i],1);    //让lcd显示ss数组里面的第i个字符,1表示传入的数据是显示数据
  39.   }
  40. /*******************这里是第二行*************************/
  41.   lcd_wrt(0xc0,0);    //设定第一个字符显示在第2行第1列,后面的会递增
  42.   for(i=0;i<16;i++)    //循环16次,把数组里面的东西依次传给LCD
  43.   {
  44.     lcd_wrt(kk[i],1);    //让lcd显示kk数组里面的第i个字符,1表示传入的数据是显示数据
  45.   }
  46. while(1);            //暂停程序,让我们看看lcd能不能显示出来
  47. }





    好了,由于找不到比较好的比喻,因此本次的介绍不是很通俗,如不能理解的请各位看官多看几遍,自己动手实践一下,相信大家都成功的玩转 1602 LCD的



下一回:让编程更简洁高效之模块化编程
传送门:http://bbs.mydigit.cn/read.php?tid=536508
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖最近打赏记录:共21条打赏 ,M币+125 ,专家+1
离线qianglong

发帖
214
M币
255
专家
2
粉丝
11
只看该作者 1楼 发表于: 2013-01-25
请登录后查看

发帖
1724
M币
69
专家
1
粉丝
95
只看该作者 2楼 发表于: 2013-01-25
请登录后查看
离线nokia5320

发帖
8003
M币
4107
专家
13
粉丝
163
只看该作者 3楼 发表于: 2013-01-25
请登录后查看
本帖最近打赏记录:共1条打赏 ,M币+3
离线5x54
发帖
335
M币
2145
专家
7
粉丝
73
只看该作者 4楼 发表于: 2013-01-25
请登录后查看
离线nono鎶

发帖
619
M币
90
专家
2
粉丝
10
只看该作者 5楼 发表于: 2013-01-25
请登录后查看

发帖
304
M币
4460
专家
4
粉丝
45
只看该作者 6楼 发表于: 2013-01-25
请登录后查看
离线easterndigi

发帖
415
M币
4398
专家
14
粉丝
134
只看该作者 7楼 发表于: 2013-01-26
回 3楼(nokia5320) 的帖子
请登录后查看
离线chenppo

发帖
2019
M币
258
专家
27
粉丝
142
只看该作者 8楼 发表于: 2013-01-26
请登录后查看
离线baiwenlongba

发帖
2126
M币
6458
专家
9
粉丝
85
只看该作者 9楼 发表于: 2013-01-26
请登录后查看
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
快速回复
限80 字节
温馨提示:欢迎交流讨论,请勿发布纯表情、纯引用等灌水帖子;以免被删除
 
上一个 下一个