Files
stc32g128k/App/clock.c
edisondeng cb37b1deea feat(clock): add day/month/year rollover and Zeller weekday calc
Extends Clock_IncMS()'s existing sec->min->hour cascade to also roll
day->month->year (with leap-year Feb 29 via Days_In_Month()), and adds
Clock_RecalcWeekday() computing current_weekday via Zeller's congruence
whenever the date changes, rather than trusting PCF8563's own weekday
register (which would drift if the date is edited manually). Verified
the formula against 2026-07-31, a known Friday.
2026-07-31 19:32:44 +08:00

100 lines
4.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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");
}
}
}