#include "clock.h" #include "xtell.h" // 软时钟基础计时变量 u8 current_hour = 10; // 系统软时钟:小时 (默认初始化为 10 点) u8 current_min = 35; // 系统软时钟:分钟 (默认初始化为 35 分) u8 current_sec = 0; // 系统软时钟:秒 u8 current_day = 1; // 系统软时钟:日 (默认初始化为 1 号) u8 current_month = 1; // 系统软时钟:月 (默认初始化为 1 月) u8 current_year = 25; // 系统软时钟:年 (默认初始化为 2025 年) u8 current_weekday = 0; // 系统软时钟:星期 (0=周日, 由 Clock_RecalcWeekday 现算) volatile u8 clock_updated = 0; // 分钟跳变标志位,置位后用于驱动 UI 刷新时间显示 volatile bit second_tick_flag = 0; // 整秒滴答标志位,每次秒进位置 1,由主循环转换为 KEY_EVENT_SECOND_TICK 事件 // 毫秒计数器 (Timer1 每 1ms 累加) static u16 ms_cnt = 0; // 每月天数表 (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); } /** * @brief 系统软时钟毫秒递增更新 (在 1ms 中断中调用) * @details 负责由定时器 1ms 驱动递增软时钟,并在分钟/日期发生跳变时做相应处理 */ void Clock_IncMS(void) { ms_cnt++; if (ms_cnt >= 1000) { ms_cnt = 0; // 1秒时间到 current_sec++; second_tick_flag = 1; // 整秒滴答,通知主循环生成 KEY_EVENT_SECOND_TICK 事件 if (current_sec >= 60) { current_sec = 0; // 1分钟时间到 current_min++; if (current_min >= 60) { current_min = 0; // 1小时时间到 current_hour++; if (current_hour >= 24) { 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(); // 日期变化,重新计算星期 } } clock_updated = 1; // 分钟跳变,标志位置位,前台待机 App 会捕获以刷新 UI XTELL_LOG("[CLOCK] Time updated!\r\n"); } } }