单片机交流
直播中

哔哔哔-

8年用户 1268经验值
擅长:电源/新能源
私信 关注
[问答]

如何去使用51单片机定时器T0做电子万年历?

如何去使用51单片机定时器T0做电子万年历?其代码是什么?
如何对电子万年历软件特性进行proteus仿真

回帖(1)

武文嘉

2021-7-19 11:23:29
  如何在51单片机实现电子万年历
  51单片机制作万年历的基本功能部分,软件特性可以在proteus上仿真,使用51单片机定时器T0做万年历计时信号源,电子万年历计时系统在timer模块,本模块主要是将年/月/日/星期/时/分/秒等信息输出到lcd1602上显示,以及将年月日换算为星期信息。单片机采用12MHz晶振,中断1ms计时方式,误差低。下面直接上代码:
  引用timer系统变量
  extern time_t time; // 电子万年历变量extern u8 time_update; // 更新显示等级,值越小等级越高,1为最高等级,0为最低 对外接口
  用于初始化/去初始化电子万年历系统,计算星期信息,以及在lcd1602上显示更新等。
  void clock_init(void); // 万年历初始化void clock_deinit(void); // 万年历去初始化u8 clock_week_calc(u16 y, u8 m, u8 d); // 星期计算void clock_display_update(void); // 显示更新 初始化模块
  主要是预置年/月/日/星期/时/分/秒/毫秒信息显示格式和初始值。
  /******************************************************************************** 函 数 名 : clock_init* 函数功能 : 万年历初始化* 输 入 : void* 输 出 : void* 说 名 : none*******************************************************************************/void clock_init(void) // 万年历初始化{ lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL); // 关闭光标和闪烁 lcd1602_clean(); lcd1602_set_pos(0, 1); lcd1602_write_num(4, time.year); lcd1602_write_data(‘-’); lcd1602_write_num(2, time.month); lcd1602_write_data(‘-’); lcd1602_write_num(2, time.day); lcd1602_set_pos(0, 0); lcd1602_write_num(2, time.hour); lcd1602_write_data(‘:’); lcd1602_write_num(2, time.miunte); lcd1602_write_data(‘:’); lcd1602_write_num(2, time.second); lcd1602_set_pos(11, 0); lcd1602_write_num(3, time.ms); lcd1602_write_str(“ms”);} lcd1602显示实例:
  
  去初始化
  清理显示屏。
  /******************************************************************************** 函 数 名 : clock_deinit* 函数功能 : 万年历去初始化* 输 入 : void* 输 出 : void* 说 名 : none*******************************************************************************/void clock_deinit(void) // 万年历去初始化{ lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL); // 关闭光标和闪烁 lcd1602_clean();} 星期计算
  通过给定年/月/日,通过星期计算公式,完成年月日到星期的换算,计算公式可通过星期的产生和定义得出。返回0表示周天,返回1到6表示周一到周六。
  code s8 week[7][4]={{“Sun”}, {“Mon”}, {“Tue”}, {“Wed”}, {“Thu”}, {“Fri”}, {“Sat”}};/******************************************************************************** 函 数 名 : clock_week_calc* 函数功能 : 星期计算* 输 入 : y/m/d:年/月/日* 输 出 : u8:星期数* 说 名 : none*******************************************************************************/u8 clock_week_calc(u16 y, u8 m, u8 d) // 星期计算{ u16 week_cnt = 0; u8 week_num; switch (m) { // 从这一年的元旦算到该天为止( 含该天) 的天数 case 12: week_cnt += 30; case 11: week_cnt += 31; case 10: week_cnt += 30; case 9: week_cnt += 31; case 8: week_cnt += 31; case 7: week_cnt += 30; case 6: week_cnt += 31; case 5: week_cnt += 30; case 4: week_cnt += 31; case 3: week_cnt += 28; case 2: week_cnt += 31; case 1: week_cnt += d; break; default: break; } if ((!(y % 4) && ((y % 100) || !(y % 400))) && (m 》 2)) { // 闰年补一天 week_cnt++; } week_num = (y - 1 + (y - 1) / 4 - (y - 1) / 100 + (y - 1) / 400 + week_cnt) % 7; return week_num;} 显示更新
  由于lcd1602写入信息耗时较高,另一方面也并不是时时刻刻年/月/日/星期/时/分/秒/毫秒等信息都在更新或者说有变化,因此利用time_update记录当前需要更新的时间信息有哪些,可以有效提高cpu利用率和性能,在51单片机场景优势非常明显。注:年/月/日/星期/时/分/秒/毫秒更新方向是线性向下的,即:更新年份,必定也需要更新月/日/星期/时/分/秒/毫秒等其他信息。
  /******************************************************************************** 函 数 名 : clock_display_update* 函数功能 : 显示更新* 输 入 : void* 输 出 : void* 说 名 : time_update需要及时清除*******************************************************************************/void clock_display_update(void) // 显示更新{ switch (time_update) { // 判断更新 case 1: time_update = 0; // 年更新 lcd1602_set_pos(0, 1); lcd1602_write_num(4, time.year); case 2: time_update = 0; // 月更新 lcd1602_set_pos(5, 1); lcd1602_write_num(2, time.month); case 3: time_update = 0; // 日更新 lcd1602_set_pos(8, 1); lcd1602_write_num(2, time.day); lcd1602_set_pos(11, 1); // 星期更新 lcd1602_write_str(week[clock_week_calc(time.year, time.month, time.day)]); case 4: time_update = 0; // 时更新 lcd1602_set_pos(0, 0); lcd1602_write_num(2, time.hour); case 5: time_update = 0; // 分更新 lcd1602_set_pos(3, 0); lcd1602_write_num(2, time.miunte); case 6: time_update = 0; // 秒更新 lcd1602_set_pos(6, 0); lcd1602_write_num(2, time.second); case 7: time_update = 0; // 毫秒更新 lcd1602_set_pos(11, 0); lcd1602_write_num(3, time.ms); break; default: break; // 无更新 }} 附录 - 基本功能(clock.h)
  #ifndef __CLOCK_H__#define __CLOCK_H__#include “include.h”#include “timer.h”extern time_t time; // 电子万年历变量extern u8 time_update; // 更新显示等级,值越小等级越高,1为最高等级,0为最低void clock_init(void); // 万年历初始化void clock_deinit(void); // 万年历去初始化u8 clock_week_calc(u16 y, u8 m, u8 d); // 星期计算void clock_display_update(void); // 显示更新#endif 附录 - 基本功能(clock.c)
  #include “clock.h”#include “lcd1602.h”code s8 week[7][4]={{“Sun”}, {“Mon”}, {“Tue”}, {“Wed”}, {“Thu”}, {“Fri”}, {“Sat”}};/******************************************************************************** 函 数 名 : clock_init* 函数功能 : 万年历初始化* 输 入 : void* 输 出 : void* 说 名 : none*******************************************************************************/void clock_init(void) // 万年历初始化{ lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL); // 关闭光标和闪烁 lcd1602_clean(); lcd1602_set_pos(0, 1); lcd1602_write_num(4, time.year); lcd1602_write_data(‘-’); lcd1602_write_num(2, time.month); lcd1602_write_data(‘-’); lcd1602_write_num(2, time.day); lcd1602_set_pos(0, 0); lcd1602_write_num(2, time.hour); lcd1602_write_data(‘:’); lcd1602_write_num(2, time.miunte); lcd1602_write_data(‘:’); lcd1602_write_num(2, time.second); lcd1602_set_pos(11, 0); lcd1602_write_num(3, time.ms); lcd1602_write_str(“ms”);}/******************************************************************************** 函 数 名 : clock_deinit* 函数功能 : 万年历去初始化* 输 入 : void* 输 出 : void* 说 名 : none*******************************************************************************/void clock_deinit(void) // 万年历去初始化{ lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL); // 关闭光标和闪烁 lcd1602_clean();}/******************************************************************************** 函 数 名 : clock_week_calc* 函数功能 : 星期计算* 输 入 : y/m/d:年/月/日* 输 出 : u8:星期数* 说 名 : none*******************************************************************************/u8 clock_week_calc(u16 y, u8 m, u8 d) // 星期计算{ u16 week_cnt = 0; u8 week_num; switch (m) { // 从这一年的元旦算到该天为止( 含该天) 的天数 case 12: week_cnt += 30; case 11: week_cnt += 31; case 10: week_cnt += 30; case 9: week_cnt += 31; case 8: week_cnt += 31; case 7: week_cnt += 30; case 6: week_cnt += 31; case 5: week_cnt += 30; case 4: week_cnt += 31; case 3: week_cnt += 28; case 2: week_cnt += 31; case 1: week_cnt += d; break; default: break; } if ((!(y % 4) && ((y % 100) || !(y % 400))) && (m 》 2)) { // 闰年补一天 week_cnt++; } week_num = (y - 1 + (y - 1) / 4 - (y - 1) / 100 + (y - 1) / 400 + week_cnt) % 7; return week_num;}/******************************************************************************** 函 数 名 : clock_display_update* 函数功能 : 显示更新* 输 入 : void* 输 出 : void* 说 名 : time_update需要及时清除*******************************************************************************/void clock_display_update(void) // 显示更新{ switch (time_update) { // 判断更新 case 1: time_update = 0; // 年更新 lcd1602_set_pos(0, 1); lcd1602_write_num(4, time.year); case 2: time_update = 0; // 月更新 lcd1602_set_pos(5, 1); lcd1602_write_num(2, time.month); case 3: time_update = 0; // 日更新 lcd1602_set_pos(8, 1); lcd1602_write_num(2, time.day); lcd1602_set_pos(11, 1); // 星期更新 lcd1602_write_str(week[clock_week_calc(time.year, time.month, time.day)]); case 4: time_update = 0; // 时更新 lcd1602_set_pos(0, 0); lcd1602_write_num(2, time.hour); case 5: time_update = 0; // 分更新 lcd1602_set_pos(3, 0); lcd1602_write_num(2, time.miunte); case 6: time_update = 0; // 秒更新 lcd1602_set_pos(6, 0); lcd1602_write_num(2, time.second); case 7: time_update = 0; // 毫秒更新 lcd1602_set_pos(11, 0); lcd1602_write_num(3, time.ms); break; default: break; // 无更新 }}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分