51单片机 - 电子万年历 - 日程提醒

51单片机 - 电子万年历 - 日程提醒

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

日程定义

日程主要由月/日与时/分确立,以及日程的状态组成。日程可逻辑抽象为数据类型schedule_t:

typedef enum {  // 日程状态
    SCHEDULE_OFF = 0,
    SCHEDULE_ON  = 1,
    SCHEDULE_BUTT
} schedule_state_t;
typedef struct {  // 日程
    u8 month;
    u8 day;
    u8 hour;
    u8 miunte;
    schedule_state_t state;
} schedule_t;

static schedule_t schedule = { 0, 0, 0, 0, SCHEDULE_OFF };  // 日程配置
static u8 cur_pos = 1;  // 游标位置

对外接口

对外接口主要由日程初始化,检测日程提醒,设置日程,关闭日程提醒等操作组成。

void schedule_init(void);    // 日程初始化
void schedule_deinit(void);    // 日程去初始化
u8 schedule_check(u8 now_month, u8 now_day, u8 now_hour, u8 now_miunte);     // 日程检测
void schedule_response_key(key_t key);  // 按键响应
void schedule_display(void);  // 日程显示
void schedule_close(void);  // 关闭日程

日程提醒初始化

主要是预置日程显示格式、界面等,前两位为月/日参数显示,使用“-”连接,后两位为时/分参数显示,使用“:”连接,界面如下图所示:
日程提醒

/*******************************************************************************
* 函 数 名         : schedule_init
* 函数功能         : 日程初始化
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void schedule_init(void)    // 日程初始化
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);  // 关闭光标和闪烁
    lcd1602_clean();
    lcd1602_set_pos(0, 1);
    lcd1602_write_str("set schedule:");
    lcd1602_set_pos(0, 0);
    lcd1602_write_num(2, schedule.month);
    lcd1602_write_data('-');
    lcd1602_write_num(2, schedule.day);
    lcd1602_set_pos(6, 0);
    lcd1602_write_num(2, schedule.hour);
    lcd1602_write_data(':');
    lcd1602_write_num(2, schedule.miunte);
    lcd1602_set_pos(13, 0);
    if (schedule.state == SCHEDULE_ON) {
        lcd1602_write_str(" on");
    } else {
        lcd1602_write_str("off");
    }
    lcd1602_set_pos(0, 0);
    lcd1602_write_cmd(0x08 |  // 显示光标并闪烁
                      LCD1602_DISPLAY_ENABLE |
                      LCD1602_CURSOR_ENABLE |
                      LCD1602_CURSOR_TWINKLE);
    cur_pos = SCHEDULE_CUR_POS_MAX;
}

日程提醒检测

通过对比在一定时间范围内,检测到日程有效便激活蜂鸣器,否则关闭。激活蜂鸣器部分主要思想如下:
1、日程状态必须为SCHEDULE_ON,即:打开日程提醒;
2、在月/日与时/分检测到相等的情况下,往后推迟的SCHEDULE_CONTINUE_TIME分钟时间激活蜂鸣器;
3、否则关闭蜂鸣器。

/*******************************************************************************
* 函 数 名         : schedule_check
* 函数功能         : 日程检测
* 输    入         : now_month/now_day/now_hour/now_miunte:当前月/日/时/分
* 输    出         : u8:0没有激活,other已激活
* 说    名         : none
*******************************************************************************/
u8 schedule_check(u8 now_month, u8 now_day, u8 now_hour, u8 now_miunte)     // 日程检测
{
    static u8 state = 0;

    if (schedule.state != SCHEDULE_ON) {
        buzzer_disable_passive();
        return 0;
    }

    if ((state == 0) && (schedule.month == now_month) && (schedule.day == now_day) &&
        (schedule.hour == now_hour) && (schedule.miunte == now_miunte)) {
        state = 1;
    }
    if (state != 1) {
        buzzer_disable_passive();
        return 0;
    }
    if (((now_hour * 60 + now_miunte) - (schedule.hour * 60 + schedule.miunte) >= 0) &&
        ((now_hour * 60 + now_miunte) - (schedule.hour * 60 + schedule.miunte) <= SCHEDULE_CONTINUE_TIME)) {
        buzzer_enable_passive();
        return 1;
    } else {
        state = 0;
    }
    if ((schedule.hour == 23) && (now_hour == 0)) {
        if (((24 * 60 + now_miunte) - (schedule.hour * 60 + schedule.miunte) >= 0) &&
            ((24 * 60 + now_miunte) - (schedule.hour * 60 + schedule.miunte) <= SCHEDULE_CONTINUE_TIME)) {
            buzzer_enable_passive();
            return 1;
        } else {
            state = 0;
        }
    }

    return 0;
}

