17 LCD1602模块——显示屏
一、51单片机模块
二、LCD1602模块
三、模块间的连接
单片机P2端口:P2_5~P2_7
单片机P0端口:P0_0~P0_7
四、LCD1602芯片
1、参数和引脚
这里只需要了解单片机的引脚功能,也可以大致看一眼,后面在编码显示功能的时候,也会做详细的说明。
2、LCD1602内部的控制指令
LCD1602 的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
技巧:
看最高位哪位是1——就是哪个指令,然后集体的看剩下的0和1情况
LCD1602 内部的控制器共有11条控制指令,如表所示:
指令1:清显示,指令码 01H,光标复位到地址 00H 位置。
指令2:光标复位,光标返回到地址00H。
指令3:
I/D:光标和显示模式设置,光标移动方向,高电平右移,低电平左移;
S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。
指令4:显示开关控制。
D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示;
C:控制光标的开与关,高电平表示有光标,低电平表示无光标;
B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:
S/C:高电平时移动显示的文字,低电平时移动光标;
R/L:高电平时右移,低电平时左移。
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线;
N:低电平时为单行显示,高电平时双行显示;
F:低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM地址设置。
指令9:读忙信号和光标地址
BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据。
指令11:读数据
3、基本操作时序
LCD1602 的基本的操作分为以下四种:
状态字读操作:输入 RS=0、RW=1、E=1;输出:D0~7 读出为状态字;
数据读出操作:输入 RS=1、RW=1、E=1;输出:D0~7 读出为数据;
指令写入操作:输入 RS=0、RW=0、E=上升沿; 输出:无;
数据写入操作:输入 RS=1、RW=0、E=上升沿; 输出:无。
4、LCD1602模块
(1)LCD1602.c
这里不用看,只是把全部的复制了一下。
可以在5里看详细的各个部分的介绍——因为新手本来就第一次接触,看不懂也没关系——只要能一步一步学下去就是成功——直接跳到5即可。
#include <REGX52.H> //引脚配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^7; #define LCD_DataPort P0 //函数定义: /** * @brief LCD1602延时函数,12MHz调用可延时1ms * @param 无 * @retval 无 */ void LCD_Delay() { unsigned char i, j; i = 2; j = 239; do { while (--j); } while (--i); } /** * @brief LCD1602写命令 * @param Command 要写入的命令 * @retval 无 */ void LCD_WriteCommand(unsigned char Command) { LCD_RS=0; LCD_RW=0; LCD_DataPort=Command; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602写数据 * @param Data 要写入的数据 * @retval 无 */ void LCD_WriteData(unsigned char Data) { LCD_RS=1; LCD_RW=0; LCD_DataPort=Data; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602设置光标位置 * @param Line 行位置,范围:1~2 * @param Column 列位置,范围:1~16 * @retval 无 */ void LCD_SetCursor(unsigned char Line,unsigned char Column) { if(Line==1) { LCD_WriteCommand(0x80|(Column-1)); } else if(Line==2) { LCD_WriteCommand(0x80|(Column-1+0x40)); } } /** * @brief LCD1602初始化函数 * @param 无 * @retval 无 */ void LCD_Init() { LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵 LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关 LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动 LCD_WriteCommand(0x01);//光标复位,清屏 } /** * @brief 在LCD1602指定位置上显示一个字符 * @param Line 行位置,范围:1~2 * @param Column 列位置,范围:1~16 * @param Char 要显示的字符 * @retval 无 */ void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) { LCD_SetCursor(Line,Column); LCD_WriteData(Char); } /** * @brief 在LCD1602指定位置开始显示所给字符串 * @param Line 起始行位置,范围:1~2 * @param Column 起始列位置,范围:1~16 * @param String 要显示的字符串 * @retval 无 */ void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) { unsigned char i; LCD_SetCursor(Line,Column); for(i=0;String[i]!='\0';i++) { LCD_WriteData(String[i]); } } /** * @brief 返回值=X的Y次方 */ int LCD_Pow(int X,int Y) { unsigned char i; int Result=1; for(i=0;i<Y;i++) { Result*=X; } return Result; } /** * @brief 在LCD1602指定位置开始显示所给数字 * @param Line 起始行位置,范围:1~2 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:0~65535 * @param Length 要显示数字的长度,范围:1~5 * @retval 无 */ void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0'); } } /** * @brief 在LCD1602指定位置开始以有符号十进制显示所给数字 * @param Line 起始行位置,范围:1~2 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:-32768~32767 * @param Length 要显示数字的长度,范围:1~5 * @retval 无 */ void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) { unsigned char i; unsigned int Number1; LCD_SetCursor(Line,Column); if(Number>=0) { LCD_WriteData('+'); Number1=Number; } else { LCD_WriteData('-'); Number1=-Number; } for(i=Length;i>0;i--) { LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0'); } } /** * @brief 在LCD1602指定位置开始以十六进制显示所给数字 * @param Line 起始行位置,范围:1~2 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:0~0xFFFF * @param Length 要显示数字的长度,范围:1~4 * @retval 无 */ void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i,SingleNumber; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber<10) { LCD_WriteData(SingleNumber+'0'); } else { LCD_WriteData(SingleNumber-10+'A'); } } } /** * @brief 在LCD1602指定位置开始以二进制显示所给数字 * @param Line 起始行位置,范围:1~2 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:0~1111 1111 1111 1111 * @param Length 要显示数字的长度,范围:1~16 * @retval 无 */ void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0'); } }(2)LCD1602.h
#ifndef __LCD1602_H__ #define __LCD1602_H__ //用户调用函数: void LCD_Init(); void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char); void LCD_ShowString(unsigned char Line,unsigned char Column,char *String); void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length); void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); #endif5、LCD1602.c里的各个函数
(1)引脚配置
LCD1602模块与单片机的功能实现需要用到的引脚——显示屏与单片机的线路连接起来
P0取个别名——在显示屏模块的名字表示
LCD_等——地址
做完准备工作,开始编写函数
(2)延时函数——LCD_Delay
接收数据和数据发送——给出一段时间
//1毫秒的延时 void LCD_Delay() { unsigned char i, j; i = 2; j = 239; do { while (--j); } while (--i); }(3)指令写入函数——LCD_WriteCommand
- RS
- 低电平时,选择命令
- 高电平时,选择数据
- RW
- 低电平时,向LCD1602写入命令或数据
- 高电平时,从LCD1602读取状态或数据
- 不需要进行读取操作,可以直接将其接VSS。
- E
- 执行命令的使能引脚
写入的数据以函数的参数写入到函数中
这个参数赋值给LCD_DataPort(别名)——P0
详细步骤:
- RS——低电平(选择命令)
- RW——低电平(向LCD1602写入命令)
- 把需要写的命令以参数的形式赋值给LCD_DataPort(P0)
- EN——高电平(使能信号)
- 延时函数
- EN——低电平(使能信号)
- 延时函数
// 1602液晶写命令函数,Command就是要写入的命令 void LCD_WriteCommand(unsigned char Command) { LCD_RS=0; //选择写指令 LCD_RW=0; //选择写 LCD_DataPort=Command; //把指令送入P0 LCD_EN=1; //使能线电平变化上升沿,命令送入1602的8位数据口 LCD_Delay(); //延时一小会儿,让1602准备接收数据 LCD_EN=0; //使能线拉低 LCD_Delay(); //延时,让数据发送 }(4)数据写入函数——LCD_WriteData
详细步骤:
- RS——高电平(选择数据)
- RW——低电平(向LCD1602写入数据)
- 把需要写的数据以参数的形式赋值给LCD_DataPort(P0)
- EN——高电平(使能信号)
- 延时函数
- EN——低电平(使能信号)
- 延时函数
// 1602液晶写数据函数,Data就是要写入的数据 void LCD_WriteData(unsigned char Data) { LCD_RS=1; //选择写数据 LCD_RW=0; //选择写 LCD_DataPort=Data; //把数据送入P0 LCD_EN=1; //使能线电平变化上升沿,命令送入1602的8位数据口 LCD_Delay(); //延时一小会儿,让1602准备接收数据 LCD_EN=0; //使能线拉低 LCD_Delay(); //延时,让数据发送 }(5)设置光标位置函数——LCD_SetCursor
两个参数分别为:行位置、列位置
详细步骤:
- 如果Line的参数为1。那么0x80与列数-1按位或后的结果,再以参数的形式调用写命令函数
- 如果Line的参数为2。那么0x80与列数-1+0x40按位或后的结果,再以参数的形式调用写命令函数
// 光标定位函数 void LCD_SetCursor(unsigned char Line,unsigned char Column) { if(Line==1) { LCD_WriteCommand(0x80|(Column-1)); //LCD_WriteCommand(0x80+column); } else if(Line==2) { LCD_WriteCommand(0x80|(Column-1+0x40)); //LCD_WriteCommand(0x80+0x40+column); } }(6)初始化函数——LCD_Init
往上去找四中的2和3——控制指令、操作时序
//参数传入单片机的P0地址——参数是传入数据 void LCD_Init() { LCD_WriteCommand(0x38); // 16*2显示,5*7点阵,8位数据口 // 显示模式设置 //——————————————————————————————指令六:置功能 LCD_WriteCommand(0x0c); // 显示开,及光标设置——不显示光标 //——————————————————————————————指令四:显示开关控制 LCD_WriteCommand(0x06); // 地址加1,当写入数据后光标右移 // 显示光标移动设置 //——————————————————————————————指令三:置输入模式 LCD_WriteCommand(0x01); // 清屏 //——————————————————————————————指令一:清显示 }(7)指定位置上显示一个字符函数——LCD_ShowChar
三个参数分别为:行位置、列位置、要显示的字符
详细步骤:
- 调用设置光标位置函数
- 调用写数据函数
//两个函数的调用 //光标位置——(行、列)——Line、Column //写的数据——char void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) { LCD_SetCursor(Line,Column); LCD_WriteData(Char); }(8)指定位置开始显示所给字符串——LCD_ShowString
三个参数分别为:起始行位置、起始列位置、要显示的字符
详细步骤:
- 定义一个变量i
- 调用光标位置函数
- 字符以参数的形式用for循环——调用写数据函数
//指定位置开始显示——字符串 //两个函数的调用 //设置光标位置 //参数传入的字符串——以for循环的形式一个一个写数据——直到循环到字符串的结束符 void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) { unsigned char i; LCD_SetCursor(Line,Column); for(i=0;String[i]!='\0';i++) { LCD_WriteData(String[i]); } }(9)返回值=X的Y次方函数——LCD_Pow
//X的Y次方函数——辅助输入的数字根据长度的依次输出 int LCD_Pow(int X,int Y) { unsigned char i; int Result=1; for(i=0;i<Y;i++) { Result*=X; } return Result; }(10)指定位置开始显示所给数字——LCD_ShowNum
四个参数分别为:起始行位置、起始列位置、要显示的数字、要显示的数字长度
详细步骤:
- 定义一个变量i
- 调用设置光标位置函数
- for函数——根据长度判断循环次数
- 要显示的数字——根据占位数——的依次输出
这里打个比方
如果输入的数字是1,占位4个
i=4 1/(10*10*10)=0 则0%10=0
i=3 1/(10*10)=0 则0%10=0
i=2 1/(10)=0 则0%10=0
i=1 1/1=1 则1%10=1
说明:
%的两边必须是——整型——运算完自动转为成了整型
但是LCD_WriteData的参数是无符号字符型,所以需要转换数据类型——+'0'的目的就是这个。
//指定位置开始显示——数字 //三个函数的调用 //设置光标位置 //根据参数传入的长度控制for循环的次数——写数据(参数依次从最高位到最低位) void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0'); } }(11)指定位置开始以有符号十进制显示所给数字——LCD_ShowSignedNum
四个参数分别为:起始行位置、起始列位置、要显示的数字、要显示的数字长度
//指定位置——以有符号十进制显示——数字 //如果Num>0 比如1 符号用+ 数据=1 输出+1 //如果Num<0 比如-1 符号用- 数据=-(-1)=1 输出-1 void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) { unsigned char i; unsigned int Number1; LCD_SetCursor(Line,Column); if(Number>=0) { LCD_WriteData('+'); Number1=Number; } else { LCD_WriteData('-'); Number1=-Number; } for(i=Length;i>0;i--) { LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0'); } }(12)指定位置开始以十六进制显示所给数字——LCD_ShowHexNum
四个参数分别为:起始行位置、起始列位置、要显示的数字、要显示的数字长度
//指定位置——十六进制显示——数字 void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i,SingleNumber; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber<10) { LCD_WriteData(SingleNumber+'0'); } else { LCD_WriteData(SingleNumber-10+'A'); } } }(13)指定位置开始以二进制显示所给数字——LCD_ShowBinNum
四个参数分别为:起始行位置、起始列位置、要显示的数字、要显示的数字长度
//指定位置——二进制显示——数字 void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0'); } }五、main.c
用具体的函数再完整的顺一遍程序运行的过程。
#include <REGX52.H> #include "LCD1602.h" //包含LCD1602头文件 #include "Delay.h" //包含Delay头文件 int Result=0; void main() { LCD_Init(); while(1) { Result++; //Result自增 Delay(1000); //延时1秒 LCD_ShowNum(1,1,Result,3); //在LCD的1行1列显示Result,长度为3位 } }指定位置开始显示所给数字——参数为(一行、一列、数字、占位数)
- 设置全局变量——Result——初值为0
- while循环
- Result++
- 延时1秒
- 调用函数——LCD_ShowNum
- ③~⑤循环
六、现象
LCD显示屏,上机后从000~999循环——间隔时间为1秒
说明:
在main.c中的代码只写实现逻辑的代码
- 在指定位置
- 什么进制形式
- 输出的数字或者字符
- 占几位
其他的都是辅助逻辑实现的。
