#include "includes.h" #include "drv_dtu.h" #include "drv_gps.h" RTC_HandleTypeDef hrtc; // 当前工作模式 uint8_t Wakeup_workMode = WORK_MODE_NORMAL; // 电量极低标志 uint8_t bat_veryLow = 0; // 休眠标识 volatile uint8_t Wakeup_Sleeping = 0; // 是否睡眠模式 volatile uint8_t Wakeup_SleepMode = 0; // 实际启动时间和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, uint8_t charging) { uint32_t period = 300; // 先计算从初始时间以来的秒数 uint32_t totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, pRTC->u32Year, pRTC->u32Month, pRTC->u32Day, pRTC->u32Hour, pRTC->u32Minute, pRTC->u32Second); if(dcBuff.configData.intervalTrans > 0 && period > dcBuff.configData.intervalTrans) period = dcBuff.configData.intervalTrans; if(dcBuff.configData.intervalSample > 0 && period > dcBuff.configData.intervalSample) period = dcBuff.configData.intervalSample; // 无外供电,采集频率不能快于1分钟 if((!VCC_POWER_STATUS() || (dcBuff.configDisplay.op_USE_SOLAR && dcBuff.dtuData.batVoltage <= 4500)) && period < 60) period = 60; if(dcBuff.configDisplay.op_ANTI_OVERFILL && Charge_Enabled && period > 10) period = 10; if(Manual_Charing && period > 10) period = 10; if(charging && period > 60) period = 60; if(dcBuff.configDisplay.op_ANTI_NORM_OPEN && Anti_Enabled && charging && period > 10) period = 10; // 计算下次唤醒时间的秒数 // 将这个秒数对齐到唤醒周期的倍数 // 这是因为:每次复位以后虽然时间是继续的,但闹钟需要重新设置 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(uint8_t charging) { S_RTC_TIME_DATA_T sRTC; // 设定下次闹钟唤醒时间 RTC_GetDateAndTime(&sRTC); // 显示当前时间 Wakeup_ShowTime("RTC time is: ", &sRTC); Wakeup_CalcWakeupTime(&sRTC, charging); 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) { S_RTC_TIME_DATA_T sRTC; static uint32_t gpsSeconds = 0; uint32_t totalSeconds; if(Wakeup_Sleeping) { SysTick->CTRL |= (SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk); delay_ms(10); Vcc_Enable(); delay_ms(40); printf("\n\nWake up by RTC.\n\n"); } // 获取当前时间 RTC_GetDateAndTime(&sRTC); // 计算自上次gps定位以来的时间 totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second); // 如果超过6个发送周期(最小2小时,最大1天)未发送成功,复位 if((totalSeconds >= DTU_succTime + 7200 && totalSeconds >= DTU_succTime + dcBuff.configData.intervalTrans * 6) || totalSeconds >= DTU_succTime + 86400) { if(!dcBuff.configDisplay.op_LOCAL_DISP) NVIC_SystemReset(); } // 每隔24小时定位一次(3秒的容错) if(totalSeconds + 3 >= gpsSeconds + 86400ul) { // 重新定位 GPS_Located = 0; GPS_Locate = 1; // 重新计时 gpsSeconds = totalSeconds; } if(Wakeup_Sleeping) DTU_semSync = 1; else DTU_semGPRS = 1; Wakeup_Sleeping = 0; // 设定下次闹钟唤醒时间 Wakeup_SetAlarm(dcBuff.sampleData.charging); } /** * @brief Alarm B callback. * @param hrtc RTC handle * @retval None */ void HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *hrtc) { DTU_CheckSleep(); } // 充电唤醒中断 void Vcc_Power_Handler(void) { // 控制电流输出开关 DAC7311_Open(); if(Wakeup_Sleeping) { SysTick->CTRL |= (SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk); delay_ms(10); Vcc_Enable(); delay_ms(40); Wakeup_Sleeping = 0; // 判断是否为低电平,排除干扰 if(!VCC_POWER_STATUS()) { printf("\nWakeup by DISTURB ...\n"); // 由干扰引起的中断,发信号休眠 return; } printf("\n\nWake up by POWER.\n\n"); // 采集数据 Sample_NotifyFromISR(); } // Modbus输出打开 VCC_RS485_ON(); } void Wakeup_Init() { LL_EXTI_InitTypeDef EXTI_InitStruct = {0}; // 充电唤醒引脚 LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); /**/ LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTE, LL_SYSCFG_EXTI_LINE7); /**/ EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_7; EXTI_InitStruct.Line_32_63 = LL_EXTI_LINE_NONE; EXTI_InitStruct.LineCommand = ENABLE; EXTI_InitStruct.Mode = LL_EXTI_MODE_IT; EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING; LL_EXTI_Init(&EXTI_InitStruct); /**/ LL_GPIO_SetPinPull(GPIOE, LL_GPIO_PIN_7, LL_GPIO_PULL_DOWN); /**/ LL_GPIO_SetPinMode(GPIOE, LL_GPIO_PIN_7, LL_GPIO_MODE_INPUT); } 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.OutPutRemap = RTC_OUTPUT_REMAP_NONE; 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(dcBuff.sampleData.charging); NVIC_SetPriority(EXTI9_5_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); NVIC_EnableIRQ(EXTI9_5_IRQn); if(VCC_POWER_STATUS()) { // Modbus输出打开 VCC_RS485_ON(); } } // 检查是否进入掉电模式 void Wakeup_Powerdown() { LL_EXTI_InitTypeDef EXTI_InitStruct = {0}; uint32_t curr_time; S_RTC_TIME_DATA_T sRTC; static uint8_t last_PowerStatus = 0; uint8_t powerStatus; #if 0 // 模拟充电和放电:每隔10分钟切换一次 if(dcBuff.configDisplay.op_SEND_GPS_DATA) { RTC_GetDateAndTime(&sRTC); curr_time = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second); powerStatus = (curr_time / 600 % 2 == 0); } else #endif { // 记录关电的时间 powerStatus = VCC_POWER_STATUS(); } if(last_PowerStatus != powerStatus && !powerStatus) { RTC_GetDateAndTime(&sRTC); Poweroff_time = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second); } last_PowerStatus = powerStatus; // 如果是槽车,且有外部供电,不休眠 if(powerStatus && dcBuff.configDisplay.op_SEND_GPS_DATA) return; // 定位未成功且未超时,不允许休眠 if(!dcBuff.configDisplay.op_SEND_GPS_DATA && Wakeup_GetWorkMode() == WORK_MODE_NORMAL && GPS_Waiting) return; // 采集任务未完成,不允许休眠 if(Sample_Busy() || Config_Vacuum_Request) return; // 槽车,刚断电的时候延迟20分钟再休眠 if(dcBuff.configDisplay.op_SEND_GPS_DATA) { // 正常模式的情况下,延迟休眠 if(!powerStatus && Wakeup_GetWorkMode() == WORK_MODE_NORMAL) { // 获取当前时间 RTC_GetDateAndTime(&sRTC); curr_time = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second); if(Poweroff_time > 0 && curr_time >= Poweroff_time && curr_time < Poweroff_time + 1200) // if(Poweroff_time > 0 && curr_time >= Poweroff_time && curr_time < Poweroff_time + 60) { if((curr_time - Poweroff_time) % 10 == 0) printf("\ndelay sleep time: %d\n", curr_time - Poweroff_time); return; } } } // 关闭DTU if(Wakeup_GetWorkMode() != WORK_MODE_NORMAL || LCD_Disabled) { if(dcBuff.dtuData.networked) DTU_Sleep(); else DTU_PowerOff(); } // 如果显示屏在操作,不休眠 if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL && !LCD_Disabled) return; // 如果防过充电磁阀处于动作状态,不休眠 if(dcBuff.configDisplay.op_ANTI_OVERFILL) { if((!dcBuff.configDisplay.op_ANTI_SINGLE_CTRL && IS_CHARGE_ENABLE_HIGH()) || IS_CHARGE_DISABLE_HIGH()) return; } // 如果常开电磁阀处于闭合状态,不休眠 if(dcBuff.configDisplay.op_ANTI_NORM_OPEN) { if(!IS_NORM_OPEN_ENABLED()) return; } // 如果声光报警且外供电,不休眠 if(dcBuff.configDisplay.op_ALARM_OUTPUT) { if(powerStatus) return; } // 有外部供电(且电池电压大于4.5v),不休眠 if(powerStatus && (!dcBuff.configDisplay.op_USE_SOLAR || dcBuff.dtuData.batVoltage > 4500)) return; // 如果RF未关闭,不休眠 if(IS_VCC_RF_ON()) return; // 如果是LNG-LORA版本,不休眠 if(dcBuff.configDisplay.op_LNG_LORA) return; // Modbus输出关闭 VCC_RS485_OFF(); // 禁止按键功能 NVIC_DisableIRQ(EXTI3_IRQn); NVIC_DisableIRQ(EXTI4_IRQn); NVIC_DisableIRQ(EXTI9_5_IRQn); // 非罐箱版,禁止加速度中断 if(!dcBuff.configDisplay.op_BOX_VER) { EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_10; EXTI_InitStruct.Line_32_63 = LL_EXTI_LINE_NONE; EXTI_InitStruct.LineCommand = DISABLE; EXTI_InitStruct.Mode = LL_EXTI_MODE_IT; EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING; LL_EXTI_Init(&EXTI_InitStruct); } printf("\nEnter to Power-Down ......\n"); // 防止休眠意外(不喂狗) Watchdog_Feed(); Wakeup_Sleeping = 1; VCC_SFLASH_FRAM_OFF(); Vcc_Disable(); // 允许按键唤醒,先清除中断标志 LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3); LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4); LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5); LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6); NVIC_EnableIRQ(EXTI3_IRQn); NVIC_EnableIRQ(EXTI4_IRQn); NVIC_EnableIRQ(EXTI9_5_IRQn); // 设置唤醒以后的时钟源 __HAL_RCC_PWR_CLK_ENABLE(); __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); // 禁止Systick,否则不能休眠 SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk); // Wakeup_Sleeping在唤醒中断里面清零(如果未清零则说明休眠失败) do { /* Enter STOP 2 mode */ HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); }while(Wakeup_Sleeping); // 罐箱或槽车版,允许加速度中断 if(dcBuff.configDisplay.op_BOX_VER || dcBuff.configDisplay.op_SEND_GPS_DATA) { // 读取运动状态 Accelero_ReadStatus(LL_GPIO_IsInputPinSet(GPIOD, LL_GPIO_PIN_10)); // 恢复加速度中断 EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_10; EXTI_InitStruct.Line_32_63 = LL_EXTI_LINE_NONE; EXTI_InitStruct.LineCommand = ENABLE; EXTI_InitStruct.Mode = LL_EXTI_MODE_IT; EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING; LL_EXTI_Init(&EXTI_InitStruct); } delay_ms(20); SFlash_UnlockBPR(); } // 立即进入休眠模式(库存模式:休眠、熄屏,只能通过按键唤醒) void Wakeup_SleepDown() { LL_EXTI_InitTypeDef EXTI_InitStruct = {0}; uint32_t curr_time; S_RTC_TIME_DATA_T sRTC; // 标记为休眠模式 Wakeup_SleepMode = 1; // 关闭显示屏 HT1621_ScreenOff(); // 关闭所有外部电源 VCC_GSM_OFF(); VCC_GPS_OFF(); VCC_RS485_OFF(); VCC_RF_OFF(); VCC_CC200A_OFF(); VCC_SENSOR_5V_OFF(); // 关闭电磁阀 KZ_CHARGE_ENABLE_LOW(); KZ_CHARGE_DISABLE_HIGH(); delay_ms(1000); KZ_CHARGE_DISABLE_LOW(); // 关闭报警输出 KZ_ALARM_OFF(); KZ_LOW_ALARM_OFF(); KZ_LOW_LEVEL_OFF(); KZ_LEVEL_OFF(); // 禁止RTC中断 HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A); HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_B); // 禁止加速度中断 EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_10; EXTI_InitStruct.Line_32_63 = LL_EXTI_LINE_NONE; EXTI_InitStruct.LineCommand = DISABLE; EXTI_InitStruct.Mode = LL_EXTI_MODE_IT; EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING; LL_EXTI_Init(&EXTI_InitStruct); // 禁止按键功能 NVIC_DisableIRQ(EXTI3_IRQn); NVIC_DisableIRQ(EXTI4_IRQn); NVIC_DisableIRQ(EXTI9_5_IRQn); printf("\nEnter to Sleep mode ......\n"); // 防止休眠意外(不喂狗) Watchdog_Feed(); VCC_SFLASH_FRAM_OFF(); Vcc_Disable(); // 允许按键唤醒,先清除中断标志 LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3); LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4); LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5); LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6); NVIC_EnableIRQ(EXTI3_IRQn); NVIC_EnableIRQ(EXTI4_IRQn); NVIC_EnableIRQ(EXTI9_5_IRQn); // 设置唤醒以后的时钟源 __HAL_RCC_PWR_CLK_ENABLE(); __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); // 禁止Systick,否则不能休眠 SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk); do { /* Enter STOP 2 mode */ HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); }while(Wakeup_SleepMode); } // 读取工作模式 uint8_t Wakeup_GetWorkMode() { return Wakeup_workMode; } // 设置工作模式 void Wakeup_SetWorkMode() { // 默认为正常工作模式 uint8_t mode = WORK_MODE_NORMAL; // 放电状态 if(!VCC_POWER_STATUS()) { // 进入电池保护模式 if(bat_veryLow) mode = WORK_MODE_PROTECT; // 进入充电提示模式 else if(dcBuff.dtuData.batLow) mode = WORK_MODE_CHARGE; } printf("\nchange work mode from %d to %d\n", Wakeup_workMode, mode); // 电池保护模式 if(mode == WORK_MODE_PROTECT) { // 关闭DTU和传感器供电 DTU_PowerOff(); // VCC_SENSOR_24V_OFF(); // 保存模式 Wakeup_workMode = mode; return; } // 解除电池保护模式 if(Wakeup_workMode == WORK_MODE_PROTECT) { } // 充电提示模式 if(mode == WORK_MODE_CHARGE) { // 关闭DTU和传感器供电 DTU_PowerOff(); // VCC_SENSOR_24V_OFF(); } else { // VCC_SENSOR_24V_ON(); } // 保存模式 Wakeup_workMode = mode; }