找回密码
 立即注册
首页 业界区 业界 51单片机_LCD1602液晶显示

51单片机_LCD1602液晶显示

山芷兰 前天 23:15
51单片机_LCD1602液晶显示

仿真电路图:
1.png

一、 LCD1602 简介

2.png

3.png

普中开发板原理图:
4.png

5.png

6.png

7.png

DDRAM(显示数据RAM)地址映射

LCD1602内部有80字节的DDRAM,但只有前32字节对应到实际显示位置:
行号物理位置DDRAM地址(十六进制)实际显示地址(写入命令)说明第1行1-16字符0x00 - 0x0F0x80 + 列号 (0x80-0x8F)标准显示区域第1行17-40字符0x10 - 0x270x90 - 0xA7不显示,但可用于滚动第2行1-16字符0x40 - 0x4F0xC0 + 列号 (0xC0-0xCF)标准显示区域第2行17-40字符0x50 - 0x670xD0 - 0xE7不显示,但可用于滚动实际使用的显示地址表格
第一行显示地址(从0开始计数):

列位置实际地址命令值备注第1列0x000x80第一行起始第2列0x010x81第3列0x020x82第4列0x030x83第5列0x040x84第6列0x050x85第7列0x060x86第8列0x070x87第9列0x080x88第10列0x090x89第11列0x0A0x8A第12列0x0B0x8B第13列0x0C0x8C第14列0x0D0x8D第15列0x0E0x8E第16列0x0F0x8F第一行末尾第二行显示地址(从0开始计数):
列位置实际地址命令值备注第1列0x400xC0第二行起始第2列0x410xC1第3列0x420xC2第4列0x430xC3第5列0x440xC4第6列0x450xC5第7列0x460xC6第8列0x470xC7第9列0x480xC8第10列0x490xC9第11列0x4A0xCA第12列0x4B0xCB第13列0x4C0xCC第14列0x4D0xCD第15列0x4E0xCE第16列0x4F0xCF第二行末尾地址确定原理

为什么地址是0x80+列号?
LCD1602的指令集中规定:

  • 设置DDRAM地址的命令格式:1 A6 A5 A4 A3 A2 A1 A0
  • 二进制:1xxxxxxx,所以最高位始终为1
  • 十六进制:0x8x(第一行)或0xCx(第二行)
地址相关的重要指令

指令二进制十六进制功能说明清屏0000 00010x01清除显示,地址归0归位0000 00100x02地址归0,显示回原位进入模式0000 01100x06地址自动递增,显示不移显示开关0000 11000x0C显示开,光标关,闪烁关功能设置0011 10000x388位数据,2行显示,5×8点阵地址设置1xxx xxxx0x8x或0xCx设置DDRAM地址指令集(11条指令):

表1
8.png

(1)指令1:清屏。指令码01H,光标复位到地址00H。
(2)指令2:光标复位。光标复位到地址00H。
(3)指令3:输入方式设置。
其中,I/D表示光标的移动方向,高电平右移,低电平左移;S表示显示屏上所有文字是否左移或右移,高电平表示有效,低电平表示无效。
(4)指令4:显示开关控制。
其中,D用于控制整体显示的开与关,高电平表示开显示,低电平表示关显示;C用于控制光标的开与关,高电平表示有光标,低电平表示无光标;B用于控制光标是否闪烁,高电平闪烁,低电平不闪烁。
(5)指令5:光标或字符移位控制。
其中,S/C表示在高电平时移动显示的文字,低电平时移动光标。
(6)指令6:功能设置命令。
其中,DL表示在高电平时为4位总线,低电平时为8位总线;N表示在低电平时为单行显示,高电平时双行显示;F表示在低电平时显示5×7的点阵字符,高电平时显示5×10的点阵字符。
(7)指令7:字符发生器RAM地址设置。
(8)指令8:DDRAM地址设置。
(9)指令9:读忙信号和光标地址。
其中,BF为忙标志位,高电平表示忙,此时模块不能接收命令或数据,如果为低电平则表示不忙。
(10)指令10:写数据。
(11)指令11:读数据。
常用指令:
0x80+0xdd:dd为地址,这条命令用于设置显示起点坐标
0x0c :开显示,无光标,光标不闪烁 。一般做带键盘输入的才加入光标,如计算器。常用的计量显示不显示光标。
0x06 :写一个数据,地址指针加1,由1602地址表可以看出,实际上就是设置成从左往右写数据而已。
0x38 : 设置显示模式,16x2显示 5x7点阵,8位数据接口。端口不够用时,这个命令也可以换用4位数据接口的。
0x01 :清屏。
表2
9.jpeg

