ShipCentralControl/Anjiehui7_DTU/User/rtc_wakeup.c

387 lines
9.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "includes.h"
#include "drv_dtu.h"
#include "drv_gps.h"
extern RTC_HandleTypeDef hrtc;
// 实际启动时间和INITIAL_YEAR相差的秒数当GPS定位或GPRS连接基站以后设置
volatile uint32_t RTC_offsetSeconds = 0;
// 获取日期时间输出格式为Nuvoton芯片格式
void RTC_GetDateAndTime(S_RTC_TIME_DATA_T *sRTC)
{
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
sRTC->u32Year = sDate.Year + RTC_YEAR2000;
sRTC->u32Month = sDate.Month;
sRTC->u32Day = sDate.Date;
if(sDate.WeekDay == RTC_WEEKDAY_SUNDAY)
sRTC->u32DayOfWeek = 0;
else
sRTC->u32DayOfWeek = sDate.WeekDay;
sRTC->u32Hour = sTime.Hours;
sRTC->u32Minute = sTime.Minutes;
sRTC->u32Second = sTime.Seconds;
sRTC->u32TimeScale = RTC_CLOCK_24;
}
// 设置日期时间输入格式为Nuvoton芯片格式
void RTC_SetDateAndTime(S_RTC_TIME_DATA_T *sRTC)
{
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
sDate.Year = sRTC->u32Year - RTC_YEAR2000;
sDate.Month = sRTC->u32Month;
sDate.Date = sRTC->u32Day;
if(sRTC->u32DayOfWeek == RTC_SUNDAY)
sDate.WeekDay = RTC_WEEKDAY_SUNDAY;
else
sDate.WeekDay = sRTC->u32DayOfWeek;
sTime.Hours = sRTC->u32Hour;
sTime.Minutes = sRTC->u32Minute;
sTime.Seconds = sRTC->u32Second;
sTime.SubSeconds = 0;
sTime.TimeFormat = RTC_HOURFORMAT_24;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
}
void RTC_SetAlarmDateAndTime(S_RTC_TIME_DATA_T *sRTC)
{
uint8_t try_count = 3;
RTC_AlarmTypeDef sAlarm = {0};
sAlarm.AlarmTime.Hours = sRTC->u32Hour;
sAlarm.AlarmTime.Minutes = sRTC->u32Minute;
sAlarm.AlarmTime.Seconds = sRTC->u32Second;
sAlarm.AlarmTime.SubSeconds = 0;
sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT_24;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = sRTC->u32Day;
sAlarm.Alarm = RTC_ALARM_A;
while(try_count--)
{
if(HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) == HAL_OK)
break;
delay_ms(10);
}
}
void RTC_SetAlarmDateAndTime_B(S_RTC_TIME_DATA_T *sRTC)
{
uint8_t try_count = 3;
RTC_AlarmTypeDef sAlarm = {0};
sAlarm.AlarmTime.Hours = sRTC->u32Hour;
sAlarm.AlarmTime.Minutes = sRTC->u32Minute;
sAlarm.AlarmTime.Seconds = sRTC->u32Second;
sAlarm.AlarmTime.SubSeconds = 0;
sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT_24;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = sRTC->u32Day;
sAlarm.Alarm = RTC_ALARM_B;
while(try_count--)
{
if(HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) == HAL_OK)
break;
delay_ms(10);
}
}
void Wakeup_ShowTime(char *preStr, S_RTC_TIME_DATA_T *pRTC)
{
S_RTC_TIME_DATA_T sRTC;
uint32_t totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, pRTC->u32Year, pRTC->u32Month, pRTC->u32Day,
pRTC->u32Hour, pRTC->u32Minute, pRTC->u32Second);
totalSeconds += RTC_offsetSeconds;
Wakeup_CalcUTCTime(totalSeconds, &sRTC);
printf("\n%s%04d-%02d-%02d %02d:%02d:%02d\n", preStr, sRTC.u32Year, sRTC.u32Month,
sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
}
// 判断是否闰年
uint8_t IsLeapYear(uint16_t year)
{
if(year % 4)
return 0;
if(year % 100 == 0 && year % 400)
return 0;
return 1;
}
// 计算从某年开始以来经过的秒数
uint32_t Calc_SecondsFromYear(uint16_t startYear, uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec)
{
uint32_t totalSeconds = 0ul;
uint16_t i;
// 计算整年的
for(i = startYear; i < year; i++)
{
totalSeconds += 31536000ul; // 365 * 86400
if(IsLeapYear(i)) // 闰年+1天
totalSeconds += 86400ul;
}
// 计算整月的
for(i = 1; i < mon; i++)
{
totalSeconds += 2678400ul; // 31 * 86400
if(i == 4 || i == 6 || i == 9 || i == 11)
totalSeconds -= 86400ul;
else if(i == 2)
{
totalSeconds -= 259200ul; // 3 * 86400
if(IsLeapYear(year)) // 闰年+1天
totalSeconds += 86400ul;
}
}
// 计算整天的
totalSeconds += (day - 1) * 86400ul;
// 计算时分秒的
totalSeconds += hour * 3600ul;
totalSeconds += min * 60ul;
totalSeconds += sec;
return totalSeconds;
}
uint16_t get_year_days(uint16_t year)
{
if(IsLeapYear(year))
return 366;
return 365;
}
uint16_t get_month_days(uint16_t year, uint8_t month)
{
if(month == 4 || month == 6 || month == 9 || month == 11)
return 30;
if(month == 2)
{
if(IsLeapYear(year))
return 29;
return 28;
}
return 31;
}
// 将从INITIAL_YEAR开始的描述转换成年月日
void Wakeup_CalcUTCTime(uint32_t totalSeconds, S_RTC_TIME_DATA_T *pRTC)
{
uint32_t totalDays, days;
// 计算下次唤醒的年、月、日
pRTC->u32Year = INITIAL_YEAR;
pRTC->u32Month = 1;
pRTC->u32Day = 1;
totalDays = totalSeconds / 86400ul;
while(totalDays >= 1)
{
// 计算整年的
days = get_year_days(pRTC->u32Year);
if(totalDays >= days)
{
pRTC->u32Year++;
totalDays -= days;
continue;
}
// 计算整月的
days = get_month_days(pRTC->u32Year, pRTC->u32Month);
if(totalDays >= days)
{
pRTC->u32Month++;
totalDays -= days;
continue;
}
// 计算整天
pRTC->u32Day += totalDays;
break;
}
// 计算下次唤醒的时、分、秒
totalSeconds %= 86400ul;
pRTC->u32Hour = totalSeconds / 3600ul;
totalSeconds %= 3600;
pRTC->u32Minute = totalSeconds / 60ul;
totalSeconds %= 60ul;
pRTC->u32Second = totalSeconds;
}
// 计算下次唤醒的时间
void Wakeup_CalcWakeupTime(S_RTC_TIME_DATA_T *pRTC)
{
uint32_t period = 300; //dcBuff.configData.intervalSample;
// 先计算从初始时间以来的秒数
uint32_t totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, pRTC->u32Year, pRTC->u32Month, pRTC->u32Day,
pRTC->u32Hour, pRTC->u32Minute, pRTC->u32Second);
printf("dcBuff.configData.intervalSample = %d, period = %d\n", dcBuff.configData.intervalSample, period);
// 计算下次唤醒时间的秒数
// 将这个秒数对齐到唤醒周期的倍数
// 这是因为:每次复位以后虽然时间是继续的,但闹钟需要重新设置
uint32_t sec = totalSeconds + period;
sec -= sec % period;
// 防止闹钟时间太近
if(sec <= totalSeconds + 2)
totalSeconds = sec + period;
else
totalSeconds = sec;
// 计算下次唤醒的年、月、日
Wakeup_CalcUTCTime(totalSeconds, pRTC);
}
// 计算下次唤醒的时间
void Wakeup_CalcWakeupTime_B(S_RTC_TIME_DATA_T *pRTC)
{
// 先计算从初始时间以来的秒数
uint32_t totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, pRTC->u32Year, pRTC->u32Month, pRTC->u32Day,
pRTC->u32Hour, pRTC->u32Minute, pRTC->u32Second);
// 计算下次唤醒时间的秒数
totalSeconds += 15;
// 计算下次唤醒的年、月、日
Wakeup_CalcUTCTime(totalSeconds, pRTC);
}
// 设定下次闹钟唤醒时间
void Wakeup_SetAlarm()
{
S_RTC_TIME_DATA_T sRTC;
// 设定下次闹钟唤醒时间
RTC_GetDateAndTime(&sRTC);
// 显示当前时间
Wakeup_ShowTime("RTC time is: ", &sRTC);
Wakeup_CalcWakeupTime(&sRTC);
RTC_SetAlarmDateAndTime(&sRTC);
// 显示唤醒时间
Wakeup_ShowTime("***********************************************\nWakeup time is: ", &sRTC);
}
// 设定下次闹钟唤醒时间
void Wakeup_SetAlarm_B()
{
S_RTC_TIME_DATA_T sRTC;
// 设定下次闹钟唤醒时间
RTC_GetDateAndTime(&sRTC);
Wakeup_CalcWakeupTime_B(&sRTC);
RTC_SetAlarmDateAndTime_B(&sRTC);
}
/**
* @brief Alarm A callback.
* @param hrtc RTC handle
* @retval None
*/
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
BaseType_t xHigherPriorityTaskWoken;
S_RTC_TIME_DATA_T sRTC;
static uint32_t upgSeconds = 0;
uint32_t totalSeconds;
// 获取当前时间
RTC_GetDateAndTime(&sRTC);
// 计算自上次查询固件升级以来的时间
totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
// 如果超过2个小时未发送成功复位
if(totalSeconds >= DTU_succTime + 7200)
NVIC_SystemReset();
// 每隔20分钟查询一次是否固件升级(3秒的容错
if(totalSeconds + 3 >= upgSeconds + 300)
{
// 重新计时
upgSeconds = totalSeconds;
// 触发固件升级任务
xSemaphoreGiveFromISR(DTU_semUpgrade, &xHigherPriorityTaskWoken);
}
// 设定下次闹钟唤醒时间
Wakeup_CalcWakeupTime(&sRTC);
Wakeup_SetAlarm();
}
/**
* @brief Alarm B callback.
* @param hrtc RTC handle
* @retval None
*/
void HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *hrtc)
{
DTU_CheckSleep();
}
void Wakeup_InitializeTime(S_RTC_TIME_DATA_T *pRTC)
{
pRTC->u32Year = INITIAL_YEAR;
pRTC->u32Month = 1;
pRTC->u32Day = 1;
pRTC->u32DayOfWeek = RTC_WEEKDAY_FRIDAY;
pRTC->u32Hour = 0;
pRTC->u32Minute = 0;
pRTC->u32Second = 0;
pRTC->u32TimeScale = RTC_CLOCK_24;
}
void Wakeup_Open()
{
S_RTC_TIME_DATA_T sRTC;
/** Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
/* Set RTC date and time */
Wakeup_InitializeTime(&sRTC);
RTC_SetDateAndTime(&sRTC);
printf("\n*******************************\n");
printf("system reseted ...\n");
// 设定下次闹钟唤醒时间
Wakeup_SetAlarm();
}