单片机——LCD1602液晶显示模块

初始化

根据手册可以得知初始化过程:

  1. 延时 15ms
  2. 写指令 38H(不检测忙信号)
  3. 延时 5ms
  4. 以后每次写指令,读/写数据操作均需要检测忙信号
  5. 写指令 38H:显示模式设置
  6. 写指令 08H:显示关闭
  7. 写指令 01H:显示清屏
  8. 写指令 06H:显示光标移动设置
  9. 写指令 0CH:显示开及光标设置

代码如下:

//模块初始化
void LCD1602_Unit()
{
	//延时15ms
	Delay15ms();
	//写指令,不检测忙信号
	LCD_Select_Data(0x38);
	//延时5ms
	Delay5ms();
	//检测忙信号
	//写指令38H,显示模式设置
	LCD_Select_Cmd(0x38);
	//写指令08H:显示关闭
	LCD_Select_Cmd(0x08);
	//写指令01H,显示清屏
	LCD_Select_Cmd(0x01);
	//写指令06H,显示光标移动设置
	LCD_Select_Cmd(0x06);
	//写指令0CH,显示开及光标设置
	LCD_Select_Cmd(0x0c);
}

写操作时序分析

分析

由手册可以知道,RS为寄存器选择,高电平选择数据寄存器,低电平选择指令(地址)寄存器;而写操作,分为写数据和写地址
image.png

  1. 选择数据寄存器为例子,分析上图可以知道,当选择数据寄存器时,RS始终为高电平
  2. R/Wtsp1之前和thd1之后,即可为高电平,也可为低电平,而在tsp1thd1之间时,始终为低电平,则让R/W始终为低电平
  3. E的变化为0 1 0,同时DB0-DB7(简称DB)在E上升沿之前,而查看手册可以知道,tsp2,对于DB而言是代表着数据建立时间,故而,在E=1之前,需要先赋值再延时一段时间,然后在E从1变为0,再次延时tf,不放心就延时两次
  4. 注意时序是周期性的,

写地址和写数据函数如下

//选择地址
void LCD_Select_Cmd(char cmd)
{
	check_busy();//检测忙信号

	RS=0;
	RW=0;
	EN=0;
	_nop_();//tf
	
	databuffer=cmd;

	_nop_();
	EN=1;
	_nop_();//tf
	_nop_();//tf
	EN=0;
	_nop_();
}

//使用数据寄存器
void LCD_Select_Data(char ch)
{
	check_busy();//检测忙信号

	//选择数据寄存器
	RS=1;
	RW=0;
	EN=0;
	_nop_();
	
	databuffer=ch;

	_nop_();
	EN=1;
	_nop_();
	_nop_();
	EN=0;
	_nop_();
}

读操作时序分析

时序图如下

image.png

分析

  1. RS可高可低
  2. R/W在读取过程中是高电平,在读取前和读取之后,可高可低
  3. E的变化过程是0 1 0
  4. DB0-DB7依然是可高可低
  5. 与写操作时序不同点:Valid Data时期一定是在E为高电平时

函数代码

void check_busy()
{
	char tmp = 0x80;
	databuffer = 0x80;
	
	while(tmp & 0x80){
		//一直读取databuffer
		RS=0;
		RW=1;
		EN=0;
		_nop_();
		EN=1;
		_nop_();
		_nop_();
		tmp=databuffer;
		EN=0;
		_nop_();
    }
}

时序参数

image.png

小问题:

  1. 如何确定字符的显示位置:根据手册可以知道,写入显示地址时,要求最高位D7恒定为高电平1,所以第五位,实际写入的应当是0x80+0x05
  2. 如何检测忙信号:根据手册可以知道D7位,为忙标志位,当为1时,代表忙,此时不能接收命令或数据。所以通过循环读取检测忙信号

LCD1602,显示一个字符实例

#include "reg52.h"
#include <intrins.h>

#define databuffer P0
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^2;
sbit led1 = P3^7;

void Delay15ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 27;
	j = 226;
	do
	{
		while (--j);
	} while (--i);
}
void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 9;
	j = 244;
	do
	{
		while (--j);
	} while (--i);
}
void check_busy()
{
	char tmp = 0x80;
	databuffer = 0x80;
	//循环检测忙信号
	while(tmp & 0x80){
		//一直读取databuffer
		RS=0;
		RW=1;
		EN=0;
		_nop_();
		EN=1;
		_nop_();
		_nop_();
		tmp=databuffer;
		
		EN=0;
		_nop_();
	}
	
}
//选择地址
void LCD_Select_Cmd(char cmd)
{
	check_busy();

	RS=0;
	RW=0;
	EN=0;
	//数据建立延时
	_nop_();
	
	//数据建立
	databuffer=cmd;
	//E上升沿
	_nop_();
	EN=1;
	_nop_();
	_nop_();
	EN=0;
	_nop_();
}

//使用数据寄存器
void LCD_Select_Data(char ch)
{
	check_busy();

	//选择数据寄存器
	RS=1;
	RW=0;
	EN=0;
	//数据建立延时
	_nop_();
	
	//数据建立
	databuffer=ch;
	//E上升沿
	_nop_();
	EN=1;
	_nop_();
	_nop_();
	EN=0;
	_nop_();
}

//模块初始化
void LCD1602_Unit()
{
	//延时15ms
	Delay15ms();
	//写指令,不检测忙信号
	LCD_Select_Data(0x38);
	//延时5ms
	Delay5ms();
	//检测忙信号
	//写指令38H,显示模式设置
	LCD_Select_Cmd(0x38);
	//写指令08H:显示关闭
	LCD_Select_Cmd(0x08);
	//写指令01H,显示清屏
	LCD_Select_Cmd(0x01);
	//写指令06H,显示光标移动设置
	LCD_Select_Cmd(0x06);
	//写指令0CH,显示开及光标设置
	LCD_Select_Cmd(0x0c);
}

void main(){
	char position = 0x80+0x05;
	//初始化
	LCD1602_Unit();
	//选择地址
	LCD_Select_Cmd(position);
	//发送数据
	LCD_Select_Data('C');

}

进阶:显示一个字符串,关键代码如下

void show_string(int col,int rol,char* str)
{
	//col行,rol列,str需要显示的字符串
	switch(col){
		case 1:{
				LCD_Select_Cmd(0x80+rol);
				while(*str){
					LCD_Select_Data(*str);
					str++;
				}
			}
			break;
		case 2:{
					LCD_Select_Cmd(0x80+0x40+rol);
					while(*str){
					
					LCD_Select_Data(*str);
					str++;
				}
			}
			break;
	}
}
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值