二、显示原理

10.jpeg

如上图,每个字符由 5X8 点阵组成(也可选用 5X10),想要实现显示,只需如下图:
例:以 5X7 点阵为例, 显示字符 A
0 代表灭,1 代表亮
只需将想要显示的字符的对应位置1,就能显示该字符
11.png

LCD1602 固化了字模寄存器,即 CGROM 和 CGRAM,存储了192个常用字符的字模。
字模库:

该表 行是低四位,列是高四位
想要显示哪个字符,只需查表,换算为十六进制,写入LCD1602即可。
12.png

例: 想要显示字符 A
需要向 LCD1602 写入 0x41(0100 0001)
三、显示位置
LCD1602 实际有80个字节的DDRAM,
只不过 LCD1602 只有 16X2 个位置,后面很多位置显示不出来,可以使用 指令5“光标或显示移动指令” 使字符慢慢移动到可见的显示范围内,看到字符的移动效果。
所以LCD1602的实际显示位置是,第一行:00 ~ 0F,第二行:40 ~ 4F
13.jpeg

注意:
如图, 指令8,D7位恒为 1,
在实际向LCD1602传入数据显示地址时,需要 < 地址+0x80 >
例:向LCD1602的第一行第一列写数据,传入的地址应为: (0x00+0x80)
14.png

三、LCD1602 操作

①写操作时序图:

15.jpeg

②读操作时序图:

16.jpeg

③时序时间参数:

17.jpeg

1、忙检测
为什么需要忙检测??
单片机和 LCD1602 的工作速度存在差异,单片机速度快,所以单片机向 LCD1602 传数据时,LCD1602 可能正在处理上一次的数据,处在忙状态,为了防止数据丢失或出错,所以单片机就需要等待,待 LCD1602 处理完时在进行下一次数据的传送。
忙检测代码:

由指令9,需判断 BF 的状态
  1. /****************** 忙检测 *********************
  2. LCD_Data 与 0x80 进行或运算,判断 bit7 位状态
  3. 若 LCD_Data 的 bit7 位是 0,则 LCD 不忙
  4. 若 LCD_Data 的 bit7 位是 1,则 LCD 忙
  5. ***********************************************/
  6. void LCD_Check_Busy(){
  7.         uchar temp;
  8.         LCD_Data = 0xff  // 十六进制:1111 1111
  9.         LCD_RS = 0;  // 0 指令
  10.         LCD_RW = 1;         // 1 读
  11.         do{
  12.                 LCD_E = 1;                  // 拉高
  13.                 temp = LCD_Data;  // 将 LCD 状态保存在 temp 中,用于判忙
  14.                 LCD_E = 0;                  // 负跳变使能
  15.         }while(temp & 0x80);  // 结果为 1,LCD 忙,继续循环;结果为 0,LCD 不忙,可以进行后面的操作
  16. }
复制代码
综合练习:

