用Proteus联合Keil联合调试做 LCD液晶显示器 显示的应用仿真问题

2024-12-14 17:54:27
推荐回答(2个)
回答1:

/*
名称:单片机时钟
作者:李嘉鹏
时间:2009-9-19
bug:当s1按下七次以后,间歇性停表,猜测是由于主函数过长无法及时检测到
*/
#include
//#include

#define uchar unsigned char
#define uint unsigned int //宏定义uchar、uint

//声明管脚
sbit lcden=P3^4;//1602使能端
sbit rs=P3^5; //数据命令选择端
sbit dula=P2^6; //数码管断选
sbit wela=P2^7; //数码管位选
sbit rd=P3^7; //键盘置零端
sbit s1=P3^0; //按键1
sbit s2=P3^1; //按键2
sbit s3=P3^2; //按键3

uchar week[][3]= //数组储存星期
{{' '},{'M','O','N'},{'T','U','E'},
{'W','E','N'},
{'T','H','U'},
{'F','R','I'},
{'S','T','A'},
{'S','U','N'}};

/*****************************************************************************
*声明变量:
*count:连同定时器控制一秒钟的时间
*nian:存储年份
*yue:存储月份
*ri:存储日期
*shi:存储当前小时
*fen:存储当前分钟
*miao:存储当前秒数
*num:向液晶中写星期时控制for循环的次数
*t:控制冒号闪烁,0为显现,1为隐去
*tt:连同定时器控制冒号每500ms闪烁一次
*s1num:记录s1按下的次数,每7次清零一次
*addr:控制向液晶中写字符时的地址
*temp:中间变量,按下s1后,记录当前位置的值(年月日时分秒),控制选择位置的闪烁
******************************************************************************/
uchar count,yue,ri,xq,shi,fen,miao,num,t,tt,s1num,addr;
uint nian,temp;

//延时函数
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--)
;
}

//向1602液晶写指令函数
void write_com(uchar com)
{
rs=0;
lcden=0;
P0=com;
delay(5);
lcden=1;
lcden=0;
}

//向1602液晶中写数据函数
void write_dt(uchar dt)
{

rs=1;
lcden=0;
P0=dt;
delay(5);
lcden=1;
lcden=0;
}

//向液晶第二行某位置写两位连续空字符
void adwrite_kong(uchar ad)
{
write_com(0x80+0x40+ad-1);
write_dt(0x20);
write_dt(0x20);
}

//向液晶第一行某位置写两位连续空字符
void adwrite_kong1(uchar ad)
{
write_com(0x80+ad-1);
write_dt(0x20);
write_dt(0x20);
}

//向1602液晶第二行特定地址写入数据
void adwrite_dt2(uchar ad,uchar dt)
{
uchar shi,ge;
shi=dt/10;
ge=dt%10;
write_com(0x80+0x40+ad-1);
write_dt(0x30+shi);
write_dt(0x30+ge);
}

//向1602液晶第一行特定地址写入数据
void adwrite_dt1(uchar ad,uchar dt)
{
uchar shi,ge;
shi=dt/10;
ge=dt%10;
write_com(0x80+ad-1);
write_dt(0x30+shi);
write_dt(0x30+ge);
}

//向液晶上写年份
void adwrite_nian(uint dt)
{
uchar qian,bai,shi,ge;
qian=dt/1000;
bai=dt%1000/100;
shi=dt%100/10;
ge=dt%10;
write_com(0x80+1);
write_dt(0x30+qian);
write_dt(0x30+bai);
write_dt(0x30+shi);
write_dt(0x30+ge);

}

//初始化函数
void init()//initial
{
//开启定时器
TMOD=0x01;//选择方式1
EA=1; //开总中断
TR0=1; //开定时器0
ET0=1; //开定时/计数器0允许
TH0=(65536-64000)/256;//赋初值
TL0=(65536-64000)%256;

s1=1;//引脚置高
s2=1;
s3=1;

nian=2009;//赋初值
yue=9;
ri=19;
xq=3;
shi=0;
fen=0;
miao=0;
t=1;

rd=0;

wela=0;//关闭数码管显示
dula=0; //关闭数码管
lcden=0;
write_com(0x38);//显示模式设置
write_com(0x0c);//显示开,光标显示闪烁
write_com(0x06);//写字符后地址指针自加一
write_com(0x01);//清屏
write_com(0x80+0x01); //写地址
adwrite_nian(nian);
adwrite_dt1(7,yue);
adwrite_dt1(10,ri);
adwrite_dt2(5,shi);
adwrite_dt2(8,fen);
adwrite_dt2(11,miao);
write_com(0x80+5);
write_dt('-');
write_com(0x80+8);
write_dt('-');
write_com(0x80+0x40+6);
write_dt(':');
write_com(0x80+0x40+9);
write_dt(':');
write_com(0x80+12);
for(num=0;num<3;num++)
{
write_dt(week[xq][num]);
}
}

