可移植到任何数字时钟程序中,根据单片机型号以及晶振频率修改TH0和TL0的值。
智能日期时间累加,平闰年判断,当月天数判断功能,年计数值0~9999。
使用1秒的延迟函数,再加上时间判断计数函数的时间,误差非常大。
采用5毫秒定时器中断计数,中断触发后重置计数值并且5毫秒计数加1。
处理5毫秒计数以及时间判断计数函数,定时器仍在计数,准确触发高精度的5毫秒中断。
5毫秒计数加到200时,5毫秒计数清零并且触发时间计数函数,包含所有判断日期时间的指令在5毫秒内完成,如5毫秒内无法完成请改成更长毫秒时间中断1次,避免出现中断重入等问题。
若发现bug或其他建议意见请及时在楼下回复。
下面是源码:
#include "reg51.h"
#include "intrins.h"
sfr AUXR = 0x8E;
sbit led=P3^2; //秒闪烁指示灯
#define ui unsigned int
#define uc unsigned char
ui y; //定义变量年
uc m,d,h,i,s,w; //定义变量月、日、时、分、秒、周
uc ms5; //5毫秒定时器中断计数
void InitTimer0(void){ //初始化5毫秒定时器,根据晶振频率修改TH0和TL0的值。
TMOD = 0x01;
TH0 = 0x28;
TL0 = 0x00;
EA = 1;
ET0 = 1;
TR0 = 1;
}
bit if_leap_year(ui y){ //平闰年检测,闰年返回1,平年返回0
//闰年是4的倍数且不是100的倍数或者是400的倍数,否则是平年。
if((y%4 == 0 && y%100 != 0) || y%400 == 0){
return 1; //返回1表示闰年
} else { //否则就是平年
return 0; //返回0表示平年
}
}
uc get_mon_day_nbr(ui y,uc m){ //通过年月获取该月有多少天
if(m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) { //大
月则31天
return 31;
}
if(m == 4 || m == 6 || m == 9 || m == 11){ //小月则30天
return 30;
}
if(m == 2){ //2月
if(if_leap_year(y) == 1){ //闰年29天
return 29;
} else { //平年28天
return 28;
}
}
return 0;
}
bit dt_is_ok(ui y,uc m,uc d,uc w,uc h,uc i,uc s){ //检测设置的日期时间格式是否有效 1有
效0无效
if(w > 7 || w < 1) return 0; //星期大于7或小于1 返回0
if(y > 9999 || m > 12 || m < 1 || d < 1) return 0; //年大于999 或 月大于12 或
月小于1 或日小于1 返回0
if(d > get_mon_day_nbr(y,m)) return 0; //通过年月获取当月天数 大于该值 返回0
if(h > 23 || i > 59 || s > 59) return 0; //时大于23 或 分大于59 或秒大于59 返回
0
return 1; //检测有效 返回1
}
bit set_time(ui yy,uc mm,uc dd,uc ww,uc hh,uc ii,uc ss){ //设置日期时间
if(dt_is_ok(yy,mm,dd,ww,hh,ii,ss) == 1){ //检查日期时间格式有效
y=yy;m=mm;d=dd;w=ww; //设置年月日周
h=hh;i=ii;s=ss; //设置时分秒
return 1; //设置成功 返回1
} else { //格式无效 返回0
return 0;
}
}
void add_time(){ //时间步进1秒
s++; //秒加1
if(s>=60){ //秒加到60
s=0; //秒清零
i++; //分加1
if(i>=60){ //分加到60
i=0; //分清零
h++; //时加1
if(h>=24){ //时加到24
h=0; //时清零
d++; //日加1
w++; //星期加1
if(w > 7){ //星期超过7
w=1; //星期等于1
}
if(d > get_mon_day_nbr(y,m)){ //日超过当前年月的天数
d=1; //日清1
m++; //月加1
if(m > 12){ //月加到12以上
m=1; //月清1
y++; //年加1
if(y >= 10000){ //年加到10000
y=0; //年清零
}
}
}
}
}
}
}
void main(){ //入口函数,上电复位后在此开始执行指令。
P3=0xFF; //设置P3口全部为高电平
set_time(2000,1,1,6,0,0,0); //设置日期时间
AUXR |= 0x80; //关闭定时器0的12分频
InitTimer0(); //初始化5毫秒定时器
//死循环内可添加其他程序,只有中断触发后退出,中断返回后继续在原地运行程序。
while(1);
}
void Timer0Interrupt(void) interrupt 1{ //5毫秒定时器中断
//重置TH0与TL0的值,根据晶振频率修改TH0和TL0的值。
TH0 = 0x28;
TL0 = 0x00;
ms5++; //5毫秒中断计数加1
if(ms5%100 == 0)led=~led;
//5毫秒中断计数加到200 200*5=1000毫秒 1秒触发1次
if(ms5 >= 200){
ms5=0; //5毫秒计数清零
add_time(); //时间步进1秒
}
}
上一篇:单片机+LCD1602+HR-04显示屏显示超声波测距工作原理
下一篇:STC15408AS单片机的EEPROM测试程序
推荐阅读最新更新时间:2024-11-10 13:16
设计资源 培训 开发板 精华推荐
- 1.8V DC转DC硬盘单路输出电源
- LTC1262,闪存 VPP 发生器参考设计
- ADR550B 5Vout 高精度可调电压源的典型应用
- 用于线性相位控制调光器的 20W、5-LED 调光 LED 驱动器
- #第六届立创电赛#ESP_MASTER ESP32多功能开发板
- NCP130 300mA、极低压差偏置轨 CMOS 稳压器的典型应用
- LT1185IT 低压差稳压器的典型应用电路改善了高频纹波抑制
- FlyingRC-AM32-Test-V0.1
- 参考设计支持在 LED 照明设计中包含 FL7701
- 无线MCU STM32WB55RG Nucleo-64开发板,支持Arduino、ST Zio和morpho
- 快乐分享,月月有奖第26期如期而至~~
- 年末福利!2019 TI 工业应用精选课程汇总,抢楼赢好礼
- 下载白皮书 答题赢好礼|TE《智能监控应用连接解决方案指南》
- 【EEWORLD第三十届】2011年09月社区明星人物揭晓!
- 【MPS有奖活动】分享【PCB设计、焊接】问题或经验
- 下载泰克电源设计测试方案+图文攻略 帮助工程师解决电源效率问题。有好礼
- 【EEWORLD第二十九届】2011年08月社区明星人物揭晓!
- 瑞萨电子颠覆传统理念的嵌入式开发平台 Renesas Synergy™ 评估套件震撼来袭!答题即可免费申请!
- 是时候充充电啦!村田宠粉月重磅开启!
- 看视频赢京东卡 | 泰享实测之水哥秘籍第二期