1)二行1列显示数字6
  1. #include <REGX52.H>                        // 加载头文件
  2. #include "Delay.h"
  3. sbit RS = P2^6;         // 数据命令选择位声明
  4. sbit RW = P2^5;         // 读写选择位声明
  5. sbit EN = P2^7;         // 使能位声明
  6. #define LCD_DATA P0
  7. void main()
  8. {
  9.     // 初始化LCD(必须)
  10.     Delay(15);          // 等待LCD稳定
  11.    
  12.     // 初始化指令
  13.     RS = 0; RW = 0;
  14.     LCD_DATA = 0x38;    // 8位数据,2行显示,5x8点阵
  15.     EN = 1; Delay(1); EN = 0; Delay(1);
  16.    
  17.     LCD_DATA = 0x0C;    // 显示开,光标关
  18.     EN = 1; Delay(1); EN = 0; Delay(1);
  19.    
  20.     LCD_DATA = 0x06;    // 地址自动+1
  21.     EN = 1; Delay(1); EN = 0; Delay(1);
  22.    
  23.     LCD_DATA = 0x01;    // 清屏
  24.     EN = 1; Delay(1); EN = 0; Delay(2); // 清屏需要更长时间
  25.    
  26.     while(1)
  27.     {
  28.         // 1. 设置显示位置(第二行第一位)
  29.         RS = 0; RW = 0;             // 写指令
  30.         LCD_DATA = 0xC0;            // 第二行第一位的地址
  31.         EN = 1; Delay(1); EN = 0; Delay(1);
  32.         
  33.         // 2. 显示字符'6'
  34.         RS = 1; RW = 0;             // 写数据
  35.         LCD_DATA = '6';             // 字符'6'的ASCII码是0x36
  36.         EN = 1; Delay(1); EN = 0; Delay(1);
  37.         
  38.         Delay(1000);  // 延时1秒,避免太快重复写入
  39.     }
  40. }
复制代码
2)  模块化编码

main.c
  1. #include <REGX52.H>
  2. #include "LCD1602.h"
  3. #include "Delay.h"
  4. void main()
  5. {
  6.         LCD_Init();                                                                //LCD初始化
  7.         LCD_ShowChar(1,1,'A');                                        //在1行1列显示字符A
  8.         LCD_ShowString(1,3,"Hello");                    //在1行3列显示字符串Hello
  9.         LCD_ShowNum(1,9,66,2);                                        //在1行9列显示数字66,长度为2
  10.         LCD_ShowSignedNum(1,12,-88,2);                //在1行12列显示有符号数字-88,长度为2
  11.         LCD_ShowHexNum(2,1,0xA5,2);                            //在2行1列显示十六进制数字0xA5,长度为2
  12.         LCD_ShowBinNum(2,4,0xA5,8);                            //在2行4列显示二进制数字0xA5,长度为8
  13.         LCD_ShowChar(2,13,0xDF);                                 //在2行13列显示编码为0xDF的字符
  14.         LCD_ShowChar(2,14,'C');                                        //在2行14列显示字符C
  15.         while(1)
  16.         {
  17.         }
  18. }
