LED 1602 时序理解 至 显示实现

需求:使用LED 1602模块,显示 NO.1_iKUN  / chang_tiao_rup ;

OK,我们先看下最终效果,再来详谈其实现,展示:

LED 1602 时序理解 至 显示实现_第1张图片

1.接线 LED 1602 时序理解 至 显示实现_第2张图片

VO:接个可调电阻到GND,方便调试对比度,提升显示效果,实在没有直接GND 在侧面找角度,也勉强能看 QAQ;

RS = P1^0; 
RW = P1^1;
EN = P1^4;

2.see see时序图,实现读写 数据/指令 函数封装;(see代码注释)

写指令+写数据(地址):

LED 1602 时序理解 至 显示实现_第3张图片

void write_cmd_func(char cmd)
{
	read_busy();
	RS = 0;	// RS低电平代表写 指令(确定位置);
	RW = 0;

	EN = 0; //根据时序图让E 开始跳变;
	_nop_();
	databuffer = cmd; //看时序图在等待E 变为高电压前,开始写入指令/数据;
	EN = 1;
	_nop_();
	EN = 0;
	_nop_();
	
}


void write_data_func (char userdata)
{
	read_busy();
	RS = 1;	// R高电平代表写 数据(显示字符)
	RW = 0;

	EN = 0;
	_nop_();
	databuffer = userdata; 	//看时序图在等待E 变为高电压前,开始写入指令/数据;
	EN = 1;
	_nop_();
	EN = 0;
	_nop_();	

}

读取忙标志 例: 

LED 1602 时序理解 至 显示实现_第4张图片

void read_busy()
{
	char tmp = 0x80;
	databuffer = 0x80;
	while(tmp & databuffer){ //只有当1602屏幕返回高位为0 时,即while(0); 推出循环; 
		RS = 0;
		RW = 1;	
		EN = 0;
		_nop_();	
		EN = 1;
		_nop_();
		tmp = databuffer; //看时序图在等待E 变为高电压后,开始读取指令/数据;
		EN = 0;
		_nop_();
	}

}

 3.最困难的日子过去了,再简单单写个void write_line_data(char hang,char qishilie,char *new),编译完成工程;

注意:

a.1602 其列的偏移是自动的,不需要写到循环里去控制,所以在每行开头声明一次即可;

b.再每次使用前,在主函数内需初始化1602(这条是必须的,手册要求)+ 清理屏幕(避免之前的数据(地址)残留);

源码展示:

#include "reg52.h"
#include  	//解决延时空函数_nop_报错;

#define databuffer P0 //8位数据线,使用P0端口组 ^0-7
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;

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 read_busy()
{
	char tmp = 0x80;
	databuffer = 0x80;
	while(tmp & databuffer){ //只有当1602屏幕返回高位为0 时,即while(0); 推出循环; 
		RS = 0;
		RW = 1;	
		EN = 0;
		_nop_();	
		EN = 1;
		_nop_();
		tmp = databuffer; //看时序图在等待E 变为高电压后,开始读取指令/数据;
		EN = 0;
		_nop_();
	}

}

void write_cmd_func(char cmd)
{
	read_busy();
	RS = 0;	// RS低电平代表写 指令(确定位置);
	RW = 0;

	EN = 0;
	_nop_();
	databuffer = cmd; //看时序图在等待E 变为高电压前,开始写入指令/数据;
	EN = 1;
	_nop_();
	EN = 0;
	_nop_();
	
}


void write_data_func (char userdata)
{
	read_busy();
	RS = 1;	// R高电平代表写 数据(显示字符)
	RW = 0;

	EN = 0;
	_nop_();
	databuffer = userdata; 	//看时序图在等待E 变为高电压前,开始写入指令/数据;
	EN = 1;
	_nop_();
	EN = 0;
	_nop_();	

}



void init1602()
{
	//  LCD1602 初始化过程(8bit)
	// (1)延时 15ms
	 Delay15ms();
	// (2)写指令 38H(不检测忙信号)
	write_cmd_func(0x38);
	// (3)延时 5ms
	Delay5ms();	
	// (4)以后每次写指令,读/写数据操作均需要检测忙信号
	//---见read_busy函数;
	// (5)写指令 38H:显示模式设置
	write_cmd_func(0x38);
	// (6)写指令 08H:显示关闭
	write_cmd_func(0x08);
	// (7)写指令 01H:显示清屏
	write_cmd_func(0x01);
	// (8)写指令 06H:显示光标移动设置
	write_cmd_func(0x06);
	// (9)写指令 0CH:显示开及光标设置
	write_cmd_func(0x0C);

}

void write_line_data(char hang,char qishilie,char *new)
{
	switch(hang){
		case 1:
			//写入显示地址(位置)时,每次都要让高位^7为高电平1 即+0x80;
			//注意:1602 其列的偏移是自动的,不需要写到循环里去控制,所以在每行开头声明一次即可;
			write_cmd_func(0x80+qishilie); 

			while(*new){				
				write_data_func(*new);
				new++;
			}
			break;
		case 2:
			//第二行位置地址是0x40开头,所以位置在第二行就要+0x40;
			write_cmd_func(0x80+0x40+qishilie);		

			while(*new){
				write_data_func(*new);
				new++;
			}	
			break;		
	}

}

void main ()
{
	init1602();
	write_cmd_func(0x01); //清理之前的显示
	
	write_line_data(1,3,"NO.01_iKUN");
	write_line_data(2,1,"chang_tiao_rup");
	
}

分享作者在调试撸码过程中遇到的一个大坑:

//如果变量名直接写成data,会导致一直报错;

//因为data是C语言中的保留关键字之一,会产生冲突报错;

【代码重构了也不行,最后的最后排查到了它,真的这种小基础很容易让人遗忘;切记切记!!!】 ToT  

最后预祝大家赏kun顺利!!QAQ 

LED 1602 时序理解 至 显示实现_第5张图片

你可能感兴趣的:(单片机,嵌入式硬件,c语言)