为什么我的LCD1602程序中指定显示位置的函数必须调用2次
#include<intrins.h> //包含_nop_()函数定义的头文件
#define uchar unsigned char
#define uint unsigned int
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;
sbit BF=P0^7; //忙碌标志位,,将BF位定义为P0.7引脚
sbit P32=P3^2;
void LCD_init(void);//初始化函数
void LCD_write_command(uchar command);//写指令函数
void LCD_write_data(uchar dat);//写数据函数
void WriteAddress(unsigned char x); //指定字符显示的实际地址 例如WriteAddress(0x03);表示:写地址,从第1行第4列开始显示
//void LCD_disp_char(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X(0-16),y(1-2)
uchar BusyTest(void);//检查忙函数。
void delay(uchar n);//延时函数
//********延时函数***************
void delay1ms(void) //误差 0us
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=142;b>0;b--)
for(a=2;a>0;a--);
}
void delay(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
void delay500ms(void) //误差 0us
{
unsigned char a,b,c;
for(c=23;c>0;c--)
for(b=152;b>0;b--)
for(a=70;a>0;a--);
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=1,忙碌;result=0,不忙
***************************************************/
uchar BusyTest(void)
{
bit result;
RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态
RW=1;
E=1; //E=1,才允许读写
_nop_(); //空操作
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
result=BF; //将忙碌标志电平赋给result
E=0; //将E恢复低电平
return result;
}
void LCD_init()
{
delay(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间
LCD_write_command(0x38); //显示模式设置:16×2显示,5×7点阵,8位数据接口
delay(5); //延时5ms ,给硬件一点反应时间
LCD_write_command(0x38);
delay(5);
LCD_write_command(0x38); //连续三次,确保初始化成功
delay(5);
LCD_write_command(0x0C); //显示模式设置:显示开,没光标,光标不闪烁
delay(5);
LCD_write_command(0x06); //显示模式设置:光标右移,字符不移
delay(5);
LCD_write_command(0x01); //清屏幕指令,将以前的显示内容清除
delay(5);
}
/*****************************************************
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:command
***************************************************/
void LCD_write_command(uchar command)
{
while(BusyTest()==1); //如果忙就等待
RS=0; //根据规定,RS和R/W同时为低电平时,可以写入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"0"
E=1; //E置高电平
P0=command; //将数据送入P0口,即写入指令或地址
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
/*****************************************************
函数功能:指定字符显示的实际地址
入口参数:x
***************************************************/
void WriteAddress(unsigned char x)
{
LCD_write_command(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
}
/*****************************************************
函数功能:将数据(字符的标准ASCII码)写入液晶模块
入口参数:y(为字符常量)
***************************************************/
void LCD_write_data(unsigned char y)
{
while(BusyTest()==1);
RS=1; //RS为高电平,RW为低电平时,可以写入数据
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"0"
P0=y; //将数据送入P0口,即将数据写入液晶模块
/* _nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
*/
E=1; //E置高电平
/* _nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
*/
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
//*******************************
//*********主函数*****************
void main(void)
{
uchar temp[]={"ABCDEFGHI"};
uint i = 0;
LCD_init();
E=0;
WriteAddress(0x01); //写地址,从第1行第4列开始显示
WriteAddress(0x01); //此处实验多次,该函数执行两次才能达到效果,不知为何,后面则没有出现类似情况,求解?
i=0; //从字符数组的第1个元素开始显示
while(temp[i]!='\0')
{
LCD_write_data(temp[i++]);
delay500ms();
}
WriteAddress(0x41); //写地址,从第1行第4列开始显示
i=0; //从字符数组的第1个元素开始显示
while(temp[i]!='\0')
{
LCD_write_data(temp[i++]);
delay(500); //此处并不是预期的500ms,比500ms短很多,求解?
}
/* WriteAddress(0x06);
LCD_write_data('A');
WriteAddress(0X07);
LCD_write_data('B');
*/
while(1)
{
if(!P32)
{
WriteAddress(0x0D);
LCD_write_data('P');
//delay(2000);
}
else
{
WriteAddress(0x0D);
LCD_write_data('B');
//delay(2000);
}
}
}
========================分割线=============================
就是上面程序中连续两个WriteAddress(0x01);这个位置,我调用一次没有,两次就有用,后面的都没有这个问题...
小弟昨晚搞了好久不知道怎么弄,程序是典型的LCD1602程序,有点长,烦劳有耐心的大哥大姐们看看。
调用后是否需要加个延时呢
先说你的延时吧 你的定义是char 他的范围是0-255 你写了个500 可定不会是500ms 你定义一个别的
unsigned int a,b,c;肯定就好了
再说你的你的两个延续 我认为你的当E由高电平跳变成低电平时开始写数据的时间有点短 还没有把数据写入
就开始了下一条语句 你加下延时看看吧
把你的程序改了下,可以试试。
========================================================
#include <reg52.h>
#include<intrins.h> //包含_nop_()函数定义的头文件
#define uchar unsigned char
#define uint unsigned int
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;
sbit BF=P0^7; //忙碌标志位,,将BF位定义为P0.7引脚
sbit P32=P3^2;
void LCD_init(void);//初始化函数
void LCD_write_command(uchar command);//写指令函数
void LCD_write_data(uchar dat);//写数据函数
void WriteAddress(unsigned char x); //指定字符显示的实际地址 例如WriteAddress(0x03);表示:写地址,从第1行第4列开始显示
//void LCD_disp_char(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X(0-16),y(1-2)
uchar BusyTest(void);//检查忙函数。
void delay(uchar n);//延时函数
//********延时函数***************
void delay1ms(void) //误差 0us
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=142;b>0;b--)
for(a=2;a>0;a--);
}
void delay(unsigned int n)//这里声明变量类型错误
{
unsigned int i;
for(i=0;i<n;i++)
delay1ms();
}
void delay500ms(void) //误差 0us
{
unsigned char a,b,c;
for(c=23;c>0;c--)
for(b=152;b>0;b--)
for(a=70;a>0;a--);
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=1,忙碌;result=0,不忙
***************************************************/
uchar BusyTest(void)
{
bit result;
RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态
RW=1;
E=1; //E=1,才允许读写
_nop_(); //空操作
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
result=BF; //将忙碌标志电平赋给result
E=0; //将E恢复低电平
return result;
}
void LCD_init()
{
delay(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间
LCD_write_command(0x38); //显示模式设置:16×2显示,5×7点阵,8位数据接口
delay(5); //延时5ms ,给硬件一点反应时间
LCD_write_command(0x38);
delay(5);
LCD_write_command(0x38); //连续三次,确保初始化成功
delay(5);
LCD_write_command(0x0C); //显示模式设置:显示开,没光标,光标不闪烁
delay(5);
LCD_write_command(0x06); //显示模式设置:光标右移,字符不移
delay(5);
LCD_write_command(0x01); //清屏幕指令,将以前的显示内容清除
delay(5);
}
/*****************************************************
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:command
***************************************************/
void LCD_write_command(uchar command)
{
while(BusyTest()==1); //如果忙就等待
RS=0; //根据规定,RS和R/W同时为低电平时,可以写入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"0"
E=1; //E置高电平
P0=command; //将数据送入P0口,即写入指令或地址
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
/*****************************************************
函数功能:指定字符显示的实际地址
入口参数:x
***************************************************/
void WriteAddress(unsigned char x)
{
LCD_write_command(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
}
/*****************************************************
函数功能:将数据(字符的标准ASCII码)写入液晶模块
入口参数:y(为字符常量)
***************************************************/
void LCD_write_data(unsigned char y)
{
while(BusyTest()==1);
RS=1; //RS为高电平,RW为低电平时,可以写入数据
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"0"
P0=y; //将数据送入P0口,即将数据写入液晶模块
/* _nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
*/
E=1; //E置高电平
/* _nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
*/
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
//*******************************
//*********主函数*****************
void main(void)
{
uchar temp[]={"ABCDEFGHI"};
uint i = 0;
LCD_init();
E=0;
WriteAddress(0x01); //写地址,从第1行第4列开始显示
//WriteAddress(0x01); //此处实验多次,该函数执行两次才能达到效果,不知为何,后面则没有出现类似情况,求解?//这里估计也是由于延时函数的问题导致的
i=0; //从字符数组的第1个元素开始显示
while(temp!='\0')
{
LCD_write_data(temp[i++]);
delay500ms();
}
WriteAddress(0x41); //写地址,从第1行第4列开始显示
i=0; //从字符数组的第1个元素开始显示
while(temp!='\0')
{
LCD_write_data(temp[i++]);
delay(500); //此处并不是预期的500ms,比500ms短很多,求解?
}
/* WriteAddress(0x06);
LCD_write_data('A');
WriteAddress(0X07);
LCD_write_data('B');
*/
while(1)
{
if(!P32)
{
WriteAddress(0x0D);
LCD_write_data('P');
//delay(2000);
}
else
{
WriteAddress(0x0D);
LCD_write_data('B');
//delay(2000);
}
}
}
谢谢你的指点,我今天白天去试试
谢谢你的修改,指定显示位置的函数一次就成功了。但是显示出现了问题,程序中while(),括号里面判断到字符串结束了就跳出循环。但是在屏幕上显示完“ABCDEFGHI”之后它继续在后面显示了各种乱码。正在找原因...
延时函数确实有问题...谢谢你
我在自己的程序里面把延时函数修改之后就正常了。总之还是要谢谢你帮我发现问题,这么长的程序放上来我真的有点不好意思了