矩阵键盘

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

设置日程

用户通过4x4矩阵键盘设定日程,事实上是日程某函数响应按键的过程,从日程抽象类型schedule_t分析,日程设定主要是修改月份、日期、小时和分钟,以及日程状态,如下表所示:

日程状态
1-12 1-31 0-23 0-59 on/off

其中月份、日期、小时和分钟可进一步细分为十位和个位2项修改项,总计有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 on/off

设定日程其实是在描述一个分段函数,根据光标当前所在位置,按键0-9直接修改日程的月份/日期/小时/分钟值,add/sub将月份/日期/小时/分钟值加一/减一,trans用于切换日程状态,enter键用于循环移动光标位置。日程按键响应代码如下:

/*******************************************************************************
* 函 数 名         : schedule_response_key
* 函数功能         : 按键响应
* 输    入         : key:按键值
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void schedule_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) && (key <= KEY_1)) {  // 月十位不能超过1
                schedule.month = 10 * key + schedule.month % 10;
            } else if (cur_pos == 2) {  // 月个位取值0-9,3-9有限制
                if (key <= KEY_2) {
                    schedule.month = key + schedule.month / 10 * 10;
                } else if ((key > KEY_2) && (schedule.month / 10 < 1)) {
                    schedule.month = key + schedule.month / 10 * 10;
                }
            } else if ((cur_pos == 3) && (key <= KEY_3)) {  // 天十位不能超过3
                schedule.day = 10 * key + schedule.day % 10;
            } else if (cur_pos == 4) {  // 天个位取值0-9,2-9有限制
                if (key <= KEY_1) {
                    schedule.day = key + schedule.day / 10 * 10;
                } else if ((key > KEY_1) && (schedule.day / 10 < 3)) {
                    schedule.day = key + schedule.day / 10 * 10;
                }
            } else if ((cur_pos == 5) && (key <= KEY_2)) {  // 时十位取值0-2
                schedule.hour = 10 * key + schedule.hour % 10;
            } else if (cur_pos == 6) {  // 时个位取值0-9,4-9有限制
                if (key <= KEY_3) {
                    schedule.hour = key + schedule.hour / 10 * 10;
                } else if ((key > KEY_3) && (schedule.hour / 10 < 2)) {
                    schedule.hour = key + schedule.hour / 10 * 10;
                }
            } else if ((cur_pos == 7) && (key <= KEY_5)) {  // 分十位取值0-5
                schedule.miunte = 10 * key + schedule.miunte % 10;
            } else if (cur_pos == 8) {  // 分个位取值0-9
                schedule.miunte = key + schedule.miunte / 10 * 10;
            }
            if ((schedule.day > 30) && ((schedule.month == 4) ||  // 各个月份天数修正
                                        (schedule.month == 6) ||
                                        (schedule.month == 9) ||
                                        (schedule.month == 11))) {
                schedule.day = 30;
            } else if ((schedule.day > 29) && (schedule.month == 2)) {
                schedule.day = 29;
            }
            break;
        }
        case KEY_ADD: {  // 加1
            if ((cur_pos == 1) || (cur_pos == 2)) {
                if (schedule.month < 12) {
                    schedule.month++;
                }
            } else if ((cur_pos == 3) || (cur_pos == 4)) {
                if (schedule.day < 31) {
                    schedule.day++;
                }
            } else if ((cur_pos == 5) || (cur_pos == 6)) {
                if (schedule.hour < 23) {
                    schedule.hour++;
                }
            } else if ((cur_pos == 7) || (cur_pos == 8)) {
                if (schedule.miunte < 59) {
                    schedule.miunte++;
                }
            }
            if ((schedule.day > 30) && ((schedule.month == 4) ||  // 各个月份天数修正
                                        (schedule.month == 6) ||
                                        (schedule.month == 9) ||
                                        (schedule.month == 11))) {
                schedule.day = 30;
            } else if ((schedule.day > 29) && (schedule.month == 2)) {
                schedule.day = 29;
            }
            break;
        }
        case KEY_SUB: {  // 减1
           if ((cur_pos == 1) || (cur_pos == 2)) {
                if (schedule.month > 0) {
                    schedule.month--;
                }
            } else if ((cur_pos == 3) || (cur_pos == 4)) {
                if (schedule.day > 0) {
                    schedule.day--;
                }
            } else if ((cur_pos == 5) || (cur_pos == 6)) {
                if (schedule.hour > 0) {
                    schedule.hour--;
                }
            } else if ((cur_pos == 7) || (cur_pos == 8)) {
                if (schedule.miunte > 0) {
                    schedule.miunte--;
                }
            }
            if ((schedule.day > 30) && ((schedule.month == 4) ||  // 各个月份天数修正
                                        (schedule.month == 6) ||
                                        (schedule.month == 9) ||
                                        (schedule.month == 11))) {
                schedule.day = 30;
            } else if ((schedule.day > 29) && (schedule.month == 2)) {
                schedule.day = 29;
            }
            break;
        }
        case KEY_ENTER: {  // 移动游标
            cur_pos++; 
            if (cur_pos > SCHEDULE_CUR_POS_MAX) {
                cur_pos = 1;
            }
            break;
        }
        case KEY_TRANS: {  // 切换日程状态
            if (cur_pos == 9) {
                if (schedule.state == SCHEDULE_OFF) {
                    schedule.state = SCHEDULE_ON;
                } else {
                    schedule.state = SCHEDULE_OFF;
                }
            }
            break;
        }
        case KEY_FUN:
        case KEY_BACK: schedule_deinit(); break;  // 退出日程设置
        default: break;
    }
}

日程显示

用于更新月份、日期、小时和分钟,以及日程状态。

/*******************************************************************************
* 函 数 名         : schedule_display
* 函数功能         : 日程显示
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void schedule_display(void)  // 日程显示
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);  // 关闭光标和闪烁
    lcd1602_set_pos(0, 0);
    lcd1602_write_num(2, schedule.month);
    lcd1602_set_pos(3, 0);
    lcd1602_write_num(2, schedule.day);
    lcd1602_set_pos(6, 0);
    lcd1602_write_num(2, schedule.hour);
    lcd1602_set_pos(9, 0);
    lcd1602_write_num(2, schedule.miunte);
    lcd1602_set_pos(13, 0);
    if (schedule.state == SCHEDULE_ON) {
        lcd1602_write_str(" on");
    } else {
        lcd1602_write_str("off");
    }
    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(3, 0);
    } else if (cur_pos == 4) {
        lcd1602_set_pos(4, 0);
    } else if (cur_pos == 5) {
        lcd1602_set_pos(6, 0);
    } else if (cur_pos == 6) {
        lcd1602_set_pos(7, 0);
    } else if (cur_pos == 7) {
        lcd1602_set_pos(9, 0);
    } else if (cur_pos == 8) {
        lcd1602_set_pos(10, 0);
    } else if (cur_pos == 9) {
        if (schedule.state == SCHEDULE_ON) {
            lcd1602_set_pos(14, 0);
        } else {
            lcd1602_set_pos(13, 0);
        }
    }
    lcd1602_write_cmd(0x08 |  // 显示光标并闪烁
                      LCD1602_DISPLAY_ENABLE |
                      LCD1602_CURSOR_ENABLE |
                      LCD1602_CURSOR_TWINKLE);
}

附录 - 日程提醒(schedule.h)

#ifndef __SCHEDULE_H__
#define __SCHEDULE_H__

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

#define SCHEDULE_CONTINUE_TIME 30  // 响铃时间,分钟计时,1-60
#define SCHEDULE_CUR_POS_MAX    9  // 游标最大位置

typedef enum {  // 日程状态
    SCHEDULE_OFF = 0,
    SCHEDULE_ON  = 1,
    SCHEDULE_BUTT
} schedule_state_t;
typedef struct {  // 日程
    u8 month;
    u8 day;
    u8 hour;
    u8 miunte;
    schedule_state_t state;
} schedule_t;

void schedule_init(void);    // 日程初始化
void schedule_deinit(void);    // 日程去初始化
u8 schedule_check(u8 now_month, u8 now_day, u8 now_hour, u8 now_miunte);     // 日程检测
void schedule_response_key(key_t key);  // 按键响应
void schedule_display(void);  // 日程显示
void schedule_close(void);  // 关闭日程

#endif

附录 - 日程提醒(schedule.c)

#include "schedule.h"
#include "lcd1602.h"
#include "buzzer.h"

static schedule_t schedule = { 0, 0, 0, 0, SCHEDULE_OFF };  // 日程配置
static u8 cur_pos = 1;  // 游标位置

/*******************************************************************************
* 函 数 名         : schedule_init
* 函数功能         : 日程初始化
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void schedule_init(void)    // 日程初始化
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);  // 关闭光标和闪烁
    lcd1602_clean();
    lcd1602_set_pos(0, 1);
    lcd1602_write_str("set schedule:");
    lcd1602_set_pos(0, 0);
    lcd1602_write_num(2, schedule.month);
    lcd1602_write_data('-');
    lcd1602_write_num(2, schedule.day);
    lcd1602_set_pos(6, 0);
    lcd1602_write_num(2, schedule.hour);
    lcd1602_write_data(':');
    lcd1602_write_num(2, schedule.miunte);
    lcd1602_set_pos(13, 0);
    if (schedule.state == SCHEDULE_ON) {
        lcd1602_write_str(" on");
    } else {
        lcd1602_write_str("off");
    }
    lcd1602_set_pos(0, 0);
    lcd1602_write_cmd(0x08 |  // 显示光标并闪烁
                      LCD1602_DISPLAY_ENABLE |
                      LCD1602_CURSOR_ENABLE |
                      LCD1602_CURSOR_TWINKLE);
    cur_pos = SCHEDULE_CUR_POS_MAX;
}

/*******************************************************************************
* 函 数 名         : schedule_deinit
* 函数功能         : 日程去初始化
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void schedule_deinit(void)     // 日程去初始化
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);
    lcd1602_clean();
}

/*******************************************************************************
* 函 数 名         : schedule_check
* 函数功能         : 日程检测
* 输    入         : now_month/now_day/now_hour/now_miunte:当前月/日/时/分
* 输    出         : u8:0没有激活,other已激活
* 说    名         : none
*******************************************************************************/
u8 schedule_check(u8 now_month, u8 now_day, u8 now_hour, u8 now_miunte)     // 日程检测
{
    static u8 state = 0;

    if (schedule.state != SCHEDULE_ON) {
        buzzer_disable_passive();
        return 0;
    }

    if ((state == 0) && (schedule.month == now_month) && (schedule.day == now_day) &&
        (schedule.hour == now_hour) && (schedule.miunte == now_miunte)) {
        state = 1;
    }
    if (state != 1) {
        buzzer_disable_passive();
        return 0;
    }
    if (((now_hour * 60 + now_miunte) - (schedule.hour * 60 + schedule.miunte) >= 0) &&
        ((now_hour * 60 + now_miunte) - (schedule.hour * 60 + schedule.miunte) <= SCHEDULE_CONTINUE_TIME)) {
        buzzer_enable_passive();
        return 1;
    } else {
        state = 0;
    }
    if ((schedule.hour == 23) && (now_hour == 0)) {
        if (((24 * 60 + now_miunte) - (schedule.hour * 60 + schedule.miunte) >= 0) &&
            ((24 * 60 + now_miunte) - (schedule.hour * 60 + schedule.miunte) <= SCHEDULE_CONTINUE_TIME)) {
            buzzer_enable_passive();
            return 1;
        } else {
            state = 0;
        }
    }

    return 0;
}

