51单片机 - 电子万年历 - timer

Emily ·
更新时间:2024-09-21
· 686 次阅读

51单片机 - 电子万年历 - timer

本文用于阐述使用51单片机制作万年历过程中的定时部分,软件特性可以在proteus上仿真,使用51单片机定时器T0做万年历计时信号源。采用12MHz晶振,中断1ms计时方式,误差低。下面直接上代码:

电子万年历计时结构体定义

用于存储万年历计时时间,包含年份、月份、天数、时分秒、毫秒等等。

typedef struct { // 电子万年历变量 u16 year; u8 month; u8 day; u8 hour; u8 miunte; u8 second; u16 ms; } time_t; 万年历变量初始化 time_t time = { 2020, 2, 2, 20, 2, 2, 0 }; // 电子万年历变量 u8 time_update = 1; // 更新显示等级,值越小等级越高,1为最高等级,0为最低 初始化定时器T0

初始化T0进行毫秒定时中断,并启动T0。

/******************************************************************************* * 函 数 名 : timer_init * 函数功能 : 初始化定时器 * 输 入 : void * 输 出 : void * 说 名 : none *******************************************************************************/ void timer_init(void) // 初始化定时器 { time.year = 2020; // 电子万年历变量 time.month = 2; time.day = 2; time.hour = 20; time.miunte = 2; time.second = 2; time.ms = 0; time_update = 1; // 更新显示等级,值越小等级越高,1为最高等级,0为最低 TMOD |= 0x01; // 定时器T0工作与方式1 IE |= 0x82; TL0 = 0x18; // 计时1ms TH0 = 0xfc; TR0 = 1; // 启动定时器 } 中断计时程序

年月日,时分秒定时计数,电子万年历的核心代码,计时过程中中引入闰年判断,timer_set_update_level()函数用于统筹当前万年历计时更新的最高位,在lcd1602上显示使用此机制可避免无意义的显示刷新,能有效提高代码执行效率。

/******************************************************************************* * 函 数 名 : t0_timer * 函数功能 : T0中断服务 * 输 入 : void * 输 出 : void * 说 名 : none *******************************************************************************/ void t0_timer(void) interrupt 1 // T0中断服务 { TL0 = 0x18; // 重装初值 TH0 = 0xfc; time.ms++; timer_set_update_level(7); // 豪秒更新 if (time.ms < 1000) { // 1秒 return; } time.ms = 0; // ms清零 time.second++; timer_set_update_level(6); // 秒更新 if (time.second < 60) { // 1分 return; } time.second = 0; // 秒清零 time.miunte++; timer_set_update_level(5); // 分更新 if (time.miunte < 60) { // 1时 return; } time.miunte = 0; // 分清零 time.hour++; timer_set_update_level(4); // 时更新 if (time.hour < 24) { // 1天 return; } time.hour = 0; // 时清零 time.day++; timer_set_update_level(3); // 天更新 if ((time.month == 2 && ((time.day == 30) || (!(!(time.year % 4) && ((time.year % 100) || !(time.year % 400))) && (time.day == 29)))) || ((time.day == 32) && ((time.month == 1) || (time.month == 3) || (time.month == 5) || (time.month == 7) || (time.month == 8) || (time.month == 10) || (time.month == 12))) || ((time.day == 31) && ((time.month == 4) || (time.month == 6) || (time.month == 9) || (time.month == 11)))) { time.day = 1; // 返回1日 time.month++; // 1月 timer_set_update_level(2); // 月更新 } else { return; } if (time.month YEAR_MAX) { // 最大年份 time.year = YEAR_MAX; } } 定时器测试代码

用于测试万年历计时的准确性以及可靠性。

/******************************************************************************* * 函 数 名 : test_timer * 函数功能 : timer测试代码 * 输 入 : void * 输 出 : void * 说 名 : none *******************************************************************************/ void test_timer(void) // timer测试代码 { lcd1602_init(); timer_init(); while (1) { switch (time_update) { // 判断更新 case 1: time_update = 0; lcd1602_set_pos(0, 0); lcd1602_write_num(4, time.year); lcd1602_write_data('-'); // 年更新 case 2: time_update = 0; lcd1602_set_pos(5, 0); lcd1602_write_num(2, time.month); lcd1602_write_data('-'); // 月更新 case 3: time_update = 0; lcd1602_set_pos(8, 0); lcd1602_write_num(2, time.day); // 日更新 case 4: time_update = 0; lcd1602_set_pos(1, 1); lcd1602_write_num(2, time.hour); lcd1602_write_data(':'); // 时更新 case 5: time_update = 0; lcd1602_set_pos(4, 1); lcd1602_write_num(2, time.miunte); lcd1602_write_data(':'); // 分更新 case 6: time_update = 0; lcd1602_set_pos(7, 1); lcd1602_write_num(2, time.second); break; // 秒更新 default: break; // 无更新 } } } 附录 – 万年历定时代码(timer.h) #ifndef __TIMER_H__ #define __TIMER_H__ #include "include.h" #define YEAR_MAX 9999 // 最大年份数 typedef struct { // 电子万年历变量 u16 year; u8 month; u8 day; u8 hour; u8 miunte; u8 second; u16 ms; } time_t; void timer_init(void); // 初始化定时器 void timer_deinit(void); // 定时器去初始化 void timer_set_update_level(u8 level); // 刷新时间更新等级 void test_timer(void); // timer测试代码 #endif 附录 – 万年历定时代码(timer.c) #include #include "timer.h" #include "lcd1602.h" time_t time = { 2020, 2, 2, 20, 2, 2, 0 }; // 电子万年历变量 u8 time_update = 1; // 更新显示等级,值越小等级越高,1为最高等级,0为最低 /******************************************************************************* * 函 数 名 : timer_init * 函数功能 : 初始化定时器 * 输 入 : void * 输 出 : void * 说 名 : none *******************************************************************************/ void timer_init(void) // 初始化定时器 { time.year = 2020; // 电子万年历变量 time.month = 2; time.day = 2; time.hour = 20; time.miunte = 2; time.second = 2; time.ms = 0; time_update = 1; // 更新显示等级,值越小等级越高,1为最高等级,0为最低 TMOD |= 0x01; // 定时器T0工作与方式1 IE |= 0x82; TL0 = 0x18; // 计时1ms TH0 = 0xfc; TR0 = 1; // 启动定时器 } /******************************************************************************* * 函 数 名 : timer_deinit * 函数功能 : 定时器去初始化 * 输 入 : void * 输 出 : void * 说 名 : none *******************************************************************************/ void timer_deinit(void) // 定时器去初始化 { TR0 = 0; // 关闭定时器 IE &= 0x9d; // 禁止T0中断 TMOD &= 0xfe; TL0 = 0x18; // 计时1ms TH0 = 0xfc; time.year = 0; // 电子万年历变量 time.month = 0; time.day = 0; time.hour = 0; time.miunte = 0; time.second = 0; time.ms = 0; time_update = 0; // 更新显示等级,值越小等级越高,1为最高等级,0为最低 } /******************************************************************************* * 函 数 名 : timer_set_update_level * 函数功能 : 刷新时间更新等级 * 输 入 : level:更新等级 * 输 出 : void * 说 名 : none *******************************************************************************/ void timer_set_update_level(u8 level) // 刷新时间更新等级 { if (time_update != 0) { if (level < time_update) { time_update = level; } } else { time_update = level; } } /******************************************************************************* * 函 数 名 : t0_timer * 函数功能 : T0中断服务 * 输 入 : void * 输 出 : void * 说 名 : none *******************************************************************************/ void t0_timer(void) interrupt 1 // T0中断服务 { TL0 = 0x18; // 重装初值 TH0 = 0xfc; time.ms++; timer_set_update_level(7); // 豪秒更新 if (time.ms < 1000) { // 1秒 return; } time.ms = 0; // ms清零 time.second++; timer_set_update_level(6); // 秒更新 if (time.second < 60) { // 1分 return; } time.second = 0; // 秒清零 time.miunte++; timer_set_update_level(5); // 分更新 if (time.miunte < 60) { // 1时 return; } time.miunte = 0; // 分清零 time.hour++; timer_set_update_level(4); // 时更新 if (time.hour < 24) { // 1天 return; } time.hour = 0; // 时清零 time.day++; timer_set_update_level(3); // 天更新 if ((time.month == 2 && ((time.day == 30) || (!(!(time.year % 4) && ((time.year % 100) || !(time.year % 400))) && (time.day == 29)))) || ((time.day == 32) && ((time.month == 1) || (time.month == 3) || (time.month == 5) || (time.month == 7) || (time.month == 8) || (time.month == 10) || (time.month == 12))) || ((time.day == 31) && ((time.month == 4) || (time.month == 6) || (time.month == 9) || (time.month == 11)))) { time.day = 1; // 返回1日 time.month++; // 1月 timer_set_update_level(2); // 月更新 } else { return; } if (time.month YEAR_MAX) { // 最大年份 time.year = YEAR_MAX; } } /******************************************************************************* * 函 数 名 : test_timer * 函数功能 : timer测试代码 * 输 入 : void * 输 出 : void * 说 名 : none *******************************************************************************/ void test_timer(void) // timer测试代码 { lcd1602_init(); timer_init(); while (1) { switch (time_update) { // 判断更新 case 1: time_update = 0; lcd1602_set_pos(0, 0); lcd1602_write_num(4, time.year); lcd1602_write_data('-'); // 年更新 case 2: time_update = 0; lcd1602_set_pos(5, 0); lcd1602_write_num(2, time.month); lcd1602_write_data('-'); // 月更新 case 3: time_update = 0; lcd1602_set_pos(8, 0); lcd1602_write_num(2, time.day); // 日更新 case 4: time_update = 0; lcd1602_set_pos(1, 1); lcd1602_write_num(2, time.hour); lcd1602_write_data(':'); // 时更新 case 5: time_update = 0; lcd1602_set_pos(4, 1); lcd1602_write_num(2, time.miunte); lcd1602_write_data(':'); // 分更新 case 6: time_update = 0; lcd1602_set_pos(7, 1); lcd1602_write_num(2, time.second); break; // 秒更新 default: break; // 无更新 } } } 附录 – 通用数据类型定义 typedef char s8; typedef unsigned char u8; typedef short s16; typedef unsigned short u16; typedef long s32; typedef unsigned long u32; typedef char* string;
作者:CX19970



51单片机 万年历 电子 单片机

需要 登录 后方可回复, 如果你还没有账号请 注册新账号