2026-07-17 09:08:53 +08:00
|
|
|
|
#include "clock.h"
|
|
|
|
|
|
#include "xtell.h"
|
|
|
|
|
|
|
|
|
|
|
|
// 软时钟基础计时变量
|
|
|
|
|
|
u8 current_hour = 10; // 系统软时钟:小时 (默认初始化为 10 点)
|
|
|
|
|
|
u8 current_min = 35; // 系统软时钟:分钟 (默认初始化为 35 分)
|
|
|
|
|
|
u8 current_sec = 0; // 系统软时钟:秒
|
2026-07-31 19:32:44 +08:00
|
|
|
|
u8 current_day = 1; // 系统软时钟:日 (默认初始化为 1 号)
|
|
|
|
|
|
u8 current_month = 1; // 系统软时钟:月 (默认初始化为 1 月)
|
|
|
|
|
|
u8 current_year = 25; // 系统软时钟:年 (默认初始化为 2025 年)
|
|
|
|
|
|
u8 current_weekday = 0; // 系统软时钟:星期 (0=周日, 由 Clock_RecalcWeekday 现算)
|
2026-07-17 09:08:53 +08:00
|
|
|
|
volatile u8 clock_updated = 0; // 分钟跳变标志位,置位后用于驱动 UI 刷新时间显示
|
2026-07-31 18:49:03 +08:00
|
|
|
|
volatile bit second_tick_flag = 0; // 整秒滴答标志位,每次秒进位置 1,由主循环转换为 KEY_EVENT_SECOND_TICK 事件
|
2026-07-17 09:08:53 +08:00
|
|
|
|
|
|
|
|
|
|
// 毫秒计数器 (Timer1 每 1ms 累加)
|
|
|
|
|
|
static u16 ms_cnt = 0;
|
|
|
|
|
|
|
2026-07-31 19:32:44 +08:00
|
|
|
|
// 每月天数表 (2 月固定按 28 天,闰年在 Days_In_Month 里单独加 1 天处理)
|
|
|
|
|
|
static code u8 days_in_month_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
|
|
|
|
|
|
|
|
|
u8 Days_In_Month(u8 year, u8 month)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (month < 1 || month > 12) {
|
|
|
|
|
|
return 31; // 防御性兜底,不应该发生
|
|
|
|
|
|
}
|
|
|
|
|
|
if (month == 2) {
|
|
|
|
|
|
// 闰年判断:2000~2099 区间内,能被 4 整除即为闰年 (期间没有能被 100 整除的年份需要排除)
|
|
|
|
|
|
if ((year % 4) == 0) {
|
|
|
|
|
|
return 29;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return days_in_month_table[month - 1];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Clock_RecalcWeekday(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Zeller 公式:h = (q + [13(m+1)/5] + K + [K/4] + [J/4] - 2J) mod 7
|
|
|
|
|
|
// h: 0=周六,1=周日,2=周一,...,6=周五;用 "+5J" 代替 "-2J" 避免无符号数下溢 (-2 ≡ 5 (mod 7))
|
|
|
|
|
|
// 1、2 月按上一年的 13、14 月处理
|
|
|
|
|
|
u8 m = current_month;
|
|
|
|
|
|
u8 y = current_year;
|
|
|
|
|
|
u8 j = 20; // 世纪数 (2000~2099 固定为 20)
|
|
|
|
|
|
u16 h;
|
|
|
|
|
|
|
|
|
|
|
|
if (m < 3) {
|
|
|
|
|
|
m += 12;
|
|
|
|
|
|
if (y == 0) {
|
|
|
|
|
|
y = 99; // 2000 年 1/2 月,按 1999 年处理的边界情况
|
|
|
|
|
|
j = 19;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
y -= 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h = (current_day + (13UL * (m + 1)) / 5 + y + y / 4 + j / 4 + 5UL * j) % 7;
|
|
|
|
|
|
|
|
|
|
|
|
// 把 Zeller 原始约定 (0=周六) 转换成常用的 0=周日, 1=周一, ..., 6=周六
|
|
|
|
|
|
current_weekday = (u8)((h + 6) % 7);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-17 09:08:53 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 系统软时钟毫秒递增更新 (在 1ms 中断中调用)
|
2026-07-31 19:32:44 +08:00
|
|
|
|
* @details 负责由定时器 1ms 驱动递增软时钟,并在分钟/日期发生跳变时做相应处理
|
2026-07-17 09:08:53 +08:00
|
|
|
|
*/
|
|
|
|
|
|
void Clock_IncMS(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
ms_cnt++;
|
|
|
|
|
|
if (ms_cnt >= 1000) {
|
|
|
|
|
|
ms_cnt = 0; // 1秒时间到
|
|
|
|
|
|
current_sec++;
|
2026-07-31 18:49:03 +08:00
|
|
|
|
second_tick_flag = 1; // 整秒滴答,通知主循环生成 KEY_EVENT_SECOND_TICK 事件
|
2026-07-17 09:08:53 +08:00
|
|
|
|
if (current_sec >= 60) {
|
|
|
|
|
|
current_sec = 0; // 1分钟时间到
|
|
|
|
|
|
current_min++;
|
|
|
|
|
|
if (current_min >= 60) {
|
|
|
|
|
|
current_min = 0; // 1小时时间到
|
|
|
|
|
|
current_hour++;
|
|
|
|
|
|
if (current_hour >= 24) {
|
2026-07-31 19:32:44 +08:00
|
|
|
|
current_hour = 0; // 小时循环,日期进位
|
|
|
|
|
|
current_day++;
|
|
|
|
|
|
if (current_day > Days_In_Month(current_year, current_month)) {
|
|
|
|
|
|
current_day = 1; // 月份进位
|
|
|
|
|
|
current_month++;
|
|
|
|
|
|
if (current_month > 12) {
|
|
|
|
|
|
current_month = 1; // 年份进位 (不处理世纪)
|
|
|
|
|
|
current_year++;
|
|
|
|
|
|
if (current_year > 99) {
|
|
|
|
|
|
current_year = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
Clock_RecalcWeekday(); // 日期变化,重新计算星期
|
2026-07-17 09:08:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
clock_updated = 1; // 分钟跳变,标志位置位,前台待机 App 会捕获以刷新 UI
|
|
|
|
|
|
XTELL_LOG("[CLOCK] Time updated!\r\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|