LCD1602 液晶显示实验

LCD1602 简介

           LCD1602是一种用来显示字母、数字、符号的点阵型液晶模块,可显示 2 行字符信息,每行又能显示 16 个字符,每个字符由若干个( 5x7 或 5x10) 的点阵字符位组成, 每位之间有一个点距的间隔,每行之间也有间隔,起到字符间距和行间距的作用。其实物图如下所示:

LCD1602 液晶显示实验_第1张图片

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

LCD1602 液晶显示实验_第2张图片

           管脚说明:

           3 脚:VL,液晶显示偏压信号,用于调整 LCD1602 的显示对比度,通常外接电位器用以调整偏压信号。注意,电压为 0 时对比度最强。

           4 脚:RS,数据/命令选择端。此脚为高电平时,可对LCD1602 进行数据字节(即使用在 LCD1602上显示的字节,且LCD1602 的数据是 8 位的)的传输操作;此脚为低电平时,则是进行命令字节(即用来对 LCD1602 的一些工作方式作设置的字节)的传输操作。

            5 脚:R/W,读写选择端。此脚为高电平,可对 LCD1602 进行读数据操作, 反之进行写数据操作。

            6 脚:E,使能信号,其实是 LCD1602 的数据控制时钟信号,利用该信号的上升沿实现对 LCD1602 的数据传输。

           7~14 脚:8 位并行数据口。 51 单片机一组 IO 也是 8 位,使得对 LCD1602 的数据读写大为方便。 在 LCD1602 内部含有 80 个字节的数据存储器DDRAM,用来寄存显示字符。其地址和屏幕的对应关系如下表所示:

显示位置 1 2 3 4 5 6 7 .... 40
DDRAM地址 第一行 00H 01H 02H 03H 04H 05H 06H .... 27H
第二行 40H 41H 42H 43H 44H 45H 46H .... 67H

LCD1602 液晶显示实验_第3张图片

            如图所示,并非所有的地址都可直接用来显示字符数据,只有第一行中的 00-0F、第二行中的 40-4F 才能显示,其他地址只能用于存储。要显示字符时,要先输入显示字符地址,也就是告诉模块在哪里显示字符

            例如第二行第一个字符的地址是 40H,那么是否直接写入 40H 就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位 D7 恒定为高电平 1

            所以实际写入的数据应该是 01000000B(40H) +10000000B(80H)=11000000B(C0H)。在 LCD1602 中就用前 16 个就行了。第二行也一样用前 16 个地址。

LCD1602 常用指令

             使用 LCD1602 需要掌握的一些常用的指令:

清屏指令 

  •  清除液晶显示器,即将 DDRAM 的内容全部填入"空白"的 ASCII 码 20H;
  • 光标归位,即将光标撤回液晶显示屏的左上方;
  • 将地址计数器(AC)的值设为 0。
指令功能 指令编码 执行时间/ms
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
清屏 0 0 0 0 0 0 0 0 0 1 1.64

模式设置指令

  • 设定每次写入 1 位数据后光标的移位方向,并且设定每次写入的一个字符是否移动
  • I/D:  0=写入新数据后光标左移             1=写入新数据后光标右移
  • S:    0=写入新数据后显示屏不移动      1=写入新数据后显示屏整体右移 1 个字符
指令功能 指令编码 执行时间/us
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
进入模式设置 0 0 0 0 0 0 0 1 I/D S 40

显示开关控制指令

  • 控制显示器开/关、光标显示/关闭以及光标是否闪烁。
  • D:  0=显示功能关     1=显示功能开
  • C:  0=无光标            1=有光
  • B:  0=光标闪烁         1=光标不闪烁 
指令功能 指令编码 执行时间/us
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
显示开关控制 0 0 0 0 0 0 1 0 C B 40

功能设定指令

  • 设定数据总线位数、显示的行数及字型。
  • DL: 0=数据总线为 4 位                1=数据总线为 8 位
  • N:   0=显示 1 行                           1=显示 2 行
  • F:   0=5×7 点阵/每字符                1=5×10 点阵/每字符
