时间终于同步,存储成功
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
* 修改日期/时间时同步更新下列宏。
|
||||
* ============================================================ */
|
||||
#define RTC_DEFAULT_INIT_ENABLE 1
|
||||
#define RTC_DEFAULT_INIT_FORCE 1
|
||||
#define RTC_DEFAULT_INIT_FORCE 0
|
||||
#define RTC_DEFAULT_YEAR 2026
|
||||
#define RTC_DEFAULT_MONTH 8
|
||||
#define RTC_DEFAULT_DAY 24
|
||||
@@ -134,10 +134,10 @@ static void unix_to_sd2506(uint32_t unix_secs, sd2506_time_t *p_sd_time)
|
||||
(uint32_t)(((uint64_t)26 * (wm + 1uL)) / 10uLL) +
|
||||
(uint32_t)(d % 100uLL)) % 7uLL;
|
||||
|
||||
/* SD2506 year 字段为 0~99(+2000) */
|
||||
uint16_t sd_year = y >= 2000 ? (y - 2000) : (y + 2000);
|
||||
|
||||
p_sd_time->year = sd_year;
|
||||
/* sd2506_time_t.year 采用完整年份(如 2026),与 sd2506_set_time
|
||||
* 中 year-2000、sd2506_get_time 中 +2000 的约定保持一致;
|
||||
* 此处绝不能再减 2000,否则写 RTC 时会被二次减 2000 导致年份错乱。 */
|
||||
p_sd_time->year = (uint16_t)y;
|
||||
p_sd_time->month = m + 1uL; /* 月份从 0 → 1 */
|
||||
p_sd_time->day = d;
|
||||
p_sd_time->hour = h;
|
||||
@@ -169,22 +169,31 @@ int sys_clock_init(void)
|
||||
int64_t unix_secs = 0;
|
||||
int i;
|
||||
|
||||
/* Step 1: 从 SD2506 RTC 读取初始时间
|
||||
* 注意:sd2506_get_time() 返回的 year 已是完整年份(如 2026,驱动内 +2000),
|
||||
* 此处不得再加 2000,否则年份虚增 → unix 秒数超 uint32 被截断回绕。 */
|
||||
/* ============================================================
|
||||
* Step 1:从 SD2506 硬件 RTC 读取初始时间
|
||||
* ============================================================
|
||||
* 注意:sd2506_get_time() 返回的 year 已是完整年份(如 2026,
|
||||
* 驱动内部已 +2000)。此处【禁止】再 +2000,否则年份虚增到 4026,
|
||||
* 换算出的 Unix 秒数远超 uint32_t 上限被截断回绕,时间彻底错乱。 */
|
||||
sd2506_get_time(&sd_time);
|
||||
|
||||
/* RTC 校时(可选):时间无效时,或 FORCE=1 强制时,写入编译期默认时间 */
|
||||
/* ============================================================
|
||||
* Step 1.1:开发期校时(可选,由 RTC_DEFAULT_INIT_* 宏控制)
|
||||
* ============================================================
|
||||
* 作用:RTC 出厂/掉电异常导致时间非法时,写入一个可用初始值;
|
||||
* FORCE=1 时每次启动都强制写入,便于首次烧录或硬件时钟丢失。
|
||||
* 判定"时间无效":年份越界、月/日越界(仅粗判,不细校 2 月 29 日等)。 */
|
||||
#if defined(RTC_DEFAULT_INIT_ENABLE)
|
||||
{
|
||||
int rtc_invalid = (sd_time.year < 2000 || sd_time.year > 2099 ||
|
||||
sd_time.month < 1 || sd_time.month > 12 ||
|
||||
sd_time.day < 1 || sd_time.day > 31);
|
||||
#if (RTC_DEFAULT_INIT_FORCE == 1)
|
||||
rtc_invalid = 1; /* 强制每次启动校时 */
|
||||
rtc_invalid = 1; /* 强制每次启动校时:会覆盖用户/网络已设的正确时间,仅限开发期 */
|
||||
#endif
|
||||
if (rtc_invalid) {
|
||||
sd2506_time_t init_t;
|
||||
/* 用编译期默认宏构造初始时间;week 由 Zeller 公式(rtc_calc_week)推算 */
|
||||
init_t.year = RTC_DEFAULT_YEAR;
|
||||
init_t.month = RTC_DEFAULT_MONTH;
|
||||
init_t.day = RTC_DEFAULT_DAY;
|
||||
@@ -193,11 +202,12 @@ int sys_clock_init(void)
|
||||
init_t.second = RTC_DEFAULT_SECOND;
|
||||
init_t.week = rtc_calc_week(init_t.year, init_t.month, init_t.day);
|
||||
|
||||
/* 写回 SD2506:断电后该时间被保留,下次上电即为有效值 */
|
||||
if (sd2506_set_time(&init_t) == SD2506_OK) {
|
||||
DBG_INFO("sys_clock_init: RTC set %04d-%02d-%02d %02d:%02d:%02d",
|
||||
init_t.year, init_t.month, init_t.day,
|
||||
init_t.hour, init_t.minute, init_t.second);
|
||||
sd2506_get_time(&sd_time); /* 重新读取校准后的时间 */
|
||||
sd2506_get_time(&sd_time); /* 重新读取校准后的值,确保后续换算用真实 RTC 数据 */
|
||||
} else {
|
||||
DBG_ERROR("sys_clock_init: RTC default write FAIL");
|
||||
}
|
||||
@@ -205,6 +215,7 @@ int sys_clock_init(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 取出各时间字段(year 已是完整年份,直接用于下文 Unix 换算) */
|
||||
year = (uint32_t)sd_time.year;
|
||||
month = (uint32_t)sd_time.month;
|
||||
day = (uint32_t)sd_time.day;
|
||||
@@ -212,13 +223,19 @@ int sys_clock_init(void)
|
||||
minute = (uint32_t)sd_time.minute;
|
||||
second = (uint32_t)sd_time.second;
|
||||
|
||||
DBG_INFO("sys_clock_init: RTC initial time %04d-%02d-%02d %02d:%02d:%02d",
|
||||
year, month, day, hour, minute, second);
|
||||
|
||||
/* Step 2: Unix epoch → seconds(简化算法,适用于 1970~2038) */
|
||||
/* ============================================================
|
||||
* Step 2:将 RTC 日历时间换算为 Unix epoch 秒数
|
||||
* ============================================================
|
||||
* Unix 时间定义:自 1970-01-01 00:00:00 起经过的秒数。
|
||||
* 算法:总天数(1970~去年整年 + 今年到上月 + 本月已过天)× 86400
|
||||
* + 当天时分秒。
|
||||
* 用 int64_t / uint64_t 累加避免中间溢出;最终结果(受 uint32_t 限制)
|
||||
* 有效范围约 1970-01-01 ~ 2038-01-19,超出将回绕(见文档第 12 节)。 */
|
||||
{
|
||||
uint64_t total_days = 0;
|
||||
|
||||
/* 2.1 累加 1970 至(今年-1)的整年天数:闰年 366、平年 365
|
||||
* 闰年规则:能被 4 整除但不能被 100 整除,或能被 400 整除 */
|
||||
for (i = 1970; i < year; i++) {
|
||||
if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0)) {
|
||||
total_days += 366uLL;
|
||||
@@ -227,22 +244,34 @@ int sys_clock_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* 2.2 判断今年是否闰年,构造各月天数表(2 月特判) */
|
||||
int is_leap = ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
|
||||
uint8_t mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
if (is_leap) mdays[1] = 29;
|
||||
if (is_leap) mdays[1] = 29; /* 闰年 2 月 29 天 */
|
||||
|
||||
/* 2.3 累加今年 1 月至(本月-1)月的天数 */
|
||||
for (i = 0; i < month - 1; i++) {
|
||||
total_days += mdays[i];
|
||||
}
|
||||
/* 2.4 加上本月已过天数(day-1:从今天 0 点起算) */
|
||||
total_days += day - 1uL;
|
||||
|
||||
/* 2.5 总天数×86400(一天秒数)+ 当日时分秒 = 绝对 Unix 秒数 */
|
||||
unix_secs = (int64_t)(total_days * 86400LL) + hour * 3600LL + minute * 60LL + second;
|
||||
}
|
||||
|
||||
/* Step 3: 设置系统墙钟基准 */
|
||||
/* ============================================================
|
||||
* Step 3:建立"墙钟基准"(基准法核心)
|
||||
* ============================================================
|
||||
* 记录当前 HAL Tick 与对应的 Unix 秒数。此后 sys_clock_get() 仅用
|
||||
* now_unix = s_base_unix_secs + (HAL_GetTick() - s_base_tick)/1000
|
||||
* 推算当前时间,运行期不再访问 I2C RTC,零阻塞、无累积误差。 */
|
||||
s_base_tick = HAL_GetTick();
|
||||
s_base_unix_secs = (uint32_t)unix_secs;
|
||||
|
||||
DBG_INFO("sys_clock_init: RTC initial time %04d-%02d-%02d %02d:%02d:%02d",
|
||||
year, month, day, hour, minute, second);
|
||||
|
||||
DBG_INFO("sys_clock_init: wall clock base = unix %lu, base_tick=%lu",
|
||||
(unsigned long)s_base_unix_secs, (unsigned long)s_base_tick);
|
||||
|
||||
@@ -293,7 +322,7 @@ char *sys_clock_get_str(char *buf, size_t buf_size)
|
||||
unix_to_sd2506(unix_secs, &sd);
|
||||
|
||||
snprintf(buf, buf_size, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
sd.year + 2000uL, sd.month, sd.day,
|
||||
sd.year, sd.month, sd.day,
|
||||
sd.hour, sd.minute, sd.second);
|
||||
return buf;
|
||||
}
|
||||
@@ -318,8 +347,11 @@ int sys_clock_set(uint32_t unix_secs, const sd2506_time_t *sd_time)
|
||||
|
||||
/* Step 2: 写回 SD2506 RTC(若提供了 sd_time) */
|
||||
if (sd_time != NULL) {
|
||||
sd2506_set_time(sd_time);
|
||||
DBG_INFO("sys_clock_set: SD2506 RTC written");
|
||||
if (sd2506_set_time(sd_time) == SD2506_OK) {
|
||||
DBG_INFO("sys_clock_set: SD2506 RTC written");
|
||||
} else {
|
||||
DBG_ERROR("sys_clock_set: SD2506 RTC write FAIL");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user