5.LCD1602显示屏

1.LCD1602简介

        LCD1602是字符型液晶显示模块,可显2行16字符,有多种接口,应用广、易控制。

        LCD1602有16个 管脚孔,从左自右管脚编号顺序是1-16,功能定义如下:

         各引脚功能如下:

电源相关引脚

  • VSS(引脚1):接地引脚,接电源负极,为模块提供零电位参考。
  • VDD(引脚2):电源正极引脚,一般接+5V电源,为模块提供工作所需的电能。
  • VL/VO(引脚3):对比度调节引脚,通过外接电位器来调节液晶显示的对比度,使显示内容清晰可见。

数据传输引脚

  • RS(引脚4):寄存器选择引脚。当RS=0时,选择指令寄存器,用于写入指令;当RS=1时,为读取操作,用于写入或读取显示数据。
  • RW(引脚5):读写控制引脚。当RW=0时,为写入操作,向LCD写入指令或数据;当RW=1时,为读取操作,从LCD读取状态或数据。
  • E(引脚6):使能信号引脚。在进行读写操作时,E引脚会产生一个高电平脉冲信号,LCD在这个脉冲的下降沿完成数据的读写。
  • D0-D7(引脚7-14):8位并行双向数据总线引脚,用于在微控制器和LCD之间传输指令、数据等信息。

背光相关引脚

  • A(引脚 15):背光源正极引脚,一般接 +5V 电源,为背光源提供电能,使屏幕在光线较暗时也能看清显示内容。
  • K(引脚 16):背光源负极引脚,接地,与 A 引脚共同构成背光源的供电回路。

LCD1602内部含有80个字节的DDRAM,它是用来寄存器显示字符的。其地址和屏幕的对应关系如下表:

         LCD1602 的控制指令系统是基于 16×2 的显示模式设计的。通过指令设置显示位置时,只能在预先定义好的这 32 个字符位置范围内进行定位。例如,使用设置 DDRAM 地址的指令,其参数范围只能指向这 32 个有效位置,无法对超出此范围的显示位置进行定位和数据写入,进而无法实现 40 列的显示。

2.LCD1602常用指令

清屏指令

  • 指令码:0x01
  • 功能:清除液晶显示屏上的所有显示内容,将 DDRAM(显示数据随机存取存储器)全部清零,同时把光标复位到屏幕左上角(即第 1 行第 1 列)。
  • 使用场景:当需要重新显示新的内容,且不希望之前的显示内容残留时,可使用该指令进行清屏操作。

光标归位指令

  • 指令码:0x02
  • 功能:将光标移动到屏幕左上角(第 1 行第 1 列),但不清空 DDRAM 中的内容,即显示屏上原有的显示内容保持不变。
  • 使用场景:在需要将光标重新定位到起始位置,以便从开头开始显示新数据时使用。

显示开关控制指令

  • 指令码:0x08 | D | C | B (其中 D、C、B 为标志位)
  • 功能
    • D(第 3 位):控制整体显示的开关。D = 1 时,显示开启;D = 0 时,显示关闭,但 DDRAM 中的数据不会被清除。
    • C(第 2 位):控制光标的显示。C = 1 时,光标显示;C = 0 时,光标隐藏。
    • B(第 1 位):控制光标闪烁。B = 1 时,光标闪烁;B = 0 时,光标不闪烁。
  • 使用场景:例如,若要关闭显示但保留数据,可将 D 置为 0;若要显示光标但不使其闪烁,可设置 D = 1、C = 1、B = 0。