void shanshuo(uchar flag)//使冒号闪烁
{
if(flag==1)
{
write_com(0x80+0x40+6);
write_dt(' ');
write_com(0x80+0x40+9);
write_dt(' ');
}
else
{
write_com(0x80+0x40+6);
write_dt(':');
write_com(0x80+0x40+9);
write_dt(':');
}
}

//键盘检测
uchar keyscan()
{
rd=0;
if(s1==0)
{
delay(5);
if(s1==0) //检测s1按下
{
while(!s1);
TR0=0; //关闭定时器
write_com(0x80+0x40+6); //由于定时器关闭冒号隐去重新写两个冒号
write_dt(':');
write_com(0x80+0x40+9);
write_dt(':');

temp=miao;//记录当前位置的值
addr=11; //记录当前闪烁位置的地址
while(1)
{
//根据s1按下的次数判断闪烁的位置
if(s1num==0||s1num==1||s1num==2)
{
adwrite_kong(addr);
delay(100);
adwrite_dt2(addr,temp);
delay(100);
}
if(s1num==3)
{
write_com(0x80+11+1);
for(num=0;num<3;num++)
{
write_dt(' ');
}
delay(100);
write_com(0x80+11+1);
for(num=0;num<3;num++)
{
write_dt(week[xq][num]);
}
delay(100);

}
if(s1num==4||s1num==5)
{
adwrite_kong1(addr);
delay(100);
adwrite_dt1(addr,temp);
delay(100);
}
if(s1num==6)
{
adwrite_kong1(addr);
adwrite_kong1(2);
delay(100);
adwrite_nian(temp);
delay(100);
}

//判断s1按下的次数
if(s1==0)
{
delay(5);
if(s1==0)
{
while(!s1);
s1num++;
}
}

//根据s1按下的次数配合s2、s3键调节闪烁位置的值
if(s1num==0)
{
if(s2==0)
{
delay(5);
if(s2==0)
{
if(miao<59)
miao++;
else
miao=0;
addr=11;
temp=miao;
}
}
if(s3==0)
{
delay(5);
if(s3==0)
{
if(miao>0)
miao--;
else
miao=59;
addr=11;
temp=miao;

}
}
}
if(s1num==1)
{
addr=8;
temp=fen;
if(s2==0)
{
delay(5);
if(s2==0)
{
if(fen<59)
fen++;
else
fen=0;
addr=8;
temp=fen;
}
}
if(s3==0)
{
delay(5);
if(s3==0)
{
if(fen>0)
fen--;
else
fen=59;
addr=8;
temp=fen;

}
}
}
if(s1num==2)
{
addr=5;
temp=shi;
if(s2==0)
{
delay(5);
if(s2==0)
{
if(shi<23)
shi++;
else
shi=0;
addr=5;
temp=shi;
}
}
if(s3==0)
{
delay(5);
if(s3==0)
{
if(shi>0)
shi--;
else
shi=23;
addr=5;
temp=shi;

}
}
}
if(s1num==3)
{
if(s2==0)
{
delay(5);
if(s2==0)
{
while(!s2);
xq++;
if(xq==8)
xq=1;

}
}
if(s3==0)
{
delay(5);
if(s3==0)
{
while(!s3);
if(xq>1)
xq--;
else
xq=7;

}
}
} //星期
if(s1num==4)
{
addr=10;
temp=ri;
if(s2==0)
{
delay(5);
if(s2==0)
{
ri++;
if(ri==31&&(yue==6||yue==4||yue==9||yue==11))
{
ri=1;
}
if(ri==32&&(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12))
{
ri=1;
}
if(ri==30&&(nian%400==0||(nian%4==0&&nian%100!=0))&&yue==2)
{
ri=1;
}
if(ri==29&&(!(nian%400==0||(nian%4==0&&nian%100!=0)))&&yue==2)
{
ri=1;
}
addr=10;
temp=ri;
}
}
if(s3==0)
{
delay(5);
if(s3==0)
{
if(ri>1)
ri--;
else
{
if(yue==6||yue==4||yue==9||yue==11)
{
ri=30;
}
if(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12)
{
ri=31;
}
if((nian%400==0||(nian%4==0&&nian%100!=0))&&yue==2)
{
ri=29;
}
if((!(nian%400==0||(nian%4==0&&nian%100!=0)))&&yue==2)
{
ri=28;
}
}
addr=10;
temp=ri;

}
}
} //日
if(s1num==5)
{
addr=7;
temp=yue;
if(s2==0)
{
delay(5);
if(s2==0)
{
yue++;
if(yue==13)
yue=1;
addr=7;
temp=yue;
}
}
if(s3==0)
{
delay(5);
if(s3==0)
{
if(yue>1)
yue--;
else
yue=12;
addr=7;
temp=yue;

}
}
} //月
if(s1num==6)
{
addr=4;
temp=nian;
if(s2==0)
{
delay(5);
if(s2==0)
{
nian++;
if(nian==9999)
nian=2009;
addr=4;
temp=nian;

}
}
if(s3==0)
{
delay(5);
if(s3==0)
{
if(nian>2009)
nian--;
else
nian=9999;
addr=4;
temp=nian;

}
}//年
}
if(s1num>=7)
{

s1num=0;
if(ri>30&&(yue==6||yue==4||yue==9||yue==11))
{
ri=30;
}
if(ri>=30&&(nian%400==0||(nian%4==0&&nian%100!=0))&&yue==2)
{
ri=29;
}
if(ri>29&&(!(nian%400==0||(nian%4==0&&nian%100!=0)))&&yue==2)
{
ri=28;
}
adwrite_dt1(10,ri);
TR0=1;
TH0=(65536-64000)/256;
TL0=(65536-64000)%256;
// break;//退出循环
return 0;//返回0结束函数
}

}
return 0;//返回0结束函数
}
}
}