指令功能 指令编码 执行时间/us
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
功能设定 0 0 0 0 1 DL N F X X 40

LCD1602 使用

             使用 LCD1602,首先需要对其初始化,即通过写入一些特定的指令实现。 然后选择要在 LCD1602 的哪个位置显示并将所要显示的数据发送到 LCD 的 DDRAM。使用 LCD1602 通常都是用于写数据进去,很少使用读功能。LCD1602 操作步骤如下所示:

  1. 初始化;
  2. 写命令(RS=L),设置显示坐标;
  3. 写数据(RS=H)。

             在此,不需要读出它的数据的状态或者数据本身。所以只需要看两个写时序:

              ①当要写指令字,设置 LCD1602 的工作方式时:需要把 RS 置为电平,RW 置为低电平,然后将数据送到数据口 D0~D7,最后使能信号 E 引脚一个高脉冲将数据写入。

              ②当要写入数据字,在 1602 上实现显示时:需要把 RS 置为电平,RW 置为低电平,然后将数据送到数据口 D0~D7,最后使能信号 E 引脚一个高脉冲将数据写入。

             写指令和写数据,差别仅仅在于 RS 的电平不一样而已。以下为 LCD1602 的时序图:

LCD1602 液晶显示实验_第4张图片

              以上时间参数全部是 ns 级别的,而 51 单片机的机器周期是 1us,指令周期是 2-4 个机器周期,所以不加延时程序,也配合 LCD1602 的时序要求。

              当要写命令字节的时候,时间由左往右,RS 变为低电平,R/W 变为低电平, 注意,RS 的状态先变化完成。然后 DB0~DB7 上数据进入有效阶段,接着 E 引脚有一个整脉冲的跳变,接着要维持时间最小值为 tpw=150ns 的 E 脉冲宽度。然后E引脚负跳变,RS电平变化,R/W 电平变化。这样便是一个完整的LCD1602 写命令的时序。

               注意:这里介绍的是 8 位 LCD1602。

硬件部分

 

               使用到硬件资源如下:

  1. LCD1602 液

               开发板上集成了一个 LCD1602 液晶接口,电路如下所示:

LCD1602 液晶显示实验_第5张图片LCD1602 液晶显示实验_第6张图片

                         如图所示,8 位数据口 DB0-DB7 与单片机的 P0.0-P0.7 管脚连接,RS、RW、E 脚与单片机的 P2.6、P2.5、P2.7 管脚连接。图中的RJ1 是一个电位器,用来调节 LCD1602 对比度即显示亮度,实物图如下所示:

LCD1602 液晶显示实验_第7张图片

              注:这里原理图使用的是 8 位 LCD1602 接口设计,可兼容 4 位 LCD1602 。 4 位 LCD1602 在传输数据时,需要将 8 位的数据截成两段,先发送高四位,后发低四位。其它引脚操作方法不变。

软件部分

         所要实现的功能是:在 LCD1602 液晶上显示字符信息。

         程序框架如下:

  1. 编写 LCD1602 显示函数
  2. 编写主函数

          重点是对 LCD1602 进行写命令和数据。 这里分析几个重要函数:

 LCD1602 驱动函数

          在代码中可以看到有如下格式:

#if (LCD1602_4OR8_DATA_INTERFACE==0)
...(省略内容 1)
#else
...(省略内容 2)
#endif

          这是 C 语言中的条件编译,如果条件表达式 LCD1602_4OR8_DATA_INTERFACE==0 为真, 则执行省略内容 1 部分,否则执行省略内容 2 部分。和 if...else 类似。 

          lcd1602_write_cmd 函数是 LCD1602 写命令。

          lcd1602_write_data 函数是 LCD1602 写数据,它们之间的区别仅在于控制脚 RS 的值,如果为 0 则写命令, 为 1 则写数据。

          对于 8 位数据和 4 位数据口的驱动,不同之处在于 8 位数据是一 次性传输到端口,而 4 位数据口需要将一个字节数据分两次传输,高 4 位和低 4 位。

           lcd1602_init 函数是 LCD1602 初始化函数,根据其命令设置相应的值,开启 LCD1602 显示。

          lcd1602_clear 函数是 LCD1602 清屏函数,实际上也是调用 lcd1602_write_cmd 函数写 0X01 命令。

          lcd1602_show_string 函数是 LCD1602 显示字符函数,该函数有 3 个入口参数,x 和 y 用来确定显示的坐标,x 范围是 0-15,y 范围是 0-1。str 参数是一个指针类型变量,用于传递显示的内容。函数内首先判断 x、y 坐标是否有效,无效则强制退出,然后根据 xy 值在对应的坐标位置显示内容,代码如下:

#include "lcd1602.h"

/*******************************************************************************
* 函 数 名       : lcd1602_write_cmd
* 函数功能		 : LCD1602写命令
* 输    入       : cmd:指令
* 输    出    	 : 无
*******************************************************************************/
#if (LCD1602_4or8_DATA_INTERFACE==0)//8为LCD
void lcd1602_write_cmd(u8 cmd)
{
	LCD1602_RS=0;	//选择命令
	LCD1602_RW=0;   //选择写
	LCD1602_E=0;
	LCD1602_DATAPORT=cmd;	//准备命令
	delay_ms(1);
	LCD1602_E=1;	 //使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E=0;	 //使能脚E后负跳变完成写入
}
#else //4位LCD
/*对于 4 位 LCD1602 在传输数据的时候需要将 8 位的数据截成两段,先发
送高四位,在发送低四位。其它引脚操作方法不变。*/
void lcd1602_write_cmd(u8 cmd)
{
 	LCD1602_RS=0;	//选择命令
	LCD1602_RW=0;   //选择写
	LCD1602_E=0;
	LCD1602_DATAPORT=cmd;	  //准备命令,发送高四位
	delay_ms(1);
	LCD1602_E=1;	 //使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E=0;	 //使能脚E后负跳变完成写入

	LCD1602_DATAPORT=cmd<<4;  //准备命令,发送低四位,此时将低四位左移至高四位再发送
	delay_ms(1);
	LCD1602_E=1;	 //使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E=0;	 //使能脚E后负跳变完成写入
}
#endif

/*******************************************************************************
* 函 数 名       : lcd1602_write_data
* 函数功能		 : LCD1602写数据
* 输    入       : dat:数据
* 输    出    	 : 无
*******************************************************************************/
#if (LCD1602_4or8_DATA_INTERFACE==0) //8位LCD
void lcd1602_write_data(u8 dat)
{
 	LCD1602_RS=1;   //选择数据
	LCD1602_RW=0;   //选择写
	LCD1602_E=0;
	LCD1602_DATAPORT=dat;   //准备数据
	delay_ms(1);
	LCD1602_E=1;   //使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E=0;   //使能脚E后负跳变完成写入
}
#else
void lcd1602_write_data(u8 dat)
{
 	LCD1602_RS=1;	//选择数据
	LCD1602_RW=0;   //选择写
	LCD1602_E=0;
	LCD1602_DATAPORT=dat;	  //准备数据,发送高四位
	delay_ms(1);
	LCD1602_E=1;	 //使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E=0;	 //使能脚E后负跳变完成写入

	LCD1602_DATAPORT=dat<<4;  //准备新数据,发送低四位,此时将低四位左移至高四位再发送
	delay_ms(1);
	LCD1602_E=1;	 //使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E=0;	 //使能脚E后负跳变完成写入		
}
#endif