进入模式设置指令

  • 指令码:0x04 | I/D | S
  • 功能:设定每次写入 1 位数据后光标的移位方向,并且设定每次写入的一个字符时显示屏是否移动。
  • 参数设定情况
    • I/D(第 2 位):控制写入新数据后光标的移动方向。当 I/D = 0 时,写入新数据后光标左移;当 I/D = 1 时,写入新数据后光标右移。
    • S(第 1 位):控制写入新数据后显示屏的移动情况。当 S = 0 时,写入新数据后显示屏不移动;当 S = 1 时,写入新数据后显示屏整体右移 1 个字。
  • 使用场景:在实际使用 LCD1602 显示数据时,可根据具体的显示需求来设置该指令的参数。例如,若希望数据从左到右依次显示且显示屏不移动,可将 I/D 设为 1,S 设为 0;若需要实现类似走马灯效果,每次写入数据后显示屏整体右移,可将 I/D 设为 1,S 设为 1。

 3.使用LCD1602

        如果要使用 LCD1602 液晶显示屏,第一步要做的就是对它进行初始化。初始化的操作其实就是向 LCD1602 写入一些特定的指令,让它准备好工作。

        初始化完成后,我们要确定在 LCD1602 的哪个具体位置显示内容。确定好位置后,再把想要显示的数据发送到 LCD 的 DDRAM(显示数据随机存取存储器)里。

        在实际使用中,我们一般只用 LCD1602 的写数据功能,很少会用到它的读功能。它的基本操作步骤可以分成下面三步:

  1. 初始化:这是让 LCD1602 进入正常工作状态的关键步骤。
  2. 写命令设置显示位置:在这个步骤里,要把 RS 引脚设置为低电平(用 “L” 表示),通过写入命令来告诉 LCD1602 我们要在哪个位置显示内容。
  3. 写数据进行显示:把 RS 引脚设置为高电平(用 “H” 表示),然后将需要显示的数据发送过去。

        因为我们一般不读取 LCD1602 里的数据状态或者数据本身,所以只需要了解两种写操作的时序就行:

  • 写指令设置工作方式:当我们要写指令来设置 LCD1602 的工作方式时,要把 RS 引脚设置为低电平,RW 引脚也设置为低电平。接着把相关指令数据送到数据口 D0 - D7。最后,在 E 引脚上产生一个高脉冲,这样指令数据就会被写入到 LCD1602 里。
  • 写数据实现显示:要是想在 LCD1602 上显示具体的数据,就得把 RS 引脚设置为高电平,RW 引脚设置为低电平。把要显示的数据送到数据口 D0 - D7,同样在 E 引脚上产生一个高脉冲,数据就会被写入并显示出来。

        可以看到,写指令和写数据这两个操作,主要的区别就是 RS 引脚的电平不一样。下面给大家展示 LCD1602 的时序图。

        从上面的图能发现,图里给出的时间参数全都是纳秒(ns)级别的。可 51 单片机呢,它的机器周期是 1 微秒(us),指令周期得 2 - 4 个机器周期。这就好比一个大块头和一个小不点,就算我们在程序里不额外加延时程序,51 单片机也能轻轻松松配合上 LCD1602 的时序要求。

        咱们来看看写命令字节的过程。首先 RS 引脚变成低电平,紧接着 R/W 引脚也变成低电平,而且 RS 引脚状态先变完。这时候,DB0 到 DB7 这些数据线上的数据就进入 “有效状态” 。

        接着,E 引脚会有一个完整脉冲的跳变。这个 E 脉冲的宽度最小得维持 400ns。之后 E 引脚来个负跳变,RS 引脚和 R/W 引脚的电平也跟着变化,这就完成了一次完整的 LCD1602 写命令的过程。

        这里要提醒一下哈,我们说的是 8 位的 LCD1602。现在有些公司为了让引脚数量少一些,就做了 4 位的 LCD1602。要是你用 4 位的 LCD1602,可得多看看它的手册,找出和 8 位的不同之处,然后把原来的程序改一改。

