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

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上显示使用此机制可避免无意义的显示刷新,在使用51单片机做主控的场景,提供更新等级能有效提高代码执行效率。对于闰年的判断可通过闰年定义得到相应公式。

/*******************************************************************************
* 函 数 名         : 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 < 13) {   // 1年
        return;
    }
    time.month = 1;
    time.year++;
    timer_set_update_level(1);    // 年更新

    if (time.year > 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 <reg52.h>
#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 < 13) {   // 1年
        return;
    }
    time.month = 1;
    time.year++;
    timer_set_update_level(1);    // 年更新

    if (time.year > 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;
发布了15 篇原创文章 · 获赞 17 · 访问量 1660

猜你喜欢

转载自blog.csdn.net/weixin_44413515/article/details/104428509