增加文件系统
This commit is contained in:
199
App/sys_clock.c
Normal file
199
App/sys_clock.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* 模块名称:System Clock — Wall Clock Time Maintenance
|
||||
* 模块功能:实现系统墙钟时间维护,包括 RTC 初始读取、HAL Tick 漂移维持
|
||||
* 适用平台:STM32F407ZGTx (Cortex-M4 FPU, 168MHz)
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-07-19
|
||||
* 修改记录:
|
||||
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||
*/
|
||||
|
||||
#include "sys_clock.h"
|
||||
#include "main.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define DBG_TAG "[CLK]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
/* ============================================================
|
||||
* 内部状态:系统墙钟
|
||||
* ============================================================ */
|
||||
|
||||
static volatile uint32_t s_base_tick = 0; /* HAL_GetTick() 基准 */
|
||||
static volatile uint32_t s_base_unix_secs = UINT32_MAX;
|
||||
|
||||
/* ============================================================
|
||||
* 内部辅助函数:Unix time ↔ sd2506_time_t 转换
|
||||
* ============================================================ */
|
||||
|
||||
static void unix_to_sd2506(uint32_t unix_secs, sd2506_time_t *p_sd_time)
|
||||
{
|
||||
uint32_t y, m, d;
|
||||
uint8_t h, mi, s;
|
||||
int is_leap;
|
||||
|
||||
/* 时分秒 */
|
||||
{
|
||||
uint64_t total = (uint64_t)unix_secs;
|
||||
s = (uint8_t)(total % 60uLL);
|
||||
total /= 60uLL;
|
||||
mi = (uint8_t)(total % 60uLL);
|
||||
total /= 60uLL;
|
||||
h = (uint8_t)(total % 24uL);
|
||||
}
|
||||
|
||||
/* 年月日 */
|
||||
{
|
||||
uint64_t day_count = ((uint64_t)unix_secs / 86400uL);
|
||||
|
||||
y = 1970u;
|
||||
while (day_count >= 365uLL) {
|
||||
uint64_t diy = 365uLL;
|
||||
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) {
|
||||
diy = 366uLL;
|
||||
}
|
||||
if (day_count < diy) break;
|
||||
day_count -= diy;
|
||||
y++;
|
||||
}
|
||||
|
||||
is_leap = ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0));
|
||||
uint8_t mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
if (is_leap) mdays[1] = 29;
|
||||
|
||||
m = 0;
|
||||
while (m < 12u) {
|
||||
if (day_count < (uint64_t)mdays[m]) break;
|
||||
day_count -= mdays[m];
|
||||
m++;
|
||||
}
|
||||
d = (uint32_t)(day_count + 1uL);
|
||||
|
||||
/* 星期(Zeller's congruence,0=Sunday) */
|
||||
uint64_t wy = y;
|
||||
uint64_t wm = m;
|
||||
if (wm <= 2) {
|
||||
wy--;
|
||||
wm += 12uL;
|
||||
}
|
||||
uint8_t week = ((uint32_t)(wy % 100uLL + wy / 100uLL / 4uLL - wy / 100uLL / 15uLL) +
|
||||
(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;
|
||||
p_sd_time->month = m + 1uL; /* 月份从 0 → 1 */
|
||||
p_sd_time->day = d;
|
||||
p_sd_time->hour = h;
|
||||
p_sd_time->minute = mi;
|
||||
p_sd_time->second = s;
|
||||
p_sd_time->week = week;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 系统墙钟时间维护
|
||||
* ============================================================ */
|
||||
|
||||
int sys_clock_init(void)
|
||||
{
|
||||
sd2506_time_t sd_time;
|
||||
uint32_t year, month, day, hour, minute, second;
|
||||
int64_t unix_secs = 0;
|
||||
int i;
|
||||
|
||||
/* Step 1: 从 SD2506 RTC 读取初始时间 */
|
||||
sd2506_get_time(&sd_time);
|
||||
|
||||
year = (uint32_t)sd_time.year + 2000uL;
|
||||
month = (uint32_t)sd_time.month;
|
||||
day = (uint32_t)sd_time.day;
|
||||
hour = (uint32_t)sd_time.hour;
|
||||
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) */
|
||||
{
|
||||
uint64_t total_days = 0;
|
||||
|
||||
for (i = 1970; i < year; i++) {
|
||||
if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0)) {
|
||||
total_days += 366uLL;
|
||||
} else {
|
||||
total_days += 365uLL;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (i = 0; i < month - 1; i++) {
|
||||
total_days += mdays[i];
|
||||
}
|
||||
total_days += day - 1uL;
|
||||
|
||||
unix_secs = (int64_t)(total_days * 86400LL) + hour * 3600LL + minute * 60LL + second;
|
||||
}
|
||||
|
||||
/* Step 3: 设置系统墙钟基准 */
|
||||
s_base_tick = HAL_GetTick();
|
||||
s_base_unix_secs = (uint32_t)unix_secs;
|
||||
|
||||
DBG_INFO("sys_clock_init: wall clock base = unix %lu, base_tick=%lu",
|
||||
(unsigned long)s_base_unix_secs, (unsigned long)s_base_tick);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t sys_clock_get(void)
|
||||
{
|
||||
uint32_t now_tick = HAL_GetTick();
|
||||
int64_t unix_secs = (int64_t)s_base_unix_secs + (int64_t)((uint32_t)(now_tick - s_base_tick) / 1000uL);
|
||||
|
||||
if (unix_secs < 0) {
|
||||
return UINT32_MAX; /* 未初始化 */
|
||||
}
|
||||
|
||||
return (uint32_t)unix_secs;
|
||||
}
|
||||
|
||||
char *sys_clock_get_str(char *buf, size_t buf_size)
|
||||
{
|
||||
uint32_t unix_secs = sys_clock_get();
|
||||
if (unix_secs == UINT32_MAX) {
|
||||
snprintf(buf, buf_size, "----/--/-- --:--:--");
|
||||
return buf;
|
||||
}
|
||||
|
||||
sd2506_time_t sd;
|
||||
unix_to_sd2506(unix_secs, &sd);
|
||||
|
||||
snprintf(buf, buf_size, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
sd.year + 2000uL, sd.month, sd.day,
|
||||
sd.hour, sd.minute, sd.second);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int sys_clock_set(uint32_t unix_secs, const sd2506_time_t *sd_time)
|
||||
{
|
||||
/* Step 1: 更新墙钟基准 */
|
||||
s_base_tick = HAL_GetTick();
|
||||
s_base_unix_secs = unix_secs;
|
||||
|
||||
DBG_INFO("sys_clock_set: wall clock updated to %lu", (unsigned long)unix_secs);
|
||||
|
||||
/* Step 2: 写回 SD2506 RTC(若提供了 sd_time) */
|
||||
if (sd_time != NULL) {
|
||||
sd2506_set_time(sd_time);
|
||||
DBG_INFO("sys_clock_set: SD2506 RTC written");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user