/*******************************************************************************
* 函 数 名         : schedule_response_key
* 函数功能         : 按键响应
* 输    入         : key:按键值
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void schedule_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) && (key <= KEY_1)) {  // 月十位不能超过1
                schedule.month = 10 * key + schedule.month % 10;
            } else if (cur_pos == 2) {  // 月个位取值0-9,3-9有限制
                if (key <= KEY_2) {
                    schedule.month = key + schedule.month / 10 * 10;
                } else if ((key > KEY_2) && (schedule.month / 10 < 1)) {
                    schedule.month = key + schedule.month / 10 * 10;
                }
            } else if ((cur_pos == 3) && (key <= KEY_3)) {  // 天十位不能超过3
                schedule.day = 10 * key + schedule.day % 10;
            } else if (cur_pos == 4) {  // 天个位取值0-9,2-9有限制
                if (key <= KEY_1) {
                    schedule.day = key + schedule.day / 10 * 10;
                } else if ((key > KEY_1) && (schedule.day / 10 < 3)) {
                    schedule.day = key + schedule.day / 10 * 10;
                }
            } else if ((cur_pos == 5) && (key <= KEY_2)) {  // 时十位取值0-2
                schedule.hour = 10 * key + schedule.hour % 10;
            } else if (cur_pos == 6) {  // 时个位取值0-9,4-9有限制
                if (key <= KEY_3) {
                    schedule.hour = key + schedule.hour / 10 * 10;
                } else if ((key > KEY_3) && (schedule.hour / 10 < 2)) {
                    schedule.hour = key + schedule.hour / 10 * 10;
                }
            } else if ((cur_pos == 7) && (key <= KEY_5)) {  // 分十位取值0-5
                schedule.miunte = 10 * key + schedule.miunte % 10;
            } else if (cur_pos == 8) {  // 分个位取值0-9
                schedule.miunte = key + schedule.miunte / 10 * 10;
            }
            if ((schedule.day > 30) && ((schedule.month == 4) ||  // 各个月份天数修正
                                        (schedule.month == 6) ||
                                        (schedule.month == 9) ||
                                        (schedule.month == 11))) {
                schedule.day = 30;
            } else if ((schedule.day > 29) && (schedule.month == 2)) {
                schedule.day = 29;
            }
            break;
        }
        case KEY_ADD: {  // 加1
            if ((cur_pos == 1) || (cur_pos == 2)) {
                if (schedule.month < 12) {
                    schedule.month++;
                }
            } else if ((cur_pos == 3) || (cur_pos == 4)) {
                if (schedule.day < 31) {
                    schedule.day++;
                }
            } else if ((cur_pos == 5) || (cur_pos == 6)) {
                if (schedule.hour < 23) {
                    schedule.hour++;
                }
            } else if ((cur_pos == 7) || (cur_pos == 8)) {
                if (schedule.miunte < 59) {
                    schedule.miunte++;
                }
            }
            if ((schedule.day > 30) && ((schedule.month == 4) ||  // 各个月份天数修正
                                        (schedule.month == 6) ||
                                        (schedule.month == 9) ||
                                        (schedule.month == 11))) {
                schedule.day = 30;
            } else if ((schedule.day > 29) && (schedule.month == 2)) {
                schedule.day = 29;
            }
            break;
        }
        case KEY_SUB: {  // 减1
           if ((cur_pos == 1) || (cur_pos == 2)) {
                if (schedule.month > 0) {
                    schedule.month--;
                }
            } else if ((cur_pos == 3) || (cur_pos == 4)) {
                if (schedule.day > 0) {
                    schedule.day--;
                }
            } else if ((cur_pos == 5) || (cur_pos == 6)) {
                if (schedule.hour > 0) {
                    schedule.hour--;
                }
            } else if ((cur_pos == 7) || (cur_pos == 8)) {
                if (schedule.miunte > 0) {
                    schedule.miunte--;
                }
            }
            if ((schedule.day > 30) && ((schedule.month == 4) ||  // 各个月份天数修正
                                        (schedule.month == 6) ||
                                        (schedule.month == 9) ||
                                        (schedule.month == 11))) {
                schedule.day = 30;
            } else if ((schedule.day > 29) && (schedule.month == 2)) {
                schedule.day = 29;
            }
            break;
        }
        case KEY_ENTER: {  // 移动游标
            cur_pos++; 
            if (cur_pos > SCHEDULE_CUR_POS_MAX) {
                cur_pos = 1;
            }
            break;
        }
        case KEY_TRANS: {  // 切换日程状态
            if (cur_pos == 9) {
                if (schedule.state == SCHEDULE_OFF) {
                    schedule.state = SCHEDULE_ON;
                } else {
                    schedule.state = SCHEDULE_OFF;
                }
            }
            break;
        }
        case KEY_FUN:
        case KEY_BACK: schedule_deinit(); break;  // 退出日程设置
        default: break;
    }
}

/*******************************************************************************
* 函 数 名         : schedule_display
* 函数功能         : 日程显示
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void schedule_display(void)  // 日程显示
{
    lcd1602_write_cmd(LCD1602_DISPLAY_CONTROL);  // 关闭光标和闪烁
    lcd1602_set_pos(0, 0);
    lcd1602_write_num(2, schedule.month);
    lcd1602_set_pos(3, 0);
    lcd1602_write_num(2, schedule.day);
    lcd1602_set_pos(6, 0);
    lcd1602_write_num(2, schedule.hour);
    lcd1602_set_pos(9, 0);
    lcd1602_write_num(2, schedule.miunte);
    lcd1602_set_pos(13, 0);
    if (schedule.state == SCHEDULE_ON) {
        lcd1602_write_str(" on");
    } else {
        lcd1602_write_str("off");
    }
    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(3, 0);
    } else if (cur_pos == 4) {
        lcd1602_set_pos(4, 0);
    } else if (cur_pos == 5) {
        lcd1602_set_pos(6, 0);
    } else if (cur_pos == 6) {
        lcd1602_set_pos(7, 0);
    } else if (cur_pos == 7) {
        lcd1602_set_pos(9, 0);
    } else if (cur_pos == 8) {
        lcd1602_set_pos(10, 0);
    } else if (cur_pos == 9) {
        if (schedule.state == SCHEDULE_ON) {
            lcd1602_set_pos(14, 0);
        } else {
            lcd1602_set_pos(13, 0);
        }
    }
    lcd1602_write_cmd(0x08 |  // 显示光标并闪烁
                      LCD1602_DISPLAY_ENABLE |
                      LCD1602_CURSOR_ENABLE |
                      LCD1602_CURSOR_TWINKLE);
}

/*******************************************************************************
* 函 数 名         : schedule_close
* 函数功能         : 关闭日程
* 输    入         : void
* 输    出         : void
* 说    名         : none
*******************************************************************************/
void schedule_close(void)  // 关闭日程
{
    schedule.state = SCHEDULE_OFF;
}
发布了15 篇原创文章 · 获赞 17 · 访问量 1647

猜你喜欢

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