//程序功能:日历,时钟,温度显示(测温代码暂没加上,加上后程序将超过4k,注意芯片型号选用),温度传感器采用18B20
// 日历与时钟,温度分时切换显示,采用8位共阳数码管
// 数据输出P1, 位码驱动P2
// 也可以采用12864LCD显示,该程序暂时没写.
#include
#include
#define unchar unsigned char
#define unint unsigned int
unchar code dispcode[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,
0Xbf,0x9c,0xc6,0x7f,0xff}; //数码管字形表,0-9,-,o,C,.,灭
unchar code rili1997code[]={0x2,0x5,0x5,0x1,0x3,0x6,0x1,0x4,0x0,0x2,0X5,0x0}; //1996年12个月的月份星期校正码
unchar timecnt=19; //定时中断计数器
unchar timeadd1=0; //时间加1判断
unchar newday=0; //日期加1判断
unchar week; //星期
unchar data date[]={9,12,9};
unchar data time[]={11,59,55};
unchar data wendu[]={14,19,116}; //wendu[0]=10为负,显示-;wendu[0] =14为正,符号位不显示, 原理参考数码管字形表
//wendu[1]是整数温度值,wendu[2]/10是"°"显示,wendu[2]/10+1显示C,wendu[2]%110是小数点后的温度值
unchar t=150; //延时常数
unchar cnt=0; //显示控制计数器
//#define SSL 0x7f //秒低位段码地址
//#define SSH 0XBF //秒高位段码地址
//#define _L 0XDF //8位数码管显示,分钟与秒之间的-分隔符
//#define MML 0XEF //以下同
//#define MMH 0XF7
//#define _H 0XFB //8位数码管显示,小时与分钟之间的-分隔符
//#define HHL 0XFD
//#define HHH 0XFE
sbit timeset=P3^2; //时间调整键
sbit dateset=P3^3; //日历调整键
sbit add=P3^4; //加调整
sbit dec=P3^5; //减调整
//日期加1函数
//当日期有进位时调用,判断年,月,日的最大值
void dateadd1(unchar i)
{
{ unchar j=0;
switch(i)
{ case 0:if(date[0]==99) //年采用低2位表示
date[0]=0;
else
date[0]++;break;
case 1:if(date[1]==12)
date[1]=1;
else
date[1]++;break;
case 2:
switch(date[1])
{case 4: //4,6,9,11月的最大天数是30
case 6:
case 9:
case 11:if(date[2]==30)
{date[2]=1;
j++; //j++表示月份加1,以下同
}
else
{date[2]++; }
break;
case 1: //1,3,5,7,8,10,12月的最大天数是31
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: if(date[2]==31)
{date[2]=1; j++; }
else
date[2]++; break;
case 2:if(date[0]%400==0) //2月份需要判断是否是闰年
{if(date[2]==29) //能被400整除的世纪年是闰年
{date[2]=1; j++; } //闰年2月29天,月份加1
else
date[2]++;break;
}
else
{if(date[0]%4==0) //非世纪年,能被4整除是闰年
{if(date[2]==29)
{date[2]=1;j++; }
else
date[2]++; break;
}
else
{if(date[2]==28) //非闰年2月28天
{date[2]=1;j++;}
else
date[2]++; break;
}
}
default:break;
}
if(j)
{ if(date[1]==12) //如果进位的月份是12月,置月份date[1]为1
date[1]=1;
else
date[1]++;
}
} }
}
void datedec1(unchar i)
{ unchar j=0;
switch(i)
{ case 0: if(date[0]==0)
date[0]=99;
else
date[0]--;break;
case 1:if(date[1]==0)
date[1]=12;
else
date[1]--;break;
case 2:
switch(date[1])
{ case 4: //4,6,9,11月的最大天数是30
case 6:
case 9:
case 11:if(date[2]==0)
date[2]=30;
else
date[2]--;
break;
case 1: //1,3,5,7,8,10,12月的最大天数是31
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: if(date[2]==0)
date[2]=31;
else
date[2]--; break;
case 2:if(date[0]%400==0) //2月份需要判断是否是闰年
{if(date[2]==0) //能被400整除的世纪年是闰年
date[2]=29; //闰年2月29天,月份进位
else
date[2]--;break;
}
else
{if(date[0]%4==0) //非世纪年,能被4整除是闰年
{if(date[2]==0)
date[2]=29;
else
date[2]--; break;
}
else
{if(date[2]==0) //非闰年2月28天
date[2]=28;
else
date[2]--; break;
}
}
default:break;
}
}
}
void add1(unchar i) //时间加1函数
{
if(i)
{
timeadd1--;
if(time[2]==59) //秒加1
{time[2]=0;
time[1]++;
if(time[1]==60) //分加1
{time[1]=0;
time[0]++;
if(time[0]==24) //小时加1
{ time[0]=0;
newday++;
}
}
}
else
time[2]++;
}
//if(newday)
// {
// dateadd1(newday);
// }
}
//延时函数
void delay(unchar x)
{unsigned char i=0;
while(i
}
//显示函数:
//(1)显示时间,格式:HH(2位)-(1位)MM(2位)(空1位) SS(2位)(共8位),
//(2)显示日历,格式:月(2位)-(1位)日(2位)(空2位) 星期(1位),
//(3)显示日期(只在调整日期时出现),格式:年-月 日
//(4)显示温度
//(5)显示过程:30秒的前25秒显示时间,后5秒显示日历
void display(unchar x,unchar y,unchar z,unchar r,unchar k)
{ unchar a=150;
cnt++;
if(cnt==300)
cnt=0; //函数使用说明:
if(((r!=5)&&(r!=2))||(cnt>a)||(r==6)) //显示函数x,y,z参数,分别对应显示时间的时,分,秒,或显示日期的年,月,日
{if(r==6)
P1=dispcode[z/10+1];
else
P1 =dispcode[z%10]; //或显示日历的,月,日,星期,或温度的正负,温度,oC.
P2 =0x7f;//SSL; //k:星期控制参数,当显示日历时,k=1,星期显示一位数,k为其他值时,不影响其他显示方式
delay(t); //r:显示控制参数,当r取不同值时,闪动显示待调整项,只有闪动项才可以用键盘调整其值.
if( k!=1) //当r分别取0,1,2,时,对应的hh,mm,ss将闪动,进入调整.r为3,4,5时,分别对应年,月,日闪动调整
{P1=dispcode[z/10]; //r=6时,为显示温度时,特有的方式
P2=0xbf;//SSH; //
delay(t);
}
}
if(((r!=4)&&(r!=1))||(cnt>a)||(r==6))
{ if(r==6)
P1=dispcode[y%10]-0x80; //用于显示小数点
else
P1 =dispcode[y%10];
P2=0xef;//MML; //
delay(t);
if(r==6) //当温度的高位是0时,不显示
if(y/10==0)
P1=dispcode[14];
P1=dispcode[y/10];
P2=0xf7;//MMH; //
delay(t);
}
if((r==6)||((r!=3)&&(r!=0))||(cnt>a))
{if(r==6)
P1=0XFF;
else
P1 =dispcode[x%10];
P2=0xfd;//HHL;
delay(t);
if(r==6)
P1=0XFF;
else
P1=dispcode[x/10];
P2=0xfe;//HHH;
delay(t);
}
if((r==6)||(cnt>a)) //r=6可用于温度测量显示控制
{if(r==6)
P1=dispcode[wendu[0]];
else
P1 =dispcode[10];//dispcode[y%10];
P2=0xfb;//_H;
delay(t);
}
if(r==6)
{P1=dispcode[wendu[2]%110];
P2=0xdf;
delay(t);
}
}
void keyscan() //键盘扫描函数,用于扫描P3.2(timeset),P3.3(dateset),P3.4(add),P3.5(dec)键是否按下
{ unchar i=0,j=0;
if(dateset==0)
{display(date[0],date[1],date[2],8,0); //延时
if(dateset==0)
while(i<3)
{ display(date[0],date[1],date[2],i,0);
if(add==0)
{display(date[0],date[1],date[2],i,0);
if(add==0)
dateadd1(i);
display(date[0],date[1],date[2],i,0);
display(date[0],date[1],date[2],i,0);
display(date[0],date[1],date[2],i,0);
display(date[0],date[1],date[2],i,0);
}
if(dec==0)
{display(date[0],date[1],date[2],i,0);
if(dec==0)
datedec1(i);
display(date[0],date[1],date[2],i,0);
display(date[0],date[1],date[2],i,0);
display(date[0],date[1],date[2],i,0);
display(date[0],date[1],date[2],i,0);
}
if(dateset==0)
{display(date[0],date[1],date[2],i,0);
if(dateset==0)
i++;
display(date[0],date[1],date[2],i,0);
display(date[0],date[1],date[2],i,0);
display(date[0],date[1],date[2],i,0);
display(date[0],date[1],date[2],i,0);
}
}
}
if(timeset==0)
{delay(100); //短暂延时
if(timeset==0)
delay(100);
while(j<3)
{ display(time[0],time[1],time[2],j,0);
if(add==0)
{delay(200);
if(add==0)
{ //delay(200);
switch(j)
{case 0:if(time[0]==24)
time[0]=0;
else
time[0]++;break;
display(time[0],time[1],time[2],j,0);
case 1:
case 2:if(time[j]==60)
time[j]=0;
else
time[j]++;
default:break;
} //delay(100);
// display(time[0],time[1],time[2],j,0);
}
}
if(dec==0)
{delay(200);
if(dec==0)
switch(j)
{case 0:if(time[0]==0)
time[0]=23;
else
time[0]--;break;
display(time[0],time[1],time[2],j,0);
case 1:
case 2:if(time[j]==0)
time[j]=59;
else
time[j]--;
display(time[0],time[1],time[2],j,0);
default:break;
} delay(100);
}
if(timeset==0)
{
display(time[0],time[1],time[2],j,0);
//display(time[0],time[1],time[2],j,0);
if(timeset==0)
j++;
}
}
}
}
void datetoweek(unchar x,unchar y,unchar z,unchar p) //计算指定日期是星期几,x,y,z参数分别为年,月,日;
{if(p)
{ int year;
year=1997+x+3;
dateadd1(2);
newday--;
if((year%400)==0) //p为是否执行该函数条件,即变量newday(由hh进位产生),
{if(y<3) //当hh没有进位时,newday=0,不执行该函数
{unchar i,j; //日期加1,要进行日历调整
j=rili1997code[y-1];
i=(((year-1997)/4+(year-1997)+j)-1);
week=(z+i+1)%7; //
}
else
{unchar i,j;
j=rili1997code[y-1];
i=(((year-1997)/4+(year-1997)+j));
week=(z+i+1)%7;
}
}
else
{ if(year%4==0)
{if(y<3)
{unchar i,j;
j=rili1997code[y-1];
i=(((year-1997)/4+(year-1997)+j)-1);
week=(z+i+1)%7;
}
else
{unchar i,j;
j=rili1997code[y-1];
i=(((year-1997)/4+(year-1997)+j));
week=(z+i+1)%7;
}
}
else
{ unchar i,j;
j=rili1997code[y-1];
i=(((year-1997)/4+(year-1997)+j));
week=(z+i+1)%7;
}
}
}
}
void displaycontrol() //显示控制函数
{
if(time[2]%30<=20) //30秒的前25秒显示时间,后5秒显示日历
display(time[0],time[1],time[2],7,0);
//if((time[2]%30<=25)&&(time[2]%30>20))
else
if(time[2]%30<=25)
display(date[1],date[2],week,8,1);
// if((time[2]%30<=30)&&(time[2]%30>25))
else
display(wendu[0],wendu[1],wendu[2],6,0);
}
void main(void) // 主函数
{
TMOD=0x01;
TH0=((65535-50000)/256); //定时器赋初值
TL0=((65535-50000)%256);
ET0=1;
EA=1;
TR0=1;
while(1)
{
keyscan(); //键盘扫描
add1(timeadd1); //加1
datetoweek(date[0],date[1],date[2],newday);
displaycontrol(); //时间,日历,温度等显示控制
}
}
void t0 (void)interrupt 1 using 0 //定时中断函数
{
TH0+=((65536-50000)/256);
TL0+=((65536-50000)%256);
timecnt--;
if(timecnt==0)
{ timecnt=19;
timeadd1++;
}
}
上一篇:Keil C51程序设计中精确延时的总结
下一篇:89C51单片机的P0~P3端口进行输入时为什么要设置为1?
推荐阅读最新更新时间:2024-03-16 15:22
- 热门资源推荐
- 热门放大器推荐