JT-DT-YD4N02B_4G_RTT_MRS/bsp/src/bsp_rtc.c

493 lines
15 KiB
C
Raw Normal View History

2024-12-30 11:50:48 +08:00
#include "bsp_rtc.h"
#include "bsp_flash.h"
#include "time.h"
// 用到了atoi
#include <stdlib.h>
#define LOG_TAG "bsp_rtc" // 该模块对应的标签。不定义时默认NO_TAG
#define LOG_LVL LOG_LVL_DBG // 该模块对应的日志输出级别。不定义时,默认:调试级别
#include <ulog.h>
#define RTC_FIRST_INIT_VALUE (0x1314)
TsRtcDateTime RtcDateTime;
uint8_t const month_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/**
* @description: Judging whether it is a leap year.
* @param {uint16_t} year
* @return {*} 1 - Yes
* 0 - No
*/
// 月份 1 2 3 4 5 6 7 8 9 10 11 12
// 闰年 31 29 31 30 31 30 31 31 30 31 30 31
// 非闰年 31 28 31 30 31 30 31 31 30 31 30 31
static uint8_t Is_LeapYear(u16 year)
{
if (year % 4 == 0)
{
if (year % 100 == 0)
{
if (year % 400 == 0)
return 1;
else
return 0;
}
else
return 1;
}
else
return 0;
}
/**
* @description: Get the current day of the week.
* (: 031, , )
* 使 , :
* https://www.cnblogs.com/fengbohello/p/3264300.html
* @param {uint16_t} year
* @param {uint8_t} month
* @param {uint8_t} day
* @return {*}
*/
uint8_t RTC_GetWeek(uint16_t year, uint8_t month, uint8_t day)
{
uint8_t week = 0;
if (month < 3)
{
month += 12;
--year;
}
week = (day + 1 + 2 * month + 3 * (month + 1) / 5 + year + (year >> 2) - year / 100 + year / 400) % 7;
return week;
}
/**
* @description:
* @note 197011, 197011, 000, 0
* 2105, uint32_t最大表示136年的秒钟数()!
* linux mktime函数, :
* http://www.openedv.com/thread-63389-1-1.html
* @param {uint16_t} syear
* @param {uint8_t} smon
* @param {uint8_t} sday
* @param {uint8_t} hour
* @param {uint8_t} min
* @param {uint8_t} sec
* @return {*}
*/
uint32_t DateTime2Seconds(uint16_t syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec)
{
ASSERT((syear > 1970 || syear < 2099));
uint32_t y, m, d, x, t;
signed char monx = smon; /* 将月份转换成带符号的值, 方便后面运算 */
if (0 >= (monx -= 2)) /* 1..12 -> 11,12,1..10 */
{
monx += 12; /* Puts Feb last since it has leap day */
syear -= 1;
}
y = (syear - 1) * 365 + syear / 4 - syear / 100 + syear / 400; /* 公元元年1到现在的闰年数 */
m = 367 * monx / 12 - 30 + 59;
d = sday - 1;
x = y + m + d - 719162; /* 减去公元元年到1970年的天数 */
t = ((x * 24 + hour) * 60 + min) * 60 + sec; /* 总秒钟数 */
return t;
}
uint32_t RTC_Time2TimeStamp(void)
{
RTC_GetTime();
uint32_t time_stamp = DateTime2Seconds(RtcDateTime.year, RtcDateTime.month, RtcDateTime.day, RtcDateTime.hour, RtcDateTime.minute, RtcDateTime.second) - (8 * 3600);
return time_stamp;
}
void Seconds2DateTime(uint32_t seconds, TsRtcDateTime *pDateTime)
{
uint16_t daycnt = 0;
uint32_t timecount = 0;
uint32_t temp = 0;
uint16_t temp1 = 0;
timecount = seconds;
temp = timecount / 86400;
if (daycnt != temp)
{
daycnt = temp;
temp1 = 1970;
while (temp >= 365)
{
if (Is_LeapYear(temp1))
{
if (temp >= 366)
temp -= 366;
else
{
temp1++;
break;
}
}
else
temp -= 365;
temp1++;
}
pDateTime->year = temp1;
temp1 = 0;
while (temp >= 28)
{
if (Is_LeapYear(pDateTime->year) && temp1 == 1)
{
if (temp >= 29)
temp -= 29;
else
break;
}
else
{
if (temp >= month_table[temp1])
temp -= month_table[temp1];
else
break;
}
temp1++;
}
pDateTime->month = temp1 + 1;
pDateTime->day = temp + 1;
}
temp = timecount % 86400;
pDateTime->hour = temp / 3600;
pDateTime->minute = (temp % 3600) / 60;
pDateTime->second = (temp % 3600) % 60;
pDateTime->week = RTC_GetWeek(pDateTime->year, pDateTime->month, pDateTime->day);
}
/**
* @description: ,
* @note 197011,
* : 1970 ~ 2105
HAL默认为年份起点为2000年
* @param {uint16_t} syear
* @param {uint8_t} smon
* @param {uint8_t} sday
* @param {uint8_t} hour
* @param {uint8_t} min
* @param {uint8_t} sec
* @return {*}
*/
void RTC_SetTime(rt_uint16_t syear, rt_uint8_t smon, rt_uint8_t sday, rt_uint8_t hour, rt_uint8_t min, rt_uint8_t sec)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC_SetCounter(DateTime2Seconds(syear, smon, sday, hour, min, sec));
RTC_WaitForLastTask();
}
// refresh RtcDateTime
/**
* @description: , RtcDateTime结构体里面
* @return {*}
*/
void RTC_GetTime(void)
{
uint16_t daycnt = 0;
uint32_t timecount = 0;
uint32_t temp = 0;
uint16_t temp1 = 0;
timecount = RTC_GetCounter();
temp = timecount / 86400;
if (daycnt != temp)
{
daycnt = temp;
temp1 = 1970;
while (temp >= 365)
{
if (Is_LeapYear(temp1))
{
if (temp >= 366)
temp -= 366;
else
{
temp1++;
break;
}
}
else
temp -= 365;
temp1++;
}
RtcDateTime.year = temp1;
temp1 = 0;
while (temp >= 28)
{
if (Is_LeapYear(RtcDateTime.year) && temp1 == 1)
{
if (temp >= 29)
temp -= 29;
else
break;
}
else
{
if (temp >= month_table[temp1])
temp -= month_table[temp1];
else
break;
}
temp1++;
}
RtcDateTime.month = temp1 + 1;
RtcDateTime.day = temp + 1;
}
temp = timecount % 86400;
RtcDateTime.hour = temp / 3600;
RtcDateTime.minute = (temp % 3600) / 60;
RtcDateTime.second = (temp % 3600) % 60;
RtcDateTime.week = RTC_GetWeek(RtcDateTime.year, RtcDateTime.month, RtcDateTime.day);
}
static void RTC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; // RTC全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 先占优先级1位,从优先级3位
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 6; // 先占优先级0位,从优先级4位
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能该通道中断
NVIC_Init(&NVIC_InitStructure); // 根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
static uint8_t RTC_FirstInit(void)
{
uint8_t temp = 0;
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET && temp < 250)
{
temp++;
rt_thread_mdelay(5);
}
if (temp >= 250)
{
LOG_E("RTC_FirstInit: LSE not ready");
return 1;
}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForLastTask();
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
2025-01-09 15:29:36 +08:00
RTC_SetTime(2025, 1, 8, 12, 0, 0); //设置出厂日期
RTC_WaitForLastTask();
2024-12-30 11:50:48 +08:00
//
// RTC_SetAlarm(20 + RTC_GetCounter()); //闹钟值设定为当前时间的10秒后
// RTC_WaitForLastTask();
//
// RTC_ExitConfigMode(); //退出配置模式
// RTC_ITConfig(RTC_IT_ALR, ENABLE);
// RTC_ITConfig(RTC_IT_SEC, ENABLE);
// RTC_WaitForLastTask();
/* Is it the first configuration */
BKP_WriteBackupRegister(BKP_DR1, RTC_FIRST_INIT_VALUE);
TuFlashProductTimeLimitFrame LimitTime;
if (Flash_GetProductTimeLimit(&LimitTime, kFactoryTimeId) == READY)
{
RTC_SetTime(LimitTime.Struct.year, LimitTime.Struct.month, LimitTime.Struct.day,
LimitTime.Struct.hour, LimitTime.Struct.minute, 0); /* Setup Time */
LOG_D("RTC_SetTime:%04d-%02d-%02d,%02d:%02d",
LimitTime.Struct.year, LimitTime.Struct.month, LimitTime.Struct.day,
LimitTime.Struct.hour, LimitTime.Struct.minute);
}
return 0;
}
int BSP_RTC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
LOG_D("RCC_GetFlagStatus(RCC_FLAG_LSERDY): %d", RCC_GetFlagStatus(RCC_FLAG_LSERDY));
/* Is it the first configuration */
if (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET || BKP_ReadBackupRegister(BKP_DR1) != RTC_FIRST_INIT_VALUE)
{
RTC_FirstInit();
}
else
{
// 上电/掉电复位标志
if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
{
LOG_D("上电复位");
}
// 软件复位
if (RCC_GetFlagStatus(RCC_FLAG_SFTRST) != RESET)
{
LOG_D("软件复位");
}
// 独立看门狗复位
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
{
LOG_D("独立看门狗复位");
}
// 窗口看门狗复位
if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET)
{
LOG_D("窗口看门狗复位");
}
// 低功耗复位
if (RCC_GetFlagStatus(RCC_FLAG_LPWRRST) != RESET)
{
LOG_D("低功耗复位");
}
// 虽然RTC模块不需要重新配置且掉电后依靠后备电池依然运行
// 但是每次上电后还是要使能RTCCLK
RCC_RTCCLKCmd(ENABLE); // 使能RTCCLK
RTC_WaitForLastTask();
RTC_WaitForSynchro(); // 等待RTC时钟与APB1时钟同步
// RTC_ITConfig(RTC_IT_ALR, ENABLE);
// RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
}
RTC_NVIC_Config();
RTC_GetTime();
LOG_D("%4d-%02d-%02d, %02d:%02d:%02d", RtcDateTime.year, RtcDateTime.month, RtcDateTime.day,
RtcDateTime.hour, RtcDateTime.minute, RtcDateTime.second);
LOG_I("BSP_RTC_Init!");
return 0;
}
// INIT_PREV_EXPORT(BSP_RTC_Init);
#if 1
void RTC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void RTC_IRQHandler(void)
{
GET_INT_SP();
/* enter interrupt */
rt_interrupt_enter();
if (RTC_GetITStatus(RTC_IT_SEC) != RESET) // 秒钟中断
{
RTC_ClearITPendingBit(RTC_IT_SEC | RTC_IT_OW); // 清秒中断
RTC_GetTime(); // 更新时间
LOG_D("%4d-%02d-%02d, %02d:%02d:%02d", RtcDateTime.year, RtcDateTime.month, RtcDateTime.day,
RtcDateTime.hour, RtcDateTime.minute, RtcDateTime.second);
}
// if (RTC_GetITStatus(RTC_IT_ALR) != RESET) // 闹钟中断
// {
// RTC_ClearITPendingBit(RTC_IT_ALR); // 清闹钟中断
// RTC_GetTime(); // 更新时间
// RTC_WaitForLastTask();
// }
rt_interrupt_leave();
FREE_INT_SP();
}
#endif
// 将时间戳转换为 TsRtcDateTime 结构体
void Timestamp_To_Rtc_DateTime(time_t timestamp, TsRtcDateTime *rtc_dt)
{
struct tm *tm_info;
time_t local_timestamp = timestamp + 8 * 3600; // 北京时间比UTC时间快8小时
tm_info = localtime(&local_timestamp);
if (tm_info != NULL)
{
rtc_dt->year = tm_info->tm_year + 1900;
rtc_dt->month = tm_info->tm_mon + 1;
rtc_dt->day = tm_info->tm_mday;
rtc_dt->hour = tm_info->tm_hour;
rtc_dt->minute = tm_info->tm_min;
rtc_dt->second = tm_info->tm_sec;
rtc_dt->week = RTC_GetWeek(rtc_dt->year, rtc_dt->month, rtc_dt->day);
// rtc_dt->week = tm_info->tm_wday + 1; // tm_wday 的范围是0-6对应星期日到星期六
}
else
{
// 处理时间转换失败的情况
rtc_dt->year = 0;
rtc_dt->month = 0;
rtc_dt->day = 0;
rtc_dt->hour = 0;
rtc_dt->minute = 0;
rtc_dt->second = 0;
rtc_dt->week = 0;
}
}
#ifdef TEST_ENABLE
void RTC_ShowTime(void)
2024-12-30 11:50:48 +08:00
{
RTC_GetTime();
LOG_I("RTC Timer : %04d-%02d-%02d %02d:%02d:%02d week[%d]", RtcDateTime.year, RtcDateTime.month, RtcDateTime.day,
2024-12-30 11:50:48 +08:00
RtcDateTime.hour, RtcDateTime.minute, RtcDateTime.second, RtcDateTime.week);
}
MSH_CMD_EXPORT(RTC_ShowTime, "get rtc timer");
static void RTC_Cfg_Time(int argc, char **argv)
{
if (argc == 7)
{
/*年 月 日 时 分 秒*/
RTC_SetTime((rt_uint16_t)(atoi(argv[1])), (rt_uint8_t)(atoi(argv[2])), (rt_uint8_t)(atoi(argv[3])),
(rt_uint8_t)(atoi(argv[4])), (rt_uint8_t)(atoi(argv[5])), (rt_uint8_t)(atoi(argv[6])));
RTC_ShowTime();
}
else
{
LOG_E("RTC_Cfg_Time --use [y m d h m s]");
}
}
MSH_CMD_EXPORT(RTC_Cfg_Time, "y m d h m s");
void RTC_Control(int argc, char **argv)
{
if (argc == 2)
{
int flag = atoi(argv[1]);
if (flag == 0)
{
RTC_ITConfig(RTC_IT_SEC, DISABLE);
RTC_WaitForLastTask();
}
else if (flag == 1)
{
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
}
else if (flag == 2)
{
RTC_GetTime();
LOG_D("%4d-%02d-%02d, week:%d, %02d:%02d:%02d", RtcDateTime.year, RtcDateTime.month, RtcDateTime.day,
RtcDateTime.week, RtcDateTime.hour, RtcDateTime.minute, RtcDateTime.second);
}
}
else
{
LOG_E("Show rtc time --use _cmd_ [0:关IT/1:开IT/2:show rtc time(once)]");
}
}
MSH_CMD_EXPORT(RTC_Control, "0, 1(1s)show time: 2-show time once");
#endif // TSET_BSP_RTC