在LCD1602液晶上显示字符信息;
1602液晶也叫1602字符型液晶,它能显示2行字符信息,每行又能显示16个字符;
它是一种专门用来显示字母、数字、符号的点阵型液晶模块;
它是由若干个5x7或者5x10的点阵字符位组成,每个点阵字符位都可以用显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此,所以它不能很好的显示图片;
LCD1602有16个管脚孔,从左至右管脚编号顺序是1-16
在LCD1602内部含有80个字节的DDRAM,它是用来寄存显示字符的;
其地址和屏幕的对应关系如下表:
从上图可知,不是所有的地址都可以直接用来显示字符数据,只有第一行中的00-0F,第二行中的40-4F才能显示,其他地址只能用于存储;
要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,而且写入显示地址时要求最高位D7恒定为高电平1,例如第二行第一个字符的地址是40H,所以要写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H);
在1602中我们只用前16个地址就行了,第二行也一样用前16个地址;
在使用LCD1602时,我们需要掌握一些常用的指令,这些指令对于LCD1602初始化是必须的;
要使用LCD1602,首先需要对其初始化,即通过写入一些特定的指令实现;
然后选择要在LCD1602的哪个位置显示并将所要显示的数据发送到LCD的DDRAM;
使用LCD1602通常都是用于写数据进去,很少使用读功能;
LCD1602操作步骤如下所示:
1 初始化
2 写命令(RS=L),设置显示坐标
3 写数据(RS=H)
LCD1602一般不需要读出它的数据的状态或者数据本身;
所以只需要看两个写时序:
LCD1602时序图:
从上图可以看到,以上给的时间参数全部是ns级别的,而51单片机的机器周期是1us,指令周期是2-4个机器周期,所以即便在程序里不加延时程序,也可以很好的配合LCD1602的时序要求;
当要写命令字节的时候,时间由左往右,RS变为低电平,R/W变为低电平,注意看是RS的状态先变化完成;
然后这时,DB0~DB7上数据进入有效阶段,接着E引脚有一个整脉冲的跳变,接着要维持时间最小值为tpw=400ns的E脉冲宽度;
然后E引脚负跳变,RS电平变化,R/W电平变化,这样便是一个完整的LCD1602写命令的时序;
注意:这里介绍的是8位LCD1602,现在某些公司为简化引脚数,使用4位LCD1602;使用4位LCD1602时,应该多看手册,找到不同点,对原有程序加以修改;
从线路图中可知,LCD1602的8位数据口D0-D7与单片机的P0.0-P0.7管脚连接,LCD1602的RS、WR、E脚与单片机的P2.6、P2.5、P2.7管脚连接;
RJ1是一个电位器,用来调节LCD1602对比度即显示亮度;
根据lcd1602的写指令和数据的时序编写相应程序;
根据lcd1602的指令格式,编写必要的初始化、清屏和显示程序;
main.c
/*
* @Description: 使LCD1602上显示字符信息
*/
#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)
{
}
}
public.h
#ifndef _public_H
#define _public_H
#include "reg52.h"
typedef unsigned int u16; // 对系统默认数据类型进行重定义
typedef unsigned char u8;
void delay_10us(u16 ten_us);
void delay_ms(u16 ms);
#endif
public.c
#include "public.h"
/**
* @description: 延时函数,ten_us=1时,大约延时10us
* @param {u16} ten_us 延时倍数
* @return {*}
*/
void delay_10us(u16 ten_us)
{
while (ten_us--)
;
}
/**ms延时函数,ms=1时,大约延时1ms***
* @param {u16} ms 延时倍数
* @return {*}
*/
void delay_ms(u16 ms)
{
u16 i, j;
for (i = ms; i > 0; i--)
for (j = 110; j > 0; j--)
;
}
lcd1602.h
#ifndef _lcd1602_H
#define _lcd1602_H
#include "public.h"
// LCD1602数据口4位和8位定义,若为1,则为LCD1602四位数据口驱动,反之为8位
#define LCD1602_4OR8_DATA_INTERFACE 0 // 默认使用8位数据口LCD1602
// 管脚定义
sbit LCD1602_RS = P2 ^ 6; // 数据命令选择
sbit LCD1602_RW = P2 ^ 5; // 读写选择
sbit LCD1602_E = P2 ^ 7; // 使能信号
#define LCD1602_DATAPORT P0 // 宏定义LCD1602数据端口
// 函数声明
void lcd1602_init(void);
void lcd1602_clear(void);
void lcd1602_show_string(u8 x, u8 y, u8 *str);
#endif
lcd1602.c
#include "lcd1602.h"
#if (LCD1602_4OR8_DATA_INTERFACE == 0) // 8位LCD
/**
* @description: LCD1602写命令
* @param {u8} cmd 指令
* @return {*}
*/
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
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
#if (LCD1602_4OR8_DATA_INTERFACE == 0) // 8位LCD
/**
* @description: LCD1602写数据
* @param {u8} dat 数据
* @return {*}
*/
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
#if (LCD1602_4OR8_DATA_INTERFACE == 0) // 8位LCD
/**
* @description: LCD1602初始化
* @return {*}
*/
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
/**
* @description: LCD1602清屏
* @return {*}
*/
void lcd1602_clear(void)
{
lcd1602_write_cmd(0x01);
}
/**
* @description: LCD1602显示字符
* @param {u8} x 坐标
* @param {u8} y 坐标
* @param {u8} *str 要显示的字符串
* @return {*}
*/
void lcd1602_show_string(u8 x, u8 y, u8 *str)
{
u8 i = 0;
if (y > 1 || x > 15)
return; // 行列参数不对则强制退出
if (y < 1) // 第1行显示
{
while (*str != '\0') // 字符串是以'\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 // 第2行显示
{
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++;
}
}
}
按F7编译,无错误,生成.hex文件,使用pz-isp将hex文件下载到单片机