4.LCD1602原理图

 

        从上面的图能看出来,LCD1602 的 8 位数据口,也就是 DB0 到 DB7 这些引脚,和单片机的 P0.0 到 P0.7 管脚连在一起,就像把两座房子的对应房间门都打通,方便两边传递东西。LCD1602 的 RS、RW、E 这三个引脚呢,分别和单片机的 P2.6、P2.5、P2.7 管脚相连,这样单片机就能控制 LCD1602 的工作状态啦,就像你通过几个开关控制玩具的不同动作。

        图里还有个叫 RJ1 的东西,它是个电位器,作用就像电视机的亮度调节按钮,通过调节它可以改变 LCD1602 显示内容的对比度,也就是让显示亮度变亮或者变暗。

5.代码实现

1.定义

  • sbit 是 51 单片机特有的关键字,用于定义可位寻址的特殊功能寄存器的某一位。这里将 LCD_RS 定义为 P2 端口的第 6 位,LCD_RW 定义为 P2 端口的第 5 位,LCD_E 定义为 P2 端口的第 7 位。这三个引脚分别对应 LCD1602 的寄存器选择引脚(RS)、读写控制引脚(RW)和使能引脚(E),用于控制 LCD1602 的操作模式和数据传输。
  • #define 是 C 语言的预处理指令,用于定义宏。这里将 LCD_DataPort 定义为 P0 端口,意味着 P0 端口将作为与 LCD1602 进行 8 位数据传输的接口。
#include <REGX52.H>

sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_E=P2^7;
#define LCD_DataPort	P0