//主函数
void main()
{
init();
while (1)
{
keyscan();
if(count==14)
{
count=0;
TH0=(65536-64000)/256;
TL0=(65536-64000)%256;
miao++;
if(miao==60)
{
miao=0;
fen++;
if(fen==60)
{
fen=0;
shi++;
if(shi==24)
{
shi=0;
ri++;
if(ri==31&&(yue==6||yue==4||yue==9||yue==11))
{
ri=1;
yue++;
adwrite_dt1(7,yue);
}
if(ri==32&&(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12))
{
ri=1;
yue++;
if(yue==13)
{
yue=1;
nian++;
adwrite_nian(nian);
}
adwrite_dt1(7,yue);
}
if(ri==30&&(nian%400==0||(nian%4==0&&nian%100!=0))&&yue==2)
{
ri=1;
yue++;
adwrite_dt1(7,yue);
}
if(ri==29&&(!(nian%400==0||(nian%4==0&&nian%100!=0)))&&yue==2)
{
ri=1;
yue++;
adwrite_dt1(7,yue);
}
xq++;
if(xq==8)
{
xq=1;
}
switch(xq)
{
case 1:
write_com(0x80+11+1);
for(num=0;num<3;num++)
{
write_dt(week[xq][num]);
}
case 2:
write_com(0x80+11+1);
for(num=0;num<3;num++)
{
write_dt(week[xq][num]);
}

case 3:
write_com(0x80+11+1);
for(num=0;num<3;num++)
{
write_dt(week[xq][num]);
}

case 4:
write_com(0x80+11+1);
for(num=0;num<3;num++)
{
write_dt(week[xq][num]);
}

case 5:
write_com(0x80+11+1);
for(num=0;num<3;num++)
{
write_dt(week[xq][num]);
}

case 6:
write_com(0x80+11+1);
for(num=0;num<3;num++)
{
write_dt(week[xq][num]);
}

case 7:
write_com(0x80+11+1);
for(num=0;num<3;num++)
{
write_dt(week[xq][num]);
}
}
adwrite_dt1(10,ri);
}
adwrite_dt2(5,shi);
}
adwrite_dt2(8,fen);
}
adwrite_dt2(11,miao);
}
}
}

