单片机:如何读取时序图(以LCD1602为例)

第13章 1602液晶与串口的应用实例

LCD1602读写时序图

在这里插入图片描述
大家看到这种图的时候,不要感觉害怕。说句不过分的话,单片机这些逻辑上的问题,只要小学毕业就可以理解的,很多时候是因为大家把问题想象的太难才学不下去的。

我们先来看一下读操作时序的 RS 引脚和 R/W 引脚,这两个引脚先进行变化,因为是读操作,所以 R/W 引脚首先要置为高电平,而不管它原来是什么。读指令还是读数据,都是读操作,而且都有可能,所以 RS 引脚既有可能是置为高电平,也有可能是置为低电平,大家注意图上的画法。而 RS 和 R/W 变化了经过 Tsp1 这么长时间后,使能引脚 E 才能从低电平到高电平发生变化。

而使能引脚E 拉高经过了tD 这么长时间后,LCD1602 输出DB 的数据就是有效数据了,我们就可以来读取 DB 的数据了。读完了之后,我们要先把使能 E 拉低,经过一段时间后 RS、R/W 和 DB 才可以变化继续为下一次读写做准备了。

而写操作时序和读操作时序的差别,就是写操作时序中,DB 的改变是由单片机来完成的,因此要放到使能引脚 E 的变化之前进行操作,其它区别大家可以自行对比一下。

细心的同学会发现,这个时序图上还有很多时间标签。比如 E 的上升时间 tR,下降时间时间 tF,使能引脚 E 从一个上升沿到下一个上升沿之间的长度周期 tC,使能 E 下降沿后,R/W 和 RS 变化时间间隔 tHD1 等等很多时间要求,这些要求怎么看呢?放心,只要是正规的数据手册,都会把这些时间要求给大家标记出来的。我们来看一下表 13-1。
表 13-1 1602 时序参数

时序参数 符号 极限值 单位 测试条件
最小值 典型值 最大值
E 信号周期 tC 400 -- -- ns 引脚E
E 脉冲宽度 tPW 150 -- -- ns
E 上升沿/下降沿时间 tR, tF -- -- 25 ns
地址建立时间 tSP1 30 -- -- ns 引脚E、
RS、R/W
地址保持时间 tHD1 10 -- -- ns
数据建立时间(读) tD -- -- 100 ns 引脚
DB0~DB7
数据保持时间(读) tHD2 20 -- -- ns
数据建立时间(写) tSP2 40 -- -- ns
数据保持时间(写) tHD2 10 -- -- ns

* tC:指的是使能引脚 E 从本次上升沿到下次上升沿的最短时间是 400ns,而我们单片机因为速度较慢,一个机器周期就是 1us 多,而一条 C 语言指令肯定是一个或者几个机器周期的,所以这个条件完全满足。 * tPW:指的是使能引脚 E 高电平的持续时间最短是 150ns,同样由于我们的单片机比较慢,这个条件也完全满足。 * tR, tF:指的是使能引脚 E 的上升沿时间和下降沿时间,不能超过 25ns,别看这个数很小,其实这个时间限值是很宽裕的,我们实际用示波器测了一下开发板的这个引脚上升沿和下降沿时间大概是 10ns 到 15ns 之间,完全满足。 * tSP1:指的是 RS 和 R/W 引脚使能后至少保持 30ns,使能引脚 E 才可以变成高电平,这个条件同样也完全满足。 * tHD1:指的是使能引脚 E 变成低电平后,至少保持 10ns 之后,RS 和 R/W 才能进行变化,这个条件也完全满足。 * tD:指的是使能引脚 E 变成高电平后,最多 100ns 后,1602 就把数据送出来了,那么我们就可以正常去读取状态或者数据了。 * tHD2:指的是读操作过程中,使能引脚 E 变成低电平后,至少保持 20ns,DB 数据总线才可以进行变化,这个条件也完全满足。 * tSP2:指的是 DB 数据总线准备好后,至少保持 40ns,使能引脚 E 才可以从低到高进行使能变化,这个条件也完全满足。 * tHD2:指的是写操作过程中,要引脚 E 变成低电平后,至少保持 10ns,DB 数据总线才可以变化,这个条件也完全满足。


/**
* 实现字符串在1602液晶上的左移
**/
#include <reg52.h>
#define LCD1602_DB P0

sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_E = P2^7;

void initLcd1602();
void lcdShowStr(unsigned char x,unsigned char y,
	unsigned char *ptr, unsigned char len);
void configTimer0(unsigned int ms);

bit flag500ms=0;  //500ms定时标志
unsigned char T0TH = 0;  //T0定时器重载值的高字节
unsigned char T0TL=0;
//待显示的第一行字符串
unsigned char code str1[]="acktomas studio";
//第二行字符串,需保持与第一行字符串等长,长度不足时可用空格补齐
unsigned char code str2[]="let's move...";

