51单片机 - 电子万年历 - 修改时间

51单片机 - 电子万年历 - 修改时间

本文用于阐述使用51单片机制作万年历过程中的修改时间部分,主要说明设计算法,软件特性可以在proteus上仿真。修改时间是人机交互的一部分,因此修改时间的实现与具体的人机交互方式息息相关,本系统采用4x4矩阵键盘作为人间交互的接口。下面直接上代码:
修改时间涉及万年历的年/月/日/时/分等信息,直接引用时间类型定义time_t。

对外接口

对外接口主要由修改时间初始化/去初始化,修改时间响应按键,修改时间显示等操作组成。

void change_time_init(void);    // 修改时间初始化
void change_time_deinit(void);    // 修改时间去初始化
void change_time_response_key(key_t key);  // 按键响应
void change_time_display(void);  // 修改时间显示

修改时间初始化

主要是预置修改时间显示格式、界面等,包含年/月/日/时/分等信息,界面如下图所示:
修改时间

/*******************************************************************************
* 函 数 名         : change_time_init
* 函数功能         : 修改时间初始化
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void change_time_init(void)    // 修改时间初始化
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);  // 关闭光标和闪烁
    lcd1602_clean();
    lcd1602_set_pos(0, 1);
    lcd1602_write_str("set time:");
    lcd1602_set_pos(0, 0);
    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(11, 0);
    lcd1602_write_num(2, time.hour);
    lcd1602_write_data(':');
    lcd1602_write_num(2, time.miunte);
    lcd1602_set_pos(0, 0);
    lcd1602_write_cmd(0x08 |  // 显示光标并闪烁
                      LCD1602_DISPLAY_ENABLE |
                      LCD1602_CURSOR_ENABLE |
                      LCD1602_CURSOR_TWINKLE);
    cur_pos = 1;
}

矩阵键盘

键盘如下图所示:
矩阵键盘

修改时间响应按键

用户通过4x4矩阵键盘修改时间,事实上是某函数响应按键的过程,从修改时间设计分析,修改时间主要是修改年/月/日/时/分等信息,如下表所示:

0-9999 1-12 1-31 0-23 0-59

其中年份可进一步细分为千位、百位、十位和个位,月/日/时/分等信息可进一步细分为十位和个位2项修改项,总计有12项修改项,如下表所示:

年份千位 年份百位 年份十位 年份个位 月份十位 月份个位 日期十位 日期个位 小时十位 小时个位 分钟十位 分钟个位
取值0-9 取值0-9 取值0-9 取值0-9 取值0-1 月份十位<1,取值1-9;月份十位=1,取值0-2 取值0-3 日期十位<3,取值1-9;日期十位=3,取值0-1 取值0-2 小时十位<2,取值0-9;小时十位=2,取值0-3 取值0-5 取值0-9

修改时间其实是在描述一个分段函数,根据光标当前所在位置,按键0-9直接修改时间的年/月/日/时/分等信息,add/sub将年/月/日/时/分等信息加一/减一,enter键用于循环移动光标位置。修改时间按键响应代码如下:

/*******************************************************************************
* 函 数 名         : change_time_response_key
* 函数功能         : 按键响应
* 输    入         : key:按键值
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void change_time_response_key(key_t key)  // 按键响应
{
    switch (key) {
        case KEY_0:
        case KEY_1:
        case KEY_2:
        case KEY_3:
        case KEY_4:
        case KEY_5:
        case KEY_6:
        case KEY_7:
        case KEY_8:
        case KEY_9: {
            if (cur_pos == 1) {
                time.year = (1000 * key) + (time.year % 1000);
            } else if (cur_pos == 2) {
                time.year = (time.year / 1000 * 1000) + (100 * key) + (time.year % 100);
            } else if (cur_pos == 3) {
                time.year = (time.year / 1000 * 1000) + ((time.year % 1000) / 100 * 100) + (10 * key) + (time.year % 10);
            } else if (cur_pos == 4) {
                time.year = (time.year / 10 * 10) + key;
            } else if ((cur_pos == 5) && (key <= KEY_1)) {  // 月十位不能超过1
                time.month = 10 * key + time.month % 10;
            } else if (cur_pos == 6) {  // 月个位取值0-9,3-9有限制
                if (key <= KEY_2) {
                    time.month = key + time.month / 10 * 10;
                } else if ((key > KEY_2) && (time.month / 10 < 1)) {
                    time.month = key + time.month / 10 * 10;
                }
            } else if ((cur_pos == 7) && (key <= KEY_3)) {  // 天十位不能超过3
                time.day = 10 * key + time.day % 10;
            } else if (cur_pos == 8) {  // 天个位取值0-9,2-9有限制
                if (key <= KEY_1) {
                    time.day = key + time.day / 10 * 10;
                } else if ((key > KEY_1) && (time.day / 10 < 3)) {
                    time.day = key + time.day / 10 * 10;
                }
            } else if ((cur_pos == 9) && (key <= KEY_2)) {  // 时十位取值0-2
                time.hour = 10 * key + time.hour % 10;
            } else if (cur_pos == 10) {  // 时个位取值0-9,4-9有限制
                if (key <= KEY_3) {
                    time.hour = key + time.hour / 10 * 10;
                } else if ((key > KEY_3) && (time.hour / 10 < 2)) {
                    time.hour = key + time.hour / 10 * 10;
                }
            } else if ((cur_pos == 11) && (key <= KEY_5)) {  // 分十位取值0-5
                time.miunte = 10 * key + time.miunte % 10;
            } else if (cur_pos == 22) {  // 分个位取值0-9
                time.miunte = key + time.miunte / 10 * 10;
            }
            if ((time.day > 30) && ((time.month == 4) ||  // 各个月份天数修正
                                    (time.month == 6) ||
                                    (time.month == 9) ||
                                    (time.month == 11))) {
                time.day = 30;
            } else if ((time.day >= 29) && (time.month == 2)) {
                time.day = 29;
                if (!(!(time.year % 4) && ((time.year % 100) || !(time.year % 400)))) {
                    time.day = 28;
                }
            }
            if (time.month == 0) {
                time.month = 1;
            }
            if (time.day == 0) {
                time.day = 1;
            }
            break;
        }
        case KEY_ADD: {  // 加1
            if ((cur_pos == 1) || (cur_pos == 2) || (cur_pos == 3) || (cur_pos == 4)) {
                if (time.year < YEAR_MAX) {
                    time.year++;
                }
            } else if ((cur_pos == 5) || (cur_pos == 6)) {
                if (time.month < 12) {
                    time.month++;
                }
            } else if ((cur_pos == 7) || (cur_pos == 8)) {
                if (time.day < 31) {
                    time.day++;
                }
            } else if ((cur_pos == 9) || (cur_pos == 10)) {
                if (time.hour < 23) {
                    time.hour++;
                }
            } else if ((cur_pos == 11) || (cur_pos == 12)) {
                if (time.miunte < 59) {
                    time.miunte++;
                }
            }
            if ((time.day > 30) && ((time.month == 4) ||  // 各个月份天数修正
                                    (time.month == 6) ||
                                    (time.month == 9) ||
                                    (time.month == 11))) {
                time.day = 30;
            } else if ((time.day >= 29) && (time.month == 2)) {
                time.day = 29;
                if (!(!(time.year % 4) && ((time.year % 100) || !(time.year % 400)))) {
                    time.day = 28;
                }
            }
            break;
        }
        case KEY_SUB: {  // 减1
            if ((cur_pos == 1) || (cur_pos == 2) || (cur_pos == 3) || (cur_pos == 4)) {
                if (time.year > 0) {
                    time.year--;
                }
            } else if ((cur_pos == 5) || (cur_pos == 6)) {
                if (time.month > 1) {
                    time.month--;
                }
            } else if ((cur_pos == 7) || (cur_pos == 8)) {
                if (time.day > 1) {
                    time.day--;
                }
            } else if ((cur_pos == 9) || (cur_pos == 10)) {
                if (time.hour > 0) {
                    time.hour--;
                }
            } else if ((cur_pos == 11) || (cur_pos == 12)) {
                if (time.miunte > 0) {
                    time.miunte--;
                }
            }
            if ((time.day > 30) && ((time.month == 4) ||  // 各个月份天数修正
                                    (time.month == 6) ||
                                    (time.month == 9) ||
                                    (time.month == 11))) {
                time.day = 30;
            } else if ((time.day >= 29) && (time.month == 2)) {
                time.day = 29;
                if (!(!(time.year % 4) && ((time.year % 100) || !(time.year % 400)))) {
                    time.day = 28;
                }
            }
            break;
        }
        case KEY_ENTER: {  // 移动游标
            cur_pos++; 
            if (cur_pos > CHANGE_TIME_CUR_POS_MAX) {
                cur_pos = 1;
            }
            break;
        }
        case KEY_TRANS: break;
        case KEY_FUN:
        case KEY_BACK: change_time_deinit(); break;  // 退出修改时间设置
        default: break;
    }
}

显示修改时间

用于显示更新年/月/日/时/分等信息。

/*******************************************************************************
* 函 数 名         : change_time_display
* 函数功能         : 修改时间显示
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void change_time_display(void)  // 修改时间显示
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);  // 关闭光标和闪烁
    lcd1602_set_pos(0, 0);
    lcd1602_write_num(4, time.year);
    lcd1602_set_pos(5, 0);
    lcd1602_write_num(2, time.month);
    lcd1602_set_pos(8, 0);
    lcd1602_write_num(2, time.day);
    lcd1602_set_pos(11, 0);
    lcd1602_write_num(2, time.hour);
    lcd1602_set_pos(14, 0);
    lcd1602_write_num(2, time.miunte);
    if (cur_pos == 1) {  // 指定光标位置
        lcd1602_set_pos(0, 0);
    } else if (cur_pos == 2) {
        lcd1602_set_pos(1, 0);
    } else if (cur_pos == 3) {
        lcd1602_set_pos(2, 0);
    } else if (cur_pos == 4) {
        lcd1602_set_pos(3, 0);
    } else if (cur_pos == 5) {
        lcd1602_set_pos(5, 0);
    } else if (cur_pos == 6) {
        lcd1602_set_pos(6, 0);
    } else if (cur_pos == 7) {
        lcd1602_set_pos(8, 0);
    } else if (cur_pos == 8) {
        lcd1602_set_pos(9, 0);
    } else if (cur_pos == 9) {
        lcd1602_set_pos(11, 0);
    } else if (cur_pos == 10) {
        lcd1602_set_pos(12, 0);
    } else if (cur_pos == 11) {
        lcd1602_set_pos(14, 0);
    } else if (cur_pos == 12) {
        lcd1602_set_pos(15, 0);
    }
    lcd1602_write_cmd(0x08 |  // 显示光标并闪烁
                      LCD1602_DISPLAY_ENABLE |
                      LCD1602_CURSOR_ENABLE |
                      LCD1602_CURSOR_TWINKLE);
}

附录 - 修改时间(change_time.h)

#ifndef __CHANGE_TIME_H__
#define __CHANGE_TIME_H__

#include "include.h"
#include "clock.h"
#include "keyboard.h"

#define CHANGE_TIME_CUR_POS_MAX    12  // 游标最大位置

void change_time_init(void);    // 修改时间初始化
void change_time_deinit(void);    // 修改时间去初始化
void change_time_response_key(key_t key);  // 按键响应
void change_time_display(void);  // 修改时间显示

#endif

附录 - 修改时间(change_time.c)

#include "change_time.h"
#include "lcd1602.h"

static u8 cur_pos = 1;  // 游标位置

/*******************************************************************************
* 函 数 名         : change_time_init
* 函数功能         : 修改时间初始化
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void change_time_init(void)    // 修改时间初始化
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);  // 关闭光标和闪烁
    lcd1602_clean();
    lcd1602_set_pos(0, 1);
    lcd1602_write_str("set time:");
    lcd1602_set_pos(0, 0);
    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(11, 0);
    lcd1602_write_num(2, time.hour);
    lcd1602_write_data(':');
    lcd1602_write_num(2, time.miunte);
    lcd1602_set_pos(0, 0);
    lcd1602_write_cmd(0x08 |  // 显示光标并闪烁
                      LCD1602_DISPLAY_ENABLE |
                      LCD1602_CURSOR_ENABLE |
                      LCD1602_CURSOR_TWINKLE);
    cur_pos = 1;
}

/*******************************************************************************
* 函 数 名         : change_time_deinit
* 函数功能         : 修改时间去初始化
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void change_time_deinit(void)     // 修改时间去初始化
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);
    lcd1602_clean();
}

/*******************************************************************************
* 函 数 名         : change_time_response_key
* 函数功能         : 按键响应
* 输    入         : key:按键值
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void change_time_response_key(key_t key)  // 按键响应
{
    switch (key) {
        case KEY_0:
        case KEY_1:
        case KEY_2:
        case KEY_3:
        case KEY_4:
        case KEY_5:
        case KEY_6:
        case KEY_7:
        case KEY_8:
        case KEY_9: {
            if (cur_pos == 1) {
                time.year = (1000 * key) + (time.year % 1000);
            } else if (cur_pos == 2) {
                time.year = (time.year / 1000 * 1000) + (100 * key) + (time.year % 100);
            } else if (cur_pos == 3) {
                time.year = (time.year / 1000 * 1000) + ((time.year % 1000) / 100 * 100) + (10 * key) + (time.year % 10);
            } else if (cur_pos == 4) {
                time.year = (time.year / 10 * 10) + key;
            } else if ((cur_pos == 5) && (key <= KEY_1)) {  // 月十位不能超过1
                time.month = 10 * key + time.month % 10;
            } else if (cur_pos == 6) {  // 月个位取值0-9,3-9有限制
                if (key <= KEY_2) {
                    time.month = key + time.month / 10 * 10;
                } else if ((key > KEY_2) && (time.month / 10 < 1)) {
                    time.month = key + time.month / 10 * 10;
                }
            } else if ((cur_pos == 7) && (key <= KEY_3)) {  // 天十位不能超过3
                time.day = 10 * key + time.day % 10;
            } else if (cur_pos == 8) {  // 天个位取值0-9,2-9有限制
                if (key <= KEY_1) {
                    time.day = key + time.day / 10 * 10;
                } else if ((key > KEY_1) && (time.day / 10 < 3)) {
                    time.day = key + time.day / 10 * 10;
                }
            } else if ((cur_pos == 9) && (key <= KEY_2)) {  // 时十位取值0-2
                time.hour = 10 * key + time.hour % 10;
            } else if (cur_pos == 10) {  // 时个位取值0-9,4-9有限制
                if (key <= KEY_3) {
                    time.hour = key + time.hour / 10 * 10;
                } else if ((key > KEY_3) && (time.hour / 10 < 2)) {
                    time.hour = key + time.hour / 10 * 10;
                }
            } else if ((cur_pos == 11) && (key <= KEY_5)) {  // 分十位取值0-5
                time.miunte = 10 * key + time.miunte % 10;
            } else if (cur_pos == 22) {  // 分个位取值0-9
                time.miunte = key + time.miunte / 10 * 10;
            }
            if ((time.day > 30) && ((time.month == 4) ||  // 各个月份天数修正
                                    (time.month == 6) ||
                                    (time.month == 9) ||
                                    (time.month == 11))) {
                time.day = 30;
            } else if ((time.day >= 29) && (time.month == 2)) {
                time.day = 29;
                if (!(!(time.year % 4) && ((time.year % 100) || !(time.year % 400)))) {
                    time.day = 28;
                }
            }
            if (time.month == 0) {
                time.month = 1;
            }
            if (time.day == 0) {
                time.day = 1;
            }
            break;
        }
        case KEY_ADD: {  // 加1
            if ((cur_pos == 1) || (cur_pos == 2) || (cur_pos == 3) || (cur_pos == 4)) {
                if (time.year < YEAR_MAX) {
                    time.year++;
                }
            } else if ((cur_pos == 5) || (cur_pos == 6)) {
                if (time.month < 12) {
                    time.month++;
                }
            } else if ((cur_pos == 7) || (cur_pos == 8)) {
                if (time.day < 31) {
                    time.day++;
                }
            } else if ((cur_pos == 9) || (cur_pos == 10)) {
                if (time.hour < 23) {
                    time.hour++;
                }
            } else if ((cur_pos == 11) || (cur_pos == 12)) {
                if (time.miunte < 59) {
                    time.miunte++;
                }
            }
            if ((time.day > 30) && ((time.month == 4) ||  // 各个月份天数修正
                                    (time.month == 6) ||
                                    (time.month == 9) ||
                                    (time.month == 11))) {
                time.day = 30;
            } else if ((time.day >= 29) && (time.month == 2)) {
                time.day = 29;
                if (!(!(time.year % 4) && ((time.year % 100) || !(time.year % 400)))) {
                    time.day = 28;
                }
            }
            break;
        }
        case KEY_SUB: {  // 减1
            if ((cur_pos == 1) || (cur_pos == 2) || (cur_pos == 3) || (cur_pos == 4)) {
                if (time.year > 0) {
                    time.year--;
                }
            } else if ((cur_pos == 5) || (cur_pos == 6)) {
                if (time.month > 1) {
                    time.month--;
                }
            } else if ((cur_pos == 7) || (cur_pos == 8)) {
                if (time.day > 1) {
                    time.day--;
                }
            } else if ((cur_pos == 9) || (cur_pos == 10)) {
                if (time.hour > 0) {
                    time.hour--;
                }
            } else if ((cur_pos == 11) || (cur_pos == 12)) {
                if (time.miunte > 0) {
                    time.miunte--;
                }
            }
            if ((time.day > 30) && ((time.month == 4) ||  // 各个月份天数修正
                                    (time.month == 6) ||
                                    (time.month == 9) ||
                                    (time.month == 11))) {
                time.day = 30;
            } else if ((time.day >= 29) && (time.month == 2)) {
                time.day = 29;
                if (!(!(time.year % 4) && ((time.year % 100) || !(time.year % 400)))) {
                    time.day = 28;
                }
            }
            break;
        }
        case KEY_ENTER: {  // 移动游标
            cur_pos++; 
            if (cur_pos > CHANGE_TIME_CUR_POS_MAX) {
                cur_pos = 1;
            }
            break;
        }
        case KEY_TRANS: break;
        case KEY_FUN:
        case KEY_BACK: change_time_deinit(); break;  // 退出修改时间设置
        default: break;
    }
}

/*******************************************************************************
* 函 数 名         : change_time_display
* 函数功能         : 修改时间显示
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void change_time_display(void)  // 修改时间显示
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);  // 关闭光标和闪烁
    lcd1602_set_pos(0, 0);
    lcd1602_write_num(4, time.year);
    lcd1602_set_pos(5, 0);
    lcd1602_write_num(2, time.month);
    lcd1602_set_pos(8, 0);
    lcd1602_write_num(2, time.day);
    lcd1602_set_pos(11, 0);
    lcd1602_write_num(2, time.hour);
    lcd1602_set_pos(14, 0);
    lcd1602_write_num(2, time.miunte);
    if (cur_pos == 1) {  // 指定光标位置
        lcd1602_set_pos(0, 0);
    } else if (cur_pos == 2) {
        lcd1602_set_pos(1, 0);
    } else if (cur_pos == 3) {
        lcd1602_set_pos(2, 0);
    } else if (cur_pos == 4) {
        lcd1602_set_pos(3, 0);
    } else if (cur_pos == 5) {
        lcd1602_set_pos(5, 0);
    } else if (cur_pos == 6) {
        lcd1602_set_pos(6, 0);
    } else if (cur_pos == 7) {
        lcd1602_set_pos(8, 0);
    } else if (cur_pos == 8) {
        lcd1602_set_pos(9, 0);
    } else if (cur_pos == 9) {
        lcd1602_set_pos(11, 0);
    } else if (cur_pos == 10) {
        lcd1602_set_pos(12, 0);
    } else if (cur_pos == 11) {
        lcd1602_set_pos(14, 0);
    } else if (cur_pos == 12) {
        lcd1602_set_pos(15, 0);
    }
    lcd1602_write_cmd(0x08 |  // 显示光标并闪烁
                      LCD1602_DISPLAY_ENABLE |
                      LCD1602_CURSOR_ENABLE |
                      LCD1602_CURSOR_TWINKLE);
}
发布了15 篇原创文章 · 获赞 17 · 访问量 1646

猜你喜欢

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