void LCD_Delay(void)	//@11.0592MHz	 1ms
{
	unsigned char data i, j;

	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

2.   向 LCD1602 写入命令     

void LCD_WriteCommand(unsigned char Command)
{
    LCD_RS=0;
    LCD_RW=0;
    LCD_DataPort=Command;
    LCD_E=1;
    LCD_Delay();
    LCD_E=0;
    LCD_Delay();
}

 

  1. LCD_RS = 0;
    • LCD_RS 是寄存器选择引脚,当 LCD_RS 为低电平(0)时,表示要写入的是命令。这一步操作告诉 LCD1602,接下来要接收的是用于设置其工作状态的命令。
  2. LCD_RW = 0;
    • LCD_RW 是读写控制引脚,当 LCD_RW 为低电平(0)时,表示进行写操作。这里明确当前的操作是向 LCD1602 写入数据,而不是读取数据。
  3. LCD_DataPort = Command;
    • LCD_DataPort 是数据端口,这里将传入的 Command 命令数据赋值给 LCD_DataPort,即将命令数据送到与 LCD1602 连接的数据总线上,准备发送给 LCD1602。
  4. LCD_E = 1;
    • LCD_E 是使能引脚,当 LCD_E 变为高电平(1)时,触发 LCD1602 开始接收数据。此时 LCD1602 会检测数据总线上的数据。
  5. LCD_Delay();
    • 调用之前定义的 LCD_Delay 函数进行延时。这个延时的作用是确保 LCD1602 有足够的时间来稳定地读取数据总线上的命令数据。
  6. LCD_E = 0;
    • 将 LCD_E 引脚拉低为低电平(0)。在 LCD_E 从高电平变为低电平的下降沿,LCD1602 会将数据总线上的数据锁存并处理,完成命令的写入操作。
  7. LCD_Delay();
    • 再次调用 LCD_Delay 函数进行延时,为下一次操作做准备,确保 LCD1602 有足够的时间处理刚刚写入的命令。

 3.向 LCD1602 写入数据

void LCD_WriteData(unsigned char Data)
{
    LCD_RS=1;
    LCD_RW=0;
    LCD_DataPort=Data;
    LCD_E=1;
    LCD_Delay();
    LCD_E=0;
    LCD_Delay();
}

        该函数的代码结构和执行过程与 LCD_WriteCommand 函数基本相同,唯一的区别在于 LCD_RS 的设置。

4.初始化

    LCD_Init 函数的作用是对 LCD1602 液晶显示屏进行初始化设置,通过向 LCD1602 写入一系列特定的命令,使其进入正常的工作状态。

void LCD_Init(void)
{
	LCD_WriteCommand(0x38);
	LCD_WriteCommand(0x0C);
	LCD_WriteCommand(0x06);
	LCD_WriteCommand(0x01);

}
1. LCD_WriteCommand(0x38);
  • 功能:设置 LCD1602 的工作模式。
  • 详细解释:命令码 0x38 对应的二进制是 00111000。在 LCD1602 的指令系统中,这个命令用于设置数据总线为 8 位(对应第 5 位为 1),显示为 2 行(对应第 4 位为 1),字符字体为 5x7 点阵(对应第 3 位为 0)。简单来说,就是告诉 LCD1602 采用 8 位数据传输方式,以 2 行显示,每个字符由 5x7 的点阵组成。
2. LCD_WriteCommand(0x0C);
  • 功能:控制显示开关。
  • 详细解释:命令码 0x0C 对应的二进制是 00001100。第 3 位为 1 表示开启显示功能;第 2 位为 0 表示不显示光标;第 1 位为 0 表示光标不闪烁。所以这条命令的作用是开启 LCD1602 的显示功能,并且不显示光标和让光标不闪烁。
3. LCD_WriteCommand(0x06);
  • 功能:设置输入模式。
  • 详细解释:命令码 0x06 对应的二进制是 00000110。第 2 位为 1 表示写入新数据后光标右移;第 1 位为 0 表示写入新数据后显示屏不移动。也就是说,当我们向 LCD1602 写入数据时,光标会自动向右移动一个位置,而显示屏整体不会发生移动。
4. LCD_WriteCommand(0x01);
  • 功能:清屏操作。
  • 详细解释:命令码 0x01 对应的二进制是 00000001。这条命令会清除 LCD1602 显示屏上的所有显示内容,将显示数据随机存取存储器(DDRAM)中的数据全部清零,同时把光标复位到屏幕的左上角(第 1 行第 1 列)。

总结

  LCD_Init 函数通过依次调用 LCD_WriteCommand 函数,向 LCD1602 发送了一系列初始化命令,完成了对 LCD1602 的工作模式、显示开关、输入模式的设置,并进行了清屏操作,使得 LCD1602 处于一个可以正常接收和显示数据的初始状态。在后续的程序中,就可以向 LCD1602 写入具体的数据进行显示了。

5.显示光标

        这段代码定义了一个名为 LCD_SetCursor 的函数,其功能是设置 LCD1602 显示屏上光标的位置。

void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
   if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));

	}
	else
	{
		LCD_WriteCommand(0x80|(Column-1)+0x40);
	}
}
  • 条件判断:当 Line 的值等于 1 时,说明要将光标设置在 LCD1602 的第一行。
  • 命令计算与发送
    • 0x80 是设置 DDRAM(显示数据随机存取存储器)地址的基本命令码。在 LCD1602 中,要设置显示位置,需要向其发送设置 DDRAM 地址的命令。
    • Column - 1 是将用户输入的列号(从 1 开始计数)转换为 DDRAM 地址偏移量(从 0 开始计数)。
    • 0x80 | (Column - 1) 是通过按位或运算将基本命令码和地址偏移量组合成完整的设置 DDRAM 地址的命令。例如,如果要将光标设置在第一行第 5 列,Column 为 5,Column - 1 为 4,0x80 | 4 得到 0x84,然后调用 LCD_WriteCommand 函数将该命令发送给 LCD1602,从而将光标定位到第一行第 5 列。
  • 条件判断:当 Line 的值不等于 1 时,即 Line 为 2,说明要将光标设置在 LCD1602 的第二行。
  • 命令计算与发送
    • 第二行的 DDRAM 地址是从 0x40 开始的。所以在设置第二行的光标位置时,除了要加上列号对应的偏移量 Column - 1,还需要加上 0x40
    • 同样通过按位或运算将基本命令码 0x80 和偏移量 (Column - 1) + 0x40 组合成完整的命令,然后调用 LCD_WriteCommand 函数发送给 LCD1602,实现将光标定位到第二行指定列的功能。