复制代码
LCD1602.c
  1. #include <REGX52.H>
  2. //引脚定义
  3. sbit LCD_RS=P2^6;
  4. sbit LCD_RW=P2^5;
  5. sbit LCD_E=P2^7;
  6. #define LCD_DataPort P0
  7. /**
  8.   * @brief  LCD1602延时函数,12MHz调用可延时1ms
  9.   * @param  无
  10.   * @retval 无
  11.   */
  12. void LCD_Delay()                //@12.000MHz 1ms
  13. {
  14.         unsigned char i, j;
  15.         i = 2;
  16.         j = 239;
  17.         do
  18.         {
  19.                 while (--j);
  20.         } while (--i);
  21. }
  22. /**
  23.   * @brief  LCD1602写命令
  24.   * @param  Command 要写入的命令
  25.   * @retval 无
  26.   */
  27. void LCD_WriteCommand(unsigned char Command)
  28. {
  29.         LCD_RS=0;
  30.         LCD_RW=0;
  31.         LCD_DataPort=Command;
  32.         LCD_E=1;
  33.         LCD_Delay();
  34.         LCD_E=0;
  35.         LCD_Delay();
  36. }
  37. /**
  38.   * @brief  LCD1602写数据
  39.   * @param  Data 要写入的数据
  40.   * @retval 无
  41.   */
  42. void LCD_WriteData(unsigned char Data)
  43. {
  44.         LCD_RS=1;
  45.         LCD_RW=0;
  46.         LCD_DataPort=Data;
  47.         LCD_E=1;
  48.         LCD_Delay();
  49.         LCD_E=0;
  50.         LCD_Delay();
  51. }
  52. /**
  53.   * @brief  LCD1602初始化函数
  54.   * @param  无
  55.   * @retval 无
  56.   */
  57. void LCD_Init(void)
  58. {
  59.         LCD_WriteCommand(0x38);
  60.         LCD_WriteCommand(0x0C);
  61.         LCD_WriteCommand(0x06);
  62.         LCD_WriteCommand(0x01);
  63. }
  64. /**
  65.   * @brief  LCD1602设置光标位置
  66.   * @param  Line 行位置,范围:1~2
  67.   * @param  Column 列位置,范围:1~16
  68.   * @retval 无
  69.   */
  70. void LCD_SetCursor(unsigned char Line,unsigned char Column)
  71. {
  72.         if(Line==1)
  73.         {
  74.                 LCD_WriteCommand(0x80|(Column-1));
  75.         }
  76.         else
  77.         {
  78.                 LCD_WriteCommand(0x80|(Column-1)+0x40);
  79.         }
  80. }
  81. /**
  82.   * @brief  在LCD1602指定位置上显示一个字符
  83.   * @param  Line 行位置,范围:1~2
  84.   * @param  Column 列位置,范围:1~16
  85.   * @param  Char 要显示的字符
  86.   * @retval 无
  87.   */
  88. void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
  89. {
  90.         LCD_SetCursor(Line,Column);
  91.         LCD_WriteData(Char);
  92. }
  93. /**
  94.   * @brief  在LCD1602指定位置开始显示所给字符串
  95.   * @param  Line 起始行位置,范围:1~2
  96.   * @param  Column 起始列位置,范围:1~16
  97.   * @param  String 要显示的字符串
  98.   * @retval 无
  99.   */
  100. void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String)
  101. {
  102.         unsigned char i;
  103.         LCD_SetCursor(Line,Column);
  104.         for(i=0;String[i]!='\0';i++)
  105.         {
  106.                 LCD_WriteData(String[i]);
  107.         }
  108. }
  109. /**
  110.   * @brief  返回值=X的Y次方
  111.   */
  112. int LCD_Pow(int X,int Y)
  113. {
  114.         unsigned char i;
  115.         int Result=1;
  116.         for(i=0;i<Y;i++)
  117.         {
  118.                 Result*=X;
  119.         }
  120.         return Result;
  121. }
  122. /**
  123.   * @brief  在LCD1602指定位置开始显示所给数字
  124.   * @param  Line 起始行位置,范围:1~2
  125.   * @param  Column 起始列位置,范围:1~16
  126.   * @param  Number 要显示的数字,范围:0~65535
  127.   * @param  Length 要显示数字的长度,范围:1~5
  128.   * @retval 无
  129.   */
  130. void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
  131. {
  132.         unsigned char i;
  133.         LCD_SetCursor(Line,Column);
  134.         for(i=Length;i>0;i--)
  135.         {
  136.                 LCD_WriteData('0'+Number/LCD_Pow(10,i-1)%10);
  137.         }
  138. }
  139. /**
  140.   * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  141.   * @param  Line 起始行位置,范围:1~2
  142.   * @param  Column 起始列位置,范围:1~16
  143.   * @param  Number 要显示的数字,范围:-32768~32767
  144.   * @param  Length 要显示数字的长度,范围:1~5
  145.   * @retval 无
  146.   */
  147. void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
  148. {
  149.         unsigned char i;
  150.         unsigned int Number1;
  151.         LCD_SetCursor(Line,Column);
  152.         if(Number>=0)
  153.         {
  154.                 LCD_WriteData('+');
  155.                 Number1=Number;
  156.         }
  157.         else
  158.         {
  159.                 LCD_WriteData('-');
  160.                 Number1=-Number;
  161.         }
  162.         for(i=Length;i>0;i--)
  163.         {
  164.                 LCD_WriteData('0'+Number1/LCD_Pow(10,i-1)%10);
  165.         }
  166. }
  167. /**
  168.   * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  169.   * @param  Line 起始行位置,范围:1~2
  170.   * @param  Column 起始列位置,范围:1~16
  171.   * @param  Number 要显示的数字,范围:0~0xFFFF
  172.   * @param  Length 要显示数字的长度,范围:1~4
  173.   * @retval 无
  174.   */
  175. void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
  176. {
  177.         unsigned char i;
  178.         unsigned char SingleNumber;
  179.         LCD_SetCursor(Line,Column);
  180.         for(i=Length;i>0;i--)
  181.         {
  182.                 SingleNumber=Number/LCD_Pow(16,i-1)%16;
  183.                 if(SingleNumber<10)
  184.                 {
  185.                         LCD_WriteData('0'+SingleNumber);
  186.                 }
  187.                 else
  188.                 {
  189.                         LCD_WriteData('A'+SingleNumber-10);
  190.                 }
  191.         }
  192. }
  193. /**
  194.   * @brief  在LCD1602指定位置开始以二进制显示所给数字
  195.   * @param  Line 起始行位置,范围:1~2
  196.   * @param  Column 起始列位置,范围:1~16
  197.   * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  198.   * @param  Length 要显示数字的长度,范围:1~16
  199.   * @retval 无
  200.   */
  201. void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
  202. {
  203.         unsigned char i;
  204.         LCD_SetCursor(Line,Column);
  205.         for(i=Length;i>0;i--)
  206.         {
  207.                 LCD_WriteData('0'+Number/LCD_Pow(2,i-1)%2);
  208.         }
  209. }
