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