AT89C51单片机万年历LCD显示实现日期时间温度闹钟功能详解
一.设计功能
1、实现日历功能,显示年月日时分秒
2、测量温度并显示
3、具有闹钟功能,可设置闹钟时间
4、温度超过上下限则启动报警
5、使用存储器芯片存储系统参数,掉电保存
二、程序流程图
三、仿真
日期 星期 时间 当前温度
下一页
闹钟时间 温度上限 温度下限
四、相关程序
sbit beep=P2^7;//蜂鸣器
sbit k1=P3^2;
sbit k2=P3^3;
sbit k3=P3^4;
sbit k4=P3^5;
//-----------------------------------显示数组
uchar ye=0;//第一页
uchar hang1[]="2000.00.00 0 ";//日期+星期
uchar hang2[]="00:00:00 T:000 C";//时间+温度
uchar hang3[]="lock 00:00 ";//第二页 闹钟
uchar hang4[]="L:000 C H:000 C";//温度阀值
uchar lcd_xian=0;//显示延时变量
//-----------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>光标位置
uchar cursor=0;//光标位置
uchar code cursor_num[]={1,3,1,6,1,9,1,12,2,1,2,4,2,7,1,6,1,9,2,4,2,13};//光标位置数组.行+列
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//###################################测量值变量
uchar wendu=0,wen_L=10,wen_H=30;//温度+阀值
uchar shi=6,fen=0;//闹钟
//###################################
//**************************************主函数
void main()
{
uchar two;
//11111111111111111111111111111111基本模块初始化
hang2[14]=0xdf;
hang4[5]=0xdf;
hang4[14]=0xdf;
init_1602();
Ds1302ReadTime();//启动DS1302
TIME[0]=0;
Ds1302Init();
//11111111111111111111111111111111
//22222222222222222222222222222222显示初始化
wen_L=At24c02Read(0); //读取温度阀值
if(wen_L>200)
{
wen_L=10;
At24c02Write(0,wen_L);
Delay1ms(10);
}
wen_H=At24c02Read(1);
if(wen_H>200)
{
wen_H=10;
At24c02Write(1,wen_H);
Delay1ms(30);
}
shi=At24c02Read(2);
if(shi>200)
{
shi=6;
At24c02Write(2,shi);
Delay1ms(10);
}
fen=At24c02Read(3);
if(fen>200)
{
fen=0;
At24c02Write(3,fen);
Delay1ms(10);
}
//22222222222222222222222222222222
//===============定时器初始化
TMOD|=0X01;
TH0=0X3C;
TL0=0XB0;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
//===============
while(1)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;判断报警
if((wendu>wen_H)||(wendu<wen_L)||((TIME[2]==shi)&&(TIME[1]==fen)))//蜂鸣器判断
beep=0;
else
beep=1;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//'''''''''''''''''''''''''''''''''''''''''''按键检测
if(!k1) //换页
{
ye=!ye;
if(ye)
cursor=7;//设置光标
else
cursor=0;
while(!k1);
}
if(!k2) //下一个
{
if(ye)
{
if(cursor<10)
cursor++;
else
cursor=7;
}
else
{
if(cursor<6)
cursor++;
else
cursor=0;
}
while(!k2);
}
if(!k3)//加
{
switch(cursor)
{
case 0://设置年
two=(TIME[6]>>4)*10+(TIME[6] &0x0f);
if(two<99)
two++;
TIME[6]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 1://设置月
two=(TIME[4]>>4)*10+(TIME[4] &0x0f);
if(two<12)
two++;
TIME[4]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 2://设置日
two=(TIME[3]>>4)*10+(TIME[3] &0x0f);
if(two<30)
two++;
TIME[3]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 3://设置星期
if(TIME[5]<8)
TIME[5]++;
Ds1302Init();
break;
case 4://设置时
two=(TIME[2]>>4)*10+(TIME[2] &0x0f);
if(two<23)
two++;
TIME[2]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 5://设置分
two=(TIME[1]>>4)*10+(TIME[1] &0x0f);
if(two<59)
two++;
TIME[1]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 6://设置秒
two=(TIME[0]>>4)*10+(TIME[0] &0x0f);
if(two<59)
two++;
TIME[0]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 7://设置时 闹钟
two=(shi>>4)*10+(shi &0x0f);
if(two<23)
two++;
shi=(two/10<<4)+two%10;
At24c02Write(2,shi);
Delay1ms(10);
break;
case 8://设置分
two=(fen>>4)*10+(fen &0x0f);
if(two<59)
two++;
fen=(two/10<<4)+two%10;
At24c02Write(3,fen);
Delay1ms(10);
break;
case 9://设置温度低阀值
if(wen_L<100)
wen_L++;
At24c02Write(0,wen_L);
Delay1ms(10);
break;
case 10://设置温度高阀值
if(wen_H<100)
wen_H++;
At24c02Write(1,wen_H);
Delay1ms(10);
}
while(!k3);
}
if(!k4)//减
{
switch(cursor)
{
case 0://设置年
two=(TIME[6]>>4)*10+(TIME[6] &0x0f);
if(two>0)
two--;
TIME[6]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 1://设置月
two=(TIME[4]>>4)*10+(TIME[4] &0x0f);
if(two>1)
two--;
TIME[4]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 2://设置日
two=(TIME[3]>>4)*10+(TIME[3] &0x0f);
if(two>1)
two--;
TIME[3]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 3://设置星期
if(TIME[5]>2)
TIME[5]--;
Ds1302Init();
break;
case 4://设置时
two=(TIME[2]>>4)*10+(TIME[2] &0x0f);
if(two>0)
two--;
TIME[2]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 5://设置分
two=(TIME[1]>>4)*10+(TIME[1] &0x0f);
if(two>0)
two--;
TIME[1]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 6://设置秒
two=(TIME[0]>>4)*10+(TIME[0] &0x0f);
if(two>0)
two--;
TIME[0]=(two/10<<4)+two%10;
Ds1302Init();
break;
case 7://设置时 闹钟
two=(shi>>4)*10+(shi &0x0f);
if(two>0)
two--;
shi=(two/10<<4)+two%10;
At24c02Write(2,shi);
Delay1ms(10);
break;
case 8://设置分
two=(fen>>4)*10+(fen &0x0f);
if(two>0)
two--;
fen=(two/10<<4)+two%10;
At24c02Write(3,fen);
Delay1ms(10);
break;
case 9://设置温度低阀值
if(wen_L>0)
wen_L--;
At24c02Write(0,wen_L);
Delay1ms(10);
break;
case 10://设置温度高阀值
if(wen_H>0)
wen_H--;
At24c02Write(1,wen_H);
Delay1ms(10);
}
while(!k4);
}
//''''''''''''''''''''''''''''''''''''''''''''
}
}
//*******************************************
//-----------------------------------------显示
void Timer0() interrupt 1
{
if(lcd_xian<5)
lcd_xian++;
else
{
lcd_xian=0;
//==============================显示计算
//()()()()()()()()测量
wendu=Ds18b20ReadTemp();//温度
Ds1302ReadTime();//读取时间
//()()()()()()()()
hang1[2]=(TIME[6]>>4)+0X30; //年
hang1[3]=(TIME[6]& 0X0F)+0X30;
hang1[5]=(TIME[4]>>4)+0X30; //月
hang1[6]=(TIME[4]& 0X0F)+0X30;
hang1[8]=(TIME[3]>>4)+0X30; //日
hang1[9]=(TIME[3]& 0X0F)+0X30;
hang1[12]=TIME[5]+0X2f; //星期
hang2[0]=(TIME[2]>>4)+0X30; //时
hang2[1]=(TIME[2]& 0X0F)+0X30;
hang2[3]=(TIME[1]>>4)+0X30; //分
hang2[4]=(TIME[1]& 0X0F)+0X30;
hang2[6]=(TIME[0]>>4)+0X30;//秒
hang2[7]=(TIME[0]& 0X0F)+0X30;
hang2[11]=wendu/100+0x30;//温度
hang2[12]=wendu%100/10+0x30;
hang2[13]=wendu%10+0x30;
//阀值显示计算
hang3[5]=(shi>>4)+0x30;//时 闹钟
hang3[6]=(shi &0x0f)+0x30;
hang3[8]=(fen>>4)+0x30;//分
hang3[9]=(fen &0x0f)+0x30;
hang4[2]=wen_L/100+0x30;//温度低
hang4[3]=wen_L%100/10+0x30;
hang4[4]=wen_L%10+0x30;
hang4[11]=wen_H/100+0x30;//温度高
hang4[12]=wen_H%100/10+0x30;
hang4[13]=wen_H%10+0x30;
//===============================
//+++++++++++++++++++++++++++++++显示
write_com(0x0c);
if(ye==0)
{
write_string(1,0,hang1);//显示第一页
write_string(2,0,hang2);
}
else
{
write_string(1,0,hang3);//显示第二页
write_string(2,0,hang4);
}
write_com(0x0e);
write_sfm(cursor_num[2*cursor],cursor_num[2*cursor+1]);//设置光标位置
//+++++++++++++++++++++++++++++++
}
TH0=0X3C;//给定时器赋初值,定时50ms
TL0=0XB0;
}