void main()
{    
	unsigned char i;
	unsigned char index = 0;  //移动索引
	unsigned char pdata bufMove1[16+sizeof(str1)+16];	//移动显示缓冲区1
	unsigned char pdata bufMove2[16+sizeof(str2)+16];
	EA = 1;
	configTimer0(10);  //配置T0定时器10ms
	initLcd1602();
	//缓冲区起始填充16个空格,对应屏幕每行16个字符
	for(i=0; i<16; i++)
	{
		bufMove1[i] = ' ';
		bufMove2[i] = ' ';
	}
	//待显示字符拷贝到缓冲区中间位置
	for(i=0; i<(sizeof(str1)-1);i++)  //sizeof(str1)-1去掉最后字符''
	{
		bufMove1[16+i] = str1[i];
		bufMove2[16+i] = str2[i];
	}
	//缓冲区结尾一段填充为空格
	for(i=(16+sizeof(str1)-1);i<sizeof(bufMove1);i++)
	{
		bufMove1[i] = ' ';
		bufMove2[i] = ' ';
	}
	
	while(1)
	{
		if (flag500ms)
		{
			flag500ms = 0;
			//从缓冲区抽出需显示的一段字符显示在液晶上
			lcdShowStr(0,0,bufMove1+index, 16);
			lcdShowStr(0,1,bufMove2+index, 16);
			//移动索引递增,实现左移
			index++;
			if (index >= (16+sizeof(str1)-1))
			{
				index = 0;
			}
		}
	}
}
/**
*  名称:
*  功能:配置并启动T0,
*  参数:ms--T0定时器时间
**/
void configTimer0(unsigned int ms)
{
	unsigned long tmp;
	tmp=12000000 / 12;  	//得到定时器计数频率
	tmp=(tmp*ms)/1000;		//计算所需的计数值
	tmp=65536 - tmp; 			//计算定时器重载值
	tmp = tmp + 12;				//补偿中断响应延时造成的误差
	T0TH = (unsigned char )(tmp>>8);
	T0TL = (unsigned char)tmp;
	TMOD &=0xF0;					//清零T0的控制位
	TMOD |=0x01;					//配置T0为模式1
	TH0 = T0TH;
	TL0 = T0TL;
	ET0=1;
	TR0=1;
}

/**
*  名称:
*  功能:等待LCD准备好
*  参数:
**/
void lcdWaitReady()
{
	unsigned char sta;
	LCD1602_DB =0xFF;
	LCD1602_RS = 0;
	LCD1602_RW=1;
	do {
		LCD1602_E=1;
		sta=LCD1602_DB;  //读取状态字
		LCD1602_E=0;
	} while(sta & 0x80); 	//bit7等于1,表示忙,需要重新检测
}


/**
*  名称:
*  功能:向LCD写入命令
*  参数:
**/
void lcdWriteCmd(unsigned char cmd)
{
	lcdWaitReady(); 	//此功能使得E使能端为低电平
	LCD1602_RS=0;
	LCD1602_RW=0;
	LCD1602_DB=cmd;
	LCD1602_E=1;
	LCD1602_E=0;
}

/**
*  名称:
*  功能:向LCD写入一个字节数据
*  参数:dat待写入数据
**/
void lcdWriteDat(unsigned char dat)
{
	lcdWaitReady(); 	//此功能使得E使能端为低电平
	LCD1602_RS=1;
	LCD1602_RW=0;
	LCD1602_DB=dat;
	LCD1602_E=1;
	LCD1602_E=0;
}
/**
*  名称:
*  功能:设置显示RAM起始地址,即光标位置
*  参数:x--列数,y--行数
**/
void lcdSetCursor(unsigned char x, unsigned char y)
{
	unsigned char addr;
	
	if(y==0)
		addr = 0x00+x;
	else
		addr = 0x40 + x;
	lcdWriteCmd(addr | 0x80); //设置RAM地址
}

/**
*  名称:
*  功能:在液晶上显示字符串
*  参数:x--列数,y--行数,*str--字符串指针
**/
void lcdShowStr(unsigned char x, unsigned char y,
	unsigned char *str,unsigned char len)
{
	lcdSetCursor(x,y);
	
	while (len--)
		lcdWriteDat(*str++);  //先取*str,再str++
}	


/**
*  名称:
*  功能:初始化LCD1602
*  参数:
**/
void initLcd1602()
{
	lcdWriteCmd(0x38); 	//16*2,5*7点阵,8位数据接口
	lcdWriteCmd(0x0c);	//显示器开,光标关闭
	lcdWriteCmd(0x06);	//文字不动,地址自动+1
	lcdWriteCmd(0x01);	//清屏(显示和地址指针)
}

/**
*  名称:
*  功能:T0中断服务函数,定时500ms
*  参数:
**/
void interruptTimer0() interrupt 1
{
	static unsigned char tmr500ms = 0;
	TH0 = T0TH;
	TL0 = T0TL;
	tmr500ms++;
	if (tmr500ms >= 50)
	{
		tmr500ms=0;
		flag500ms=1;
	}
}

版权声明:本文为CSDN博主「acktomas」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/acktomas/article/details/104658669

生成海报
点赞 0

acktomas

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

单片机:串口通信

RS-422A RS-422A输出驱动器为双端平衡驱动器。如果其中一条线为逻辑“1”状态,另一条线就为逻辑“0”,比采用单端不平衡驱动对电压的放大倍数大一倍。差分电路能从地线干扰中拾取有效信号,差分接收

单片机:EEPROM(IIC总线)

I2C总线只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。 I2C总线通过上拉电阻接正电源。当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都将使总线的信号变低&#xff

单片机:DS18B20温度传感器原理

DS18B20数字温度传感器接线方便,封装后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式。主要根据应用场合的不同而改变其外观。封装后的DS18B20可用于电缆