复制代码
LCD1602.h
  1. #ifndef __LCD1602_H__
  2. #define __LCD1602_H__
  3. void LCD_Init(void);
  4. void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char);
  5. void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String);
  6. void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
  7. void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
  8. void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
  9. void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
  10. #endif
复制代码
Delay.c
  1. void Delay(unsigned int xms)
  2. {
  3.         unsigned char i, j;
  4.         while(xms--)
  5.         {
  6.                 i = 2;
  7.                 j = 239;
  8.                 do
  9.                 {
  10.                         while (--j);
  11.                 } while (--i);
  12.         }
  13. }
复制代码
Delay.h
  1. #ifndef __DELAY_H__
  2. #define __DELAY_H__
  3. void Delay(unsigned int xms);
  4. #endif
复制代码
18.png

3)实现正计时显示

只需要修改 main.c ,其余部分同上
  1. #include <REGX52.H>
  2. #include "LCD1602.h"
  3. #include "Delay.h"
  4. unsigned int hour = 0;
  5. unsigned int minute = 0;
  6. unsigned int second = 0;
  7. /**
  8. * 更新时间函数
  9. */
  10. void UpdateTime()
  11. {
  12.     second++;
  13.    
  14.     if(second >= 60)
  15.     {
  16.         second = 0;
  17.         minute++;
  18.     }
  19.    
  20.     if(minute >= 60)
  21.     {
  22.         minute = 0;
  23.         hour++;
  24.     }
  25.    
  26.     if(hour >= 24)
  27.     {
  28.         hour = 0;
  29.     }
  30. }
  31. /**
  32. * 主函数
  33. */
  34. void main()
  35. {
  36.     // LCD初始化
  37.     LCD_Init();
  38.    
  39.     // 显示初始界面
  40.         LCD_ShowString(1, 1, "F_timing:");
  41.    
  42.     while(1)
  43.     {
  44.                 // 显示小时
  45.                 LCD_ShowNum(2, 1, hour, 2);
  46.                 // 显示分钟
  47.                 LCD_ShowNum(2, 4, minute, 2);
  48.         // 显示秒数
  49.         LCD_ShowNum(2, 7, second, 2);
  50.                        
  51.                 // 显示冒号
  52.             LCD_ShowChar(2, 3, ':');
  53.         LCD_ShowChar(2, 6, ':');
  54.                        
  55.         // 延时1秒
  56.         Delay(1000);
  57.         
  58.         // 更新时间
  59.         UpdateTime();
  60.     }
  61. }
复制代码
19.png

附加内容:
20.jpeg


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册