/*******************************************************************************
* 函 数 名       : lcd1602_init
* 函数功能		 : LCD1602初始化
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
#if (LCD1602_4or8_DATA_INTERFACE==0) //8位LCD
void lcd1602_init(void)
{
 	lcd1602_write_cmd(0x38);   //功能设定指令:数据总线8位,显示2行,5*7点阵/字符
	lcd1602_write_cmd(0x0c);   //显示开关控制指令:显示功能开,无光标,光标闪烁
	lcd1602_write_cmd(0x06);   //模式设置指令:写入新数据后光标右移,显示屏不移动
	lcd1602_write_cmd(0x01);   //清屏指令:清屏
}
#else
void lcd1602_init(void)
{
	lcd1602_write_cmd(0x28);   //功能设定指令:数据总线4位,显示2行,5*7点阵/字符
	lcd1602_write_cmd(0x0c);   //显示开关控制指令:显示功能开,无光标,光标闪烁
	lcd1602_write_cmd(0x06);   //模式设置指令:写入新数据后光标右移,显示屏不移动
	lcd1602_write_cmd(0x01);   //清屏指令:清屏 	
}
#endif

/*******************************************************************************
* 函 数 名       : lcd1602_clear
* 函数功能		 : LCD1602清屏
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void lcd1602_clear(void)
{
 	lcd1602_write_cmd(0x01);
}

/*******************************************************************************
* 函 数 名       : lcd1602_show_string
* 函数功能		 : LCD1602显示字符
* 输    入       : x,y:显示坐标,x=0~15,y=0~1;
				   str:显示字符串
* 注    释    	 : 并非所有的地址都可直接用来显示字符数据,只有第一行中
                   的 00-0F、第二行中的 40-4F 才能显示,其他地址只能用于存储。
*******************************************************************************/
void lcd1602_show_string(u8 x,u8 y,u8 *str)
{
 	u8 i=0;

	if(y>1||x>15)	//行列参数无效,强制退出
		return;
	if(y<1)	  //第一行显示
	{
	 	while(*str!='\0')
		{
		 	if(i<16-x)
			{
			 	lcd1602_write_cmd(0x80+i+x);
			}
			else 
			{
			 	lcd1602_write_cmd(0x40+0x80+i+x-16);
			}
			lcd1602_write_data(*str);
			str++;
			i++;
		}	
	}
	else
	{
		while(*str!='\0')
		{
		 	if(i<16-x)	  //如果字符长度超过第二行显示范围,则在第一行继续显示
			{
			 	lcd1602_write_cmd(0x80+0x40+i+x);
			}
			else 
			{
			 	lcd1602_write_cmd(0x80+i+x-16);
			}
			lcd1602_write_data(*str);
			str++;
			i++;
		}	
	}
}

主函数

          首先调用外设驱动头文件,然后进入 main 函数初始化 LCD1602,并调用 LCD1602 显示函数让第一行显示"Hello World!",第二行显 示"0123456789"。

#include "public.h"
#include "lcd1602.h"

void main()
{
 	lcd1602_init();	  //LCD1602初始化
	lcd1602_show_string(0,0,"Hello world!");  //第一行显示
	lcd1602_show_string(0,1,"0123456789");	  //第二行显示
	while(1)
	{

	}
}

          这里说明下,在开发中通常会显示数值,比如温度数据,程序中我们获取的温度数据通常存储在 float 变量中,并非字符串,此时需要想办法将 float 变量中的值转换为字符串,比如 float temp=31.2,那么我们可以再定义一个数组 temp_buf[]用于保存 temp 中的每一个位,操作如下:

float temp=31.2;
u8 temp_buf[5];
u16 temp_value=temp*10;//将浮点数转换为整型变量,乘10得312

/*获取temp)value的各位,并存储在数组temp_value中*/
temp_buf[0]=temp_value/100+0x30;
temp_buf[1]=temp_value%100/10+0x30;
temp_buf[2]='.';
temp_buf[3]=temp_value%100%10+0x30;
temp_buf[4]='\0';
lcd1602_show_string(0,0,temp_buf);

          将浮点数转换为整型变量,然后将整型值的每一个位取出来存储在数组 temp_buf 中,取出的每一位后面加了 0X30,这个值是将数字 0-9 转换为 ASCII 码,因为液晶是以 ASCII 码显示的。最后一个数组元素赋值 了’\0’,这是为了让 LCD1602 显示函数知道数组内结束位置。

          根据 C 语言指针的特点,此时调用 LCD1602 显示函数时,只需要将数组名传递进去即可,因为数组名即为该数组的起始地址,然后显示函数内部通过指针访问数组的每一位。

现象

        实现现象如下:在 LCD1602 液晶上显示字符信息。

LCD1602 液晶显示实验_第8张图片

 

你可能感兴趣的:(51单片机,开发语言,经验分享,51单片机)