总结

  LCD_SetCursor 函数通过判断用户输入的行号,结合列号计算出对应的 DDRAM 地址,并将设置地址的命令发送给 LCD1602,从而实现了在 LCD1602 显示屏上精确设置光标位置的功能,为后续在指定位置显示字符数据提供了基础。

6.显示字符

        这段代码定义了一个名为 LCD_ShowChar 的函数,其主要功能是在 LCD1602 显示屏的指定位置显示一个字符。

void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

  LCD_ShowChar 函数通过先调用 LCD_SetCursor 函数定位光标位置,再调用 LCD_WriteData 函数写入字符数据,实现了在 LCD1602 显示屏的指定位置显示单个字符的功能。这个函数为后续在 LCD 上显示更复杂的信息(如字符串、数字等)提供了基础。

7.显示字符串

  这段代码定义了一个名为 LCD_ShowString 的函数,其功能是在 LCD1602 显示屏的指定位置显示一个字符串。

void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}
  • String:这是一个指向无符号字符型的指针,它指向要显示的字符串的首地址。在 C 语言里,字符串是以 '\0'(空字符)结尾的字符数组。

   LCD_ShowString 函数先通过 LCD_SetCursor 函数定位字符串的起始显示位置,然后利用 for 循环遍历字符串中的每个字符,再调用 LCD_WriteData 函数将字符逐个写入 LCD1602,从而实现了在指定位置显示字符串的功能。

8.整数的指定次幂

int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

   LCD_Pow 函数通过一个简单的 for 循环,将底数 X 累乘 Y 次,实现了整数的幂运算功能。这个函数在处理一些需要进行数值计算的场景中可能会用到,比如在显示数字时可能需要将数字拆分为不同的位进行处理,这时候就可能会用到幂运算。

9.显示数字

        这段代码定义了一个名为 LCD_ShowNum 的函数,其主要功能是在 LCD1602 显示屏的指定位置显示一个指定长度的无符号整数。

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+0x30);
	}
}
  • 参数
    • Line:表示要显示数字的起始行号,由于 LCD1602 通常为 2 行显示,所以该参数一般取值为 1 或 2。
    • Column:表示要显示数字的起始列号,LCD1602 每行可显示 16 个字符,因此该参数取值范围是 1 到 16。
    • Number:是一个无符号整型变量,代表要显示的无符号整数。
    • Length:是一个无符号字符型变量,指定了要显示数字的长度,即显示该数字所占的字符位数。
  • 循环体
    • LCD_Pow(10, i - 1):调用之前定义的 LCD_Pow 函数,计算 10 的 i - 1 次幂。例如,当 i 为 3 时,计算 10 的 2 次幂,结果为 100。
    • Number / LCD_Pow(10, i - 1):将 Number 除以 10 的 i - 1 次幂,得到该数字的高位部分。例如,若 Number 为 123,i 为 3 时,Number / LCD_Pow(10, 2) 即 123 / 100,结果为 1。
    • Number / LCD_Pow(10, i - 1) % 10:对上述结果取模 10,得到该数字当前位的值。例如,1 % 10 结果仍为 1。
    • Number / LCD_Pow(10, i - 1) % 10 + 0x30:在 ASCII 码中,数字 0 - 9 的编码是从 0x30 开始的,所以将当前位的值加上 0x30 就得到了该数字字符对应的 ASCII 码值。例如,数字 1 对应的 ASCII 码值为 0x31。
    • LCD_WriteData(Number / LCD_Pow(10, i - 1) % 10 + 0x30):调用 LCD_WriteData 函数将该数字字符的 ASCII 码值写入 LCD1602 的 DDRAM 中,从而在显示屏上显示该数字位。

  LCD_ShowNum 函数通过先定位光标位置,再利用循环依次提取并显示数字的每一位,实现了在 LCD1602 显示屏的指定位置显示指定长度无符号整数的功能。

