Files
secs2-SJ/usr/bsp/bsp_DS1302.c
T
2026-09-09 14:54:40 +08:00

373 lines
10 KiB
C

#include "bsp_DS1302.h"
#define bsp_DS1302_DELAY() do{ \
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
}while(0)
#define RST_CLR HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_RESET )
#define RST_SET HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_SET )
#define IO_CLR HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_RESET )
#define IO_SET HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_SET )
#define IO_READ HAL_GPIO_ReadPin (DS1302_DIO_GPIO_Port, DS1302_DIO_Pin )
#define SCK_CLR HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_RESET )
#define SCK_SET HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_SET )
static u32 g_time_sec_base = 0; // 绝对秒数基准(从 2000-01-01 起)
static u32 g_time_tick_base = 0; // 对应的 HAL Tick 值(毫秒)
static void bsp_DS1302Init(void);
static void bsp_DS1302_Task(void);
static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime);
static void bsp_DS1302DataInput(void);
static void bsp_DS1302DataOutput(void);
static void bsp_DS1302_write_byte(u8 Addr, u8 Data);
static u8 bsp_DS1302_read_byte(u8 Addr);
static u8 HexToBCD(u8 code);
static u8 is_leap_year(u16 year);
static void bsp_DS1302_UpdateBase(void);
static void bsp_DS1302_GetTimeWithMs(char *buf, u16 len);
static u32 bsp_DS1302_GetCurrentSeconds(void);
static u8 bsp_DS1302_SetTimeWithMs(u16 year, u8 month, u8 day,
u8 hour, u8 minute, u8 second, u32 ms);
static u32 datetime_to_seconds(u16 year, u8 month, u8 day,
u8 hour, u8 minute, u8 second);
static void seconds_to_datetime(u32 seconds, u16 *year, u8 *month, u8 *day,
u8 *hour, u8 *minute, u8 *second);
bsp_DS1302_t DS1302 =
{
.Init = bsp_DS1302Init,
.Task = bsp_DS1302_Task,
.Set = bsp_DS1302_Set,
.UpdateBase = bsp_DS1302_UpdateBase,
.GetTimeWithMs = bsp_DS1302_GetTimeWithMs,
.GetCurrentSeconds = bsp_DS1302_GetCurrentSeconds,
.SetTimeWithMs = bsp_DS1302_SetTimeWithMs,
};
bsp_DS1302_t *pDS1302 = &DS1302;
static void bsp_DS1302DataInput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
static void bsp_DS1302DataOutput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
/*向bsp_DS1302写入一字节数据*/
static void bsp_DS1302_write_byte(u8 Addr, u8 Data)
{
u8 i;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr & 0xFE;/*最低位置零*/
for (i = 0; i < 8; i++)
{
if (Addr & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
/*写入数据:d*/
for (i = 0; i < 8; i++)
{
if (Data & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Data = Data >> 1;
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
}
/*从bsp_DS1302读出一字节数据*/
static u8 bsp_DS1302_read_byte(u8 Addr)
{
u8 i;
u8 temp;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr | 0x01;/*最低位置高*/
for (i = 0; i < 8; i++)
{
if (Addr & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
bsp_DS1302DataInput();
/*输出数据:temp*/
for (i = 0; i < 8; i++)
{
temp = temp >> 1;
if (IO_READ)
{
temp |= 0x80;
}
else
{
temp &= 0x7F;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
bsp_DS1302DataOutput();
return temp;
}
static u8 HexToBCD(u8 code)
{
u8 temp;
temp = ((code / 10) << 4) + (code % 10);
return temp;
}
// ---------- 时间计算辅助函数 ----------
static u8 is_leap_year(u16 year)
{
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
static u32 datetime_to_seconds(u16 year, u8 month, u8 day,
u8 hour, u8 minute, u8 second)
{
const u8 month_days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
u32 days = 0;
for (u16 y = 2000; y < year; y++) {
days += 365 + is_leap_year(y);
}
for (u8 m = 1; m < month; m++) {
days += month_days[m-1];
if (m == 2 && is_leap_year(year)) days++;
}
days += (day - 1);
return days * 86400UL + hour * 3600UL + minute * 60UL + second;
}
static void seconds_to_datetime(u32 seconds, u16 *year, u8 *month, u8 *day,
u8 *hour, u8 *minute, u8 *second)
{
u32 days = seconds / 86400;
u32 secs_rem = seconds % 86400;
u16 y = 2000;
while (1) {
u16 days_in_year = 365 + is_leap_year(y);
if (days < days_in_year) break;
days -= days_in_year;
y++;
}
*year = y;
u8 month_days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
if (is_leap_year(y)) month_days[1] = 29;
u8 m;
for (m = 1; m <= 12; m++) {
if (days < month_days[m-1]) break;
days -= month_days[m-1];
}
*month = m;
*day = days + 1;
*hour = secs_rem / 3600;
*minute = (secs_rem % 3600) / 60;
*second = secs_rem % 60;
}
// ---------- 新增毫秒级扩展功能实现 ----------
static void bsp_DS1302_UpdateBase(void)
{
u16 year = 2000 + DS1302.Time.Year;
g_time_sec_base = datetime_to_seconds(year, DS1302.Time.Month, DS1302.Time.Day,
DS1302.Time.Hour, DS1302.Time.Minute, DS1302.Time.Second);
g_time_tick_base = HAL_GetTick();
}
static void bsp_DS1302_GetTimeWithMs(char *buf, u16 len)
{
if (!buf || len < 17) return;
u32 tick_diff = HAL_GetTick() - g_time_tick_base; // 自动处理回绕
u32 total_sec = g_time_sec_base + tick_diff / 1000;
u32 ms = tick_diff % 1000;
u16 year; u8 month, day, hour, minute, second;
seconds_to_datetime(total_sec, &year, &month, &day, &hour, &minute, &second);
u8 ms_two_digits = ms / 10;
snprintf(buf, len, "%04d%02d%02d%02d%02d%02d%02d",
year, month, day, hour, minute, second, ms_two_digits);
}
static u32 bsp_DS1302_GetCurrentSeconds(void)
{
u32 tick_diff = HAL_GetTick() - g_time_tick_base;
return g_time_sec_base + tick_diff / 1000;
}
static u8 bsp_DS1302_SetTimeWithMs(u16 year, u8 month, u8 day,
u8 hour, u8 minute, u8 second, u32 ms)
{
if (year < 2000 || year > 2099 || month < 1 || month > 12 ||
day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59 || ms > 99) {
return 0;
}
bsp_DS1302_Time_t time;
time.Year = year - 2000;
time.Month = month;
time.Day = day;
time.Hour = hour;
time.Minute = minute;
time.Second = second;
if (bsp_DS1302_Set(&time) != 1) {
return 0;
}
// 校准基准
u32 actual_ms = ms * 10;
g_time_sec_base = datetime_to_seconds(year, month, day, hour, minute, second);
g_time_tick_base = HAL_GetTick() - actual_ms;
return 1;
}
static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime)
{
if ((pTime->Year > 99) || (pTime->Month > 12) || (pTime->Day > 31) ||
(pTime->Hour > 23) || (pTime->Minute > 59) || (pTime->Second > 59))
{
return USR_FALSE;
}
else
{
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x00); //关闭写保护
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, 0x80); //暂停
bsp_DS1302_write_byte(BSP_DS1302_YEAR_ADDR, HexToBCD(pTime->Year));
bsp_DS1302_write_byte(BSP_DS1302_MONTH_ADDR, HexToBCD(pTime->Month));
bsp_DS1302_write_byte(BSP_DS1302_DATA_ADDR, HexToBCD(pTime->Day));
bsp_DS1302_write_byte(BSP_DS1302_HOUR_ADDR, HexToBCD(pTime->Hour));
bsp_DS1302_write_byte(BSP_DS1302_MIN_ADDR, HexToBCD(pTime->Minute));
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, HexToBCD(pTime->Second));
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x80); //打开写保护
return USR_TRUE;
}
}
static void bsp_DS1302_Task(void)
{
u8 RegData;
RegData = bsp_DS1302_read_byte(BSP_DS1302_YEAR_ADDR);
pDS1302->Time.Year = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MONTH_ADDR);
pDS1302->Time.Month = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_DATA_ADDR);
pDS1302->Time.Day = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_HOUR_ADDR);
pDS1302->Time.Hour = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MIN_ADDR);
pDS1302->Time.Minute = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_SEC_ADDR);
pDS1302->Time.Second = (RegData / 16) * 10 + RegData % 16;
}
static void bsp_DS1302Init(void)
{
RST_SET;
SCK_CLR;
bsp_DS1302_Task();
if ((pDS1302->Time.Year > 99) || (pDS1302->Time.Month > 12) || (pDS1302->Time.Day > 31) ||
(pDS1302->Time.Hour > 23) || (pDS1302->Time.Minute > 59) || (pDS1302->Time.Second > 59))
{
pDS1302->Time.Year = 25;
pDS1302->Time.Month = 1;
pDS1302->Time.Day = 1;
pDS1302->Time.Hour = 0;
pDS1302->Time.Minute = 0;
pDS1302->Time.Second = 0;
bsp_DS1302_Set(&pDS1302->Time);
}
}