//定时器控制时间每一秒加一
void timer0() interrupt 1
{
count++;
tt++;
if(tt==7)
{
tt=0;
shanshuo(t);
if(t==0)
t=1;
else
t=0;
}
}
这是我编的LCD1602的程序,你参考一下吧

回答2:

这是个1602显示移动程序,你看看吧,可能对你有用

#include
#include

#define uchar unsigned char
#define uint unsigned int

sbit LCD_RS = P2^0;
sbit LCD_RW = P2^1;
sbit LCD_EN = P2^2;

uchar code dis1[] = {" CHINESE "};
uchar code dis2[] = {" NEW YEAR "};

/*******************************************************************/
/* */
/* 延时子程序 */
/* */
/*******************************************************************/

void delay(int ms)
{
int i;
while(ms--)
{
for(i = 0; i< 250; i++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}

/*******************************************************************/
/* */
/*检查LCD忙状态 */
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。 */
/* */
/*******************************************************************/

bit lcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
_nop_();
_nop_();
_nop_();
_nop_();
result = (bit)(P0&0x80);
LCD_EN = 0;
return result;
}

/*******************************************************************/
/* */
/*写指令数据到LCD */
/*RS=L,RW=L,E=高脉冲,D0-D7=指令码。 */
/* */
/*******************************************************************/

void lcd_wcmd(uchar cmd)
{
while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
P0 = cmd;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN = 1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN = 0;
}

/*******************************************************************/
/* */
/*写显示数据到LCD */
/*RS=H,RW=L,E=高脉冲,D0-D7=数据。 */
/* */
/*******************************************************************/

void lcd_wdat(uchar dat)
{
while(lcd_busy());
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
P0 = dat;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN = 1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN = 0;
}

/*******************************************************************/
/* */
/* 设定显示位置 */
/* */
/*******************************************************************/

void lcd_pos(uchar pos)
{
lcd_wcmd(pos|0x80); //数据指针=80+地址变量
}

/*******************************************************************/
/* */
/* LCD初始化设定 */
/* */
/*******************************************************************/

void lcd_init()
{
delay(15); //等待LCD电源稳定
lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据
delay(5);
lcd_wcmd(0x38);
delay(5);
lcd_wcmd(0x38);
delay(5);

lcd_wcmd(0x0c); //显示开,关光标
delay(5);
lcd_wcmd(0x06); //移动光标
delay(5);
lcd_wcmd(0x01); //清除LCD的显示内容
delay(5);
}

/*******************************************************************/
/* */
/* 清屏子程序 */
/* */
/*******************************************************************/

void lcd_clr()
{
lcd_wcmd(0x01); //清除LCD的显示内容
delay(5);
}

/*******************************************************************/
/* */
/* 闪动子程序 */
/* */
/*******************************************************************/

void flash()
{
delay(600); //控制停留时间
lcd_wcmd(0x08); //关闭显示
delay(200); //延时
lcd_wcmd(0x0c); //开显示
delay(200);
lcd_wcmd(0x08); //关闭显示
delay(200); //延时
lcd_wcmd(0x0c); //开显示
delay(200);
}

/*******************************************************************/
/* */
/* 主程序 */
/* */
/*******************************************************************/

main()
{
uchar i,j;
delay(10);
lcd_init(); //初始化LCD

while(1)
{
lcd_clr();

lcd_pos(0x10); //设置显示位置为第一行第17列
i = 0;

while(dis1[i] != '\0')
{ //显示字符" CHINESE "
lcd_wdat(dis1[i]);
i++;
}

lcd_pos(0x50); //设置显示位置为第二行第17列
i = 0;

while(dis2[i] != '\0')
{
lcd_wdat(dis2[i]); //显示字符" NEW YEAR "
i++;
}

for(j=0 ;j< 29 ;j++) //向左移动29格
{
lcd_wcmd(0x18) ; //字符同时左移一格
delay(100) ; //控制移动时间
}

for(j=0 ;j< 13 ;j++) //向右移动13格
{
lcd_wcmd(0x1C) ; //字符同时左移一格
delay(100) ; //控制移动时间
}
flash() ; //闪动二次

}
}