10.显示有符号整数

        这段代码定义了一个名为 LCD_ShowSignedNum 的函数,其功能是在 LCD1602 显示屏的指定位置显示一个有符号整数。

void LCD_ShowSignedNum(unsigned char Line, unsigned char Column, int Number, unsigned char Length)
{
    unsigned char i;
    LCD_SetCursor(Line, Column);
    if (Number >= 0)
    {
        LCD_WriteData('+');
    }
    else
    {
        LCD_WriteData('-');
        Number = -Number; // 将负数转换为正数进行后续处理
    }

    // 调整显示位置,从符号后面开始显示数字
    LCD_SetCursor(Line, Column + 1); 

    for (i = Length; i > 0; i--)
    {
        LCD_WriteData(Number / LCD_Pow(10, i - 1) % 10 + 0x30);
    }
}

  LCD_ShowSignedNum 函数先在指定位置显示有符号整数的符号,然后将负数转换为正数,接着调整光标位置,最后通过循环依次提取并显示数字的数值部分的每一位,实现了在 LCD1602 显示屏上显示有符号整数的功能。

11.显示十六进制

       这段代码定义了一个名为 LCD_ShowHexNum 的函数,其功能是在 LCD1602 显示屏的指定位置显示一个无符号整数的十六进制形式。

void LCD_ShowHexNum(unsigned char Line, unsigned char Column,unsigned int Number, unsigned char Length)
{
	unsigned char i;
	unsigned char 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+'A'-10);
		}
		
	}
}
  • 显示十六进制位
    • 数字 0 - 9:如果 SingleNumber 小于 10,说明该十六进制位是数字 0 - 9,将其加上字符 '0' 的 ASCII 码值,就得到了对应的数字字符的 ASCII 码值,然后调用 LCD_WriteData 函数将其写入 LCD1602 进行显示。
    • 字母 A - F:如果 SingleNumber 大于等于 10,说明该十六进制位是字母 A - F,将其加上字符 'A' 的 ASCII 码值再减去 10,得到对应的字母字符的 ASCII 码值,然后调用 LCD_WriteData 函数进行显示。

         LCD_ShowHexNum 函数通过循环依次提取无符号整数的每一位十六进制值,并根据其值是数字还是字母,将其转换为对应的 ASCII 码字符,最后在 LCD1602 的指定位置显示出来,实现了十六进制数的显示功能。

12.显示二进制

        这段代码定义了一个名为 LCD_ShowBinNum 的函数,其作用是在 LCD1602 显示屏的指定位置显示一个无符号整数的二进制形式。

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+0x30);
	}
}
  • 显示二进制位
    • 在 ASCII 码中,数字 0 的编码是 0x30,数字 1 的编码是 0x31。将提取到的二进制位的值(0 或 1)加上 0x30,就得到了对应的数字字符的 ASCII 码值。
    • LCD_WriteData(Number / LCD_Pow(2, i - 1) % 2 + 0x30):调用 LCD_WriteData 函数将该二进制位对应的数字字符的 ASCII 码值写入 LCD1602 的 DDRAM 中,从而在显示屏上显示该二进制位。

        LCD_ShowBinNum 函数通过循环依次提取无符号整数的每一位二进制值,将其转换为对应的 ASCII 码字符,然后在 LCD1602 的指定位置显示出来,实现了二进制数的显示功能。

13.总结 

        本章全面介绍 LCD1602,包括硬件特性、指令、使用方法及代码实现。讲解各引脚功能、常用指令作用,给出初始化等代码。多个显示函数可实现字符、数字等显示。
        建议:深入研究指令,优化代码,添加注释,使用LCD1602显示数字、字符等。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值