基于51单片机的时钟设计.docx
《基于51单片机的时钟设计.docx》由会员分享,可在线阅读,更多相关《基于51单片机的时钟设计.docx(13页珍藏版)》请在冰点文库上搜索。
基于51单片机的时钟设计
单片机时钟
1.1单片机定时器的基本概念和相关寄存器
51系列单片机片内有二个十六位定时/计数器:
定时器0(T0)和定时器1(T1)。
两个定时器都有定时或事件计数的功能,可用于定时控制、延时、对外部事件计数和检测等场合,定时/计数器实际上是16位加1计数器。
T0由2个8位持殊功能寄存器TH0和TL0构成,
T1由2个8位持殊功能寄存TH1和TL1构成。
每个定时器都可由软件设置为定时工作方式或计数工作方式。
T0和T1受特殊功能寄存器TMOD和TCON控制。
1.2单片机中断系统和相关的寄存器
51单片机有5个中断请求源,两个中断优先级,可两级嵌套。
与中断有关的特殊功能寄存器SFR有定时器控制寄存器TCON、串行口控制寄存器SCON、中断允许寄存器IE、中断优先权寄存器IP。
1.3具体设计
1.3.1任务要求、任务分析
要求:
应用定时器和中断系统,比如电子时钟,参考功能有:
时间;年、月、日;闹钟;时间修改;年月日设置;闹钟时间设置。
分析:
运用中断系统实现定时器功能与显示。
1.3.2Proteus仿真原理图
1.3.3C语言程序算法分析与程序构架
#include
#defineucharunsignedchar
#defineuintunsignedint
//可位寻址单元的位定义
sbitLE1=P2^0;
sbitLE2=P2^1;
sbitKEY1=P2^2;
sbitKEY2=P2^3;
sbitKEY3=P2^4;
sbitSPEAK=P2^5;
sbitP26=P2^6;
sbitP27=P2^7;
sbitP10=P1^0;
sbitKEY4=P1^1;
sbitP30=P3^0;
sbitP31=P3^1;
sbitP32=P3^2;
sbitP33=P3^3;
sbitP34=P3^4;
sbitP35=P3^5;
sbitP36=P3^6;
sbitP37=P3^7;
sbitP12=P1^2;
//共阳LED显示代码
ucharLED_Duanxuan[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
//共阴LED显示代码
ucharLED_Duanxuan1[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
//LED位选
ucharLED_weixuan[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//显示缓冲区
ucharLED_DIS[8]={0,0,0,0,0,0,0,0};
ucharLED_Saomiao=0;
uchartime_50ms,i=0;
ucharsecond,minute,hour,minute1,day,mon,year,alhour,almin;
ucharnumber_key;
intn=0;
voiddelay(void);//延时程序
voiddisplay(void);//显示程序
voidkey_process(void);//按键处理程序
voidInitialize(void);//初始化程序
intLeepyear(unsignedintyear);
voidInitialize(void)
{
second=0;//秒
minute=0;//分
hour=0;//时
day=1;//日
mon=1;//月
year=0;//年
number_key=0;//按键次数
TH0=(65536-50000)/256;//定时50ms
TL0=(65536-50000)%256;
EA=1;//开中断总开关;
ET0=1;//允许定时器0中断开关;
TR0=1;//启动定时器T0;
LED_DIS[0]=LED_Duanxuan[0];//显示缓冲区初始化
LED_DIS[1]=LED_Duanxuan[1];
LED_DIS[2]=LED_Duanxuan[2];
LED_DIS[3]=LED_Duanxuan[3];
LED_DIS[4]=LED_Duanxuan[4];
LED_DIS[5]=LED_Duanxuan[5];
LED_DIS[6]=LED_Duanxuan[6];
LED_DIS[7]=LED_Duanxuan[7];
}
voidkey_process(void)
{
KEY1=1;
KEY2=1;
KEY3=1;//IO口读之前先写1;
if(P10==0&&P12==1)
{if(KEY1==0)//时分修改
{
(minute==59)?
(minute=0):
(minute++);
while(KEY1==0)display();//等待按键释放;
}
if(KEY2==0)
{
(hour==23)?
(hour=0):
(hour++);
while(KEY2==0)display();//等待按键释放;
}}
if(P10==1&&P12==1)//年月日修改
{if(KEY1==0)
{
(day==31)?
(day=1):
(day++);
while(KEY1==0)display();//等待按键释放;
}
if(KEY2==0)
{
(mon==12)?
(mon=1):
(mon++);
while(KEY2==0)display();//等待按键释放;
}
if(KEY3==0)
{
(year==99)?
(year=0):
(year++);
while(KEY3==0)display();
}
}
if(P12==0)
{if(KEY1==0)//闹钟时分修改
{
(almin==59)?
(almin=0):
(almin++);
while(KEY1==0)display();//等待按键释放;
}
if(KEY2==0)
{
(alhour==23)?
(alhour=0):
(alhour++);
while(KEY2==0)display();//等待按键释放;
}
}
}
voidalarm()
{if((hour==alhour)&&(minute==almin))//当时钟与设定值相同时发出声音
SPEAK=1;
if(KEY4==0)//手动按键停止
while(KEY4==0)display();
SPEAK=0;//闹钟停止
}
voidmain(void)
{
Initialize();
while
(1)
{
display();//调用显示程序
key_process();//调用按键处理程序
alarm();//调用闹钟
}
}
voiddisplay(void)//动态扫描显示
{
uinttemp=100;
LED_Saomiao++;
if(LED_Saomiao==8)LED_Saomiao=0;
P3=LED_weixuan[LED_Saomiao];//位选
LE2=1;
LE2=0;
P0=LED_DIS[LED_Saomiao];//段选
LE1=1;
LE1=0;
while(temp--);
}
voidtiming(void)interrupt1//定时器T0中断,50ms中断一次
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
time_50ms++;
if(time_50ms==200)
{
time_50ms=0;
second++;//秒加1;
if(second==60)
{
second=0;
minute++;//分钟加1;
if(minute==60)
{
minute=0;
hour++;//小时+1
if(hour==24)
{
hour=0;
day++;//日期加1;
}
if(mon==2&&day==29&&!
Leepyear(year))//判断是否2月28天且不为闰年
{day=1;
mon++;}//月份+1
if(mon==2&&day==30&&Leepyear(year))//判断是否2月29天且为闰年
{day=1;
mon++;}
if((mon==4|mon==6|mon==9|mon==11)&&day==31)
{day=1;
mon++;}
if((mon==1|mon==3|mon==5|mon==7|mon==8|mon==10|mon==12)&&day==32)
{day=1;
if(mon==12)
{mon=1;
year++;}
else
mon++;}
if(year==100)
year==0;
}
}
}if(P10==0&&P12==1)
{LED_DIS[0]=LED_Duanxuan[hour/10];//时
LED_DIS[1]=LED_Duanxuan[hour%10];
LED_DIS[2]=0xBF;//-
LED_DIS[3]=LED_Duanxuan[minute/10];//分
LED_DIS[4]=LED_Duanxuan[minute%10];
LED_DIS[5]=0xBF;//-
LED_DIS[6]=LED_Duanxuan[second/10];//秒
LED_DIS[7]=LED_Duanxuan[second%10];
}
if(P10==1&&P12==1)
{LED_DIS[0]=LED_Duanxuan[year/10];//年
LED_DIS[1]=LED_Duanxuan[year%10];
LED_DIS[2]=0xBF;//-
LED_DIS[3]=LED_Duanxuan[mon/10];//月
LED_DIS[4]=LED_Duanxuan[mon%10];
LED_DIS[5]=0xBF;//-
LED_DIS[6]=LED_Duanxuan[day/10];//日
LED_DIS[7]=LED_Duanxuan[day%10];
}
if(P12==0)
{LED_DIS[0]=LED_Duanxuan[alhour/10];//显示闹钟定时小时
LED_DIS[1]=LED_Duanxuan[alhour%10];
LED_DIS[2]=0xBF;//-
LED_DIS[3]=LED_Duanxuan[almin/10];/显示闹钟定时分钟
LED_DIS[4]=LED_Duanxuan[almin%10];
LED_DIS[5]=0xBF;//-
LED_DIS[6]=0xBF;//-
LED_DIS[7]=0xBF;//-
}}
intLeepyear(unsignedintyear)
{
if(year%4==0)//判断是否为闰年因为21世纪正好只要是4的倍数就为闰年....不支持其他世纪
return1;
else
return0;
}
1.3.4任务编程与调试
1P10=1P10=0时显示时间
KEY1调节分KEY2调节时
2P10=1P12=0显示日期KEY1调节日KEY2调节月KEY3调节年
3闹钟当P12=1时显示闹钟设置界面KEY1设置时KEY2设置分
图示设置8点时喇叭响起图中STOPALARM按键可以使闹钟停止