| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- /*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-09-15 19813 the first version
- */
- /* 包含头文件 ----------------------------------------------------------------*/
- #include "bsp_rtc.h"
- #include "main.h"
- #include "wwdg.h"
- #define DBG_TAG "bsp_rtc"
- #define DBG_LVL DBG_LOG
- #include <rtdbg.h>
- #include "bsp_date.h"
- #include "loar.h"
- #include <easyflash.h>
- #define RTC_Alarm_Time_BCK RTC_BKP_DR0
- #define RTC_Alarm_RETRY RTC_BKP_DR2
- extern WWDG_HandleTypeDef hwwdg;
- extern uint8_t wwdg_state;
- extern RTC_HandleTypeDef hrtc;
- extern RTC_TimeTypeDef GetTime;
- struct rtc_time systmtime;
- extern int _EXFUN(getchar, (void));
- int Compensation_time; //补偿时间(单位秒) 减去每次开机的运行时间 以使上报数据维持在设定值
- uint8_t Time_Correced = 0; //标记时间是否已补偿
- /**
- * 函数功能: 从串口调试助手获取数字值(把ASCII码转换为数字)
- * 输入参数: value 用户在超级终端中输入的数值
- * 返 回 值: 输入字符的ASCII码对应的数值
- * 说 明:本函数专用于RTC获取时间,若进行其它输入应用,要修改一下
- */
- // uint8_t USART_Scanf(uint32_t value)
- //{
- // uint32_t index = 0;
- // uint32_t tmp[2] = {0, 0};
- // while (index < 2)
- // {
- // /* 等待直到串口接收到数据 */
- // tmp[index++] = getchar();
- // if ((tmp[index - 1] < 0x30) || (tmp[index - 1] > 0x39)) /*数字0到9的ASCII码为0x30至0x39*/
- // {
- // rt_kprintf("请输入 0 到 9 之间的数字 -->:\n");
- // index--;
- // }
- // }
- // /* 计算输入字符的ASCII码转换为数字*/
- // index = (tmp[1] - 0x30) + ((tmp[0] - 0x30) * 10);
- //
- // /* 检查数据有效性 */
- // if (index > value)
- // {
- // rt_kprintf("请输入 0 到 %d 之间的数字\n", value);
- // return 0xFF;
- // }
- // return index;
- // }
- RTC_DateTypeDef yTime; //年份
- RTC_TimeTypeDef nTime; //时 分 秒 时间
- RTC_AlarmTypeDef aTime; //闹钟定时
- extern uint8_t Wakeup_alarm;
- extern uint8_t RTC_Check;
- extern void Recode_e_code(uint8_t code , uint8_t para);
- extern void Trigger_report(uint8_t type);
- uint8_t RTC_Alarm_Flag = Zero;
- void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *nhrtc)
- {
- //从闹钟唤醒了 以此触发警戒线程
- // uint16_t RTC_Check_Tigger = 0x6400; //此值左移8位==100
- RTC_Alarm_Flag = One;
- rt_kprintf("--------- HAL_RTC_Alarm ----------\r\n");
- if (RTC_Check == Zero /*&& Node_Type != Monitor*/)
- {
- // rt_kprintf("--------- RTC forced reset ----------\r\n");
- // __HAL_RCC_PWR_CLK_ENABLE(); //使能电源时钟PWR
- // HAL_PWR_EnableBkUpAccess(); //取消备份区域写保护
- // HAL_RTCEx_BKUPWrite(&hrtc, RTC_Alarm_RETRY, RTC_Check_Tigger);
- // HAL_PWR_DisableBkUpAccess(); //开启备份区域写保护
- //
- // Recode_e_code(11 , 1);
- //
- // RESET_MCU();
- Trigger_report(1);
- }
- }
- //获取当前时间戳——加上需要定时的时间(单位秒)——定时闹钟的时间戳转换为rtc_time结构体格式——给RTC_AlarmTypeDef结构体变量赋值时分秒——写入闹钟寄存器
- //进入待机模式,输入参数单位为分钟,范围0-1000
- extern RTC_TimeTypeDef GetTime; //获取时间结构体
- extern RTC_HandleTypeDef hrtc;
- extern void RESET_MCU(void);
- extern uint8_t RTC_Shotdown;
- extern uint16_t read_bcktime;
- extern void rt_hw_cpu_reset(void);
- extern LOAR_Parameter loar_par;
- extern Revise_par rev_par;
- extern uint8_t Double_INR;
- extern Trans_para Trans_p;
- uint8_t ReFlash_RTC(void);
- void Set_Alarm_A_Wakeup(uint16_t standbytime)
- {
- uint32_t TimeVar;
- struct rtc_time alarmtime;
- uint16_t backup_time = 0;
- uint8_t count = 0, Correction_time = 0, i = 0; //提前整点时刻开机的修正参数 Compensation_time 单位秒
- rt_thread_mdelay(10);
- ReFlash_RTC();
- if (Double_INR)
- {
- sys_info.interval *= 2;
- }
- /*
- *
- * 此处加上整点上报的控制逻辑
- *
- * */
- Compensation_time += sys_info.Sensor_num * 9; // 为传感器的读取预留时间
- Compensation_time += 15; // 4G版提前开机所需固定时间
- if(Node_Type == LTE)
- {
- LOG_I("This time took %d sec", Compensation_time);
- }
- if(Trans_p.en == One && Node_Type == LTE) //保护模式 间隔改为2小时
- {
- standbytime = 120;
- LOG_W("Trans_p > INR = 120");
- }
- if (standbytime != 60 && Trans_p.en != One) //若是保护模式 不再进行整点匹配
- {
- Correction_time = GetTime.Minutes;
- Correction_time++;
- for (i = 0; i <= sys_info.interval; i++) //使用for循环 寻找匹配的时间点
- {
- Correction_time++;
- if (Correction_time % sys_info.interval == 0) //判断是否整除时间间隔
- {
- if ((Correction_time - (Compensation_time / 60 + 1)) <= GetTime.Minutes) //校验当前时间是否已晚于设定开机时间
- {
- Correction_time += sys_info.interval;
- }
- if (Correction_time % 30 == 0)
- {
- Correction_time += 1;
- }
- if (Correction_time >= 0 && Correction_time < 120) //判定区间
- {
- if (Correction_time < 60) //分情况处理
- {
- GetTime.Minutes = Correction_time;
- }
- else
- {
- GetTime.Minutes = Correction_time % 60;
- GetTime.Hours = (GetTime.Hours + 1) % 24;
- }
- GetTime.Seconds = 0;
- Time_Correced = 1;
- // LOG_I("time corr succ %d:%d", GetTime.Hours, GetTime.Minutes);
- break;
- }
- else
- {
- // LOG_W("Out of range!");
- break;
- }
- }
- if (count < sys_info.interval)
- {
- count++;
- }
- else
- {
- LOG_W("corr ×");
- count = 0;
- Time_Correced = 0;
- break;
- }
- }
- }
- /*
- *
- * 此处加上整点上报的控制逻辑
- *
- * */
- TimeVar = GetTime.Seconds + GetTime.Minutes * 60 + GetTime.Hours * 3600;
- if (Time_Correced == 0)
- {
- TimeVar = TimeVar + standbytime * 60; //加上需要闹钟时间。
- }
- TimeVar = TimeVar + 24 * 3600 - Compensation_time; //在设定的时间中减去每次开机的运行时间·
- to_tm(TimeVar, &alarmtime); /*把时间戳转换为闹钟的时分秒*/
- if (RTC_Shotdown == One && RTC_Check != One) //如果本次被迫关机 不再根据interval重新计算
- {
- // LOG_W("bcktime %d" , read_bcktime);
- alarmtime.tm_hour = (int)read_bcktime / 360;
- alarmtime.tm_min = (int)(read_bcktime - alarmtime.tm_hour * 360) / 6;
- alarmtime.tm_sec = (int) (read_bcktime - alarmtime.tm_hour * 360 - alarmtime.tm_min * 6) * 10;
- }
- aTime.Alarm = RTC_ALARM_A;
- aTime.AlarmTime.Hours = alarmtime.tm_hour;
- aTime.AlarmTime.Minutes = alarmtime.tm_min;
- aTime.AlarmTime.Seconds = alarmtime.tm_sec;
- aTime.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
- aTime.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
- aTime.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
- aTime.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
- aTime.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
- if (HAL_RTC_SetAlarm_IT(&hrtc, &aTime, RTC_FORMAT_BIN) == HAL_OK)
- {
- if (wwdg_state == One) //初始化之后再喂
- HAL_WWDG_Refresh(&hwwdg); //喂狗也是每秒一次
- LOG_I("alarm-t :%d:%d:%d\n", aTime.AlarmTime.Hours, aTime.AlarmTime.Minutes, aTime.AlarmTime.Seconds);
- /******************
- *
- *
- * 使用一个uint16_t 存放当前时刻总秒数/10
- *
- */
- backup_time = aTime.AlarmTime.Hours * 360 + aTime.AlarmTime.Minutes * 6 + aTime.AlarmTime.Seconds / 10;
- __HAL_RCC_PWR_CLK_ENABLE(); //使能电源时钟PWR
- HAL_PWR_EnableBkUpAccess(); //取消备份区域写保护
- HAL_RTCEx_BKUPWrite(&hrtc, RTC_Alarm_Time_BCK, backup_time); //此处减去5秒 为boot loader留下时间
- HAL_PWR_DisableBkUpAccess(); //开启备份区域写保护
- LOG_I("BCK_T %d\n", backup_time);
- }
- HAL_RTCEx_BKUPWrite(&hrtc, RTC_Alarm_Time_BCK, 0);
- }
- extern SPI_HandleTypeDef hspiflash;
- extern void SPI_Flash_PowerDown(void);
- extern void Enadble_module(uint8_t en);
- extern void rt_hw_cpu_reset(void);
- extern uint8_t Valve_Mode;
- int inter_standby(uint16_t standbytime)
- {
- if (standbytime > 1000)
- return -1;
- if (standbytime == 0)
- return -1;
- if (wwdg_state == One) //初始化之后再喂
- HAL_WWDG_Refresh(&hwwdg); //喂狗也是每秒一次
- //将当前的定时值转化为参数 设置到Alarm_A中
- Set_Alarm_A_Wakeup(standbytime);//就是将形参 保存到RTC的备份寄存器0中
- if (wwdg_state == One) //初始化之后再喂
- HAL_WWDG_Refresh(&hwwdg); //喂狗也是每秒一次
- #if 1 //关闭休眠唤醒
- //mode1
- // LOG_I("check wake up\r\n");
- if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET) //检查并检查系统是否从待机模式恢复
- {//单片机刚刚从待机模式唤醒
- /* Clear Standby flag */
- __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
- }
- rt_thread_mdelay(10);
- // PWR_WAKEUP_PIN2 唤醒引脚无用
- HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN2); //禁用所有使用的唤醒源
- HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN6);
- __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF); //清除所有相关的唤醒标志
- /**************************** 各种关闭耗电源 *********************************/
- Enadble_module(0); //去使能各个组件
- wwdg_state = Zero;//看门狗
- rt_kprintf("--------------- All sleep ----------------\n");
- __HAL_RCC_APB2_FORCE_RESET(); //复位所有IO口
- __HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
- /**************************** 各种关闭耗电源 *********************************/
- if (Valve_Mode == 1)
- {
- HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2); //启用连接到WakeUp Pin2 PC13
- }
- HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN6); //启用连接到WakeUp Pin6 PB5
- ///
- ///
- /// 现已证实,连接到PWR_WAKEUP_PIN1 必须保持该IO保持低电平
- /// 设置低电平 然后浮空也不行 必须加入弱下拉(目前是100K到GND)
- /// 没有下拉会导致 进入休眠后立即唤醒 还有就是功耗增加
- ///
- ///
- /*
- *
- *
- * 实测当前各区域耗能比例
- *
- * 单片机 standby 模式 1.6uA 该部分调试主要是设置了standby和关闭所有io
- * XC62FP 静态模式占用 <2uA 从662K换成了XC62FP 进来电流低至2uA
- * falsh 断电 0uA 休眠时flash地线将IO配置成高阻断电
- * lora 低功耗模式 2uA 使用AT+EL=0000配置为长期休眠(波特率需要>9600)
- * TVS SMBJ6.8(C)A 0-5uA TVS 从3.3-4.2V,漏电流会随电压在0-5uA线性变化
- *
- *
- * 当前待机模式下整机功耗 4-12uA浮动
- * 去除TVS下 Loar版4-6uA LTE版3-5uA
- *
- */
- // 进入待机模式, 此时所有1.8V域的时钟都关闭,HIS和HSE的振荡器关闭, 电压调节器关闭.
- // 只有WKUP引脚上升沿,RTC警告事件,NRST引脚的外部复位,IWDG复位.
- HAL_PWR_EnterSTANDBYMode(); //进入待机模式 按道理立即进入休眠模式 类似断电
- //低功耗进入失败? 复位试试吧
- RESET_MCU();
- rt_hw_cpu_reset();
- rt_thread_mdelay(2000);
- #endif
- return 0;
- }
- // void run_standby(void)
- //{
- // inter_standby(2);
- // }
- //
- // MSH_CMD_EXPORT(run_standby, run_standby);
- /***************** 警戒线程 ********************/
- /*
- 不论终端进行任何操作
- 只要运行在低功耗模式且通过闹钟中断回调函数唤醒
- 3分钟后必然进入低功耗模式
- 确保终端出现问题时无法进入低功耗而耗尽电量下线
- */
- /***************** 警戒线程 ********************/
- extern void All_standby(uint16_t stime, uint8_t level);
- extern uint8_t Start_LTE;
- volatile uint8_t Expand_Guard_T = Zero; //扩容警戒线程时间
- char guard_head[] = "Guard:%d/%d\n";
- static void Guard_thread_entry(void *param)
- {
- static uint16_t count = 0; // while计数
- static uint16_t timeout = 0;
- static uint8_t ET_EN = 1; //1:允许扩容 0:扩容完成
- static uint8_t Add_Sen_Time = 1; // 加入一次要素延时
- //rt_thread_mdelay(200);
- if (wwdg_state == Zero)
- {
- MX_WWDG_Init(); //初始化看门狗
- wwdg_state = One;
- rt_kprintf("wwdg start\n");
- HAL_WWDG_Refresh(&hwwdg);
- }
- timeout = 1020; //加入了定位这个时间+60秒
- while (1) // Guard
- {
- if (wwdg_state == One)
- {
- HAL_WWDG_Refresh(&hwwdg);//喂狗
- }
- if(sys_info.Sensor_num <= MAX_SENSOR_NUM && sys_info.Sensor_num > 0) // 给读传感器留些时间 有传感器
- {
- if(Add_Sen_Time == 1)
- {
- timeout = timeout + (60 * sys_info.Sensor_num); //820 + 60*num
- Add_Sen_Time = 0;
- //rt_kprintf("Guard timeout: %d\n",timeout);
- }
- }
- if (sys_info.run_mode == Zero)//供电正常
- {
- count += 1; //
- if (count > timeout)
- {
- LOG_E("boot time ↓");
- Recode_e_code(20 , count/100);
- All_standby(sys_info.interval, 3);//满足条件进行1.关闭4G供电 2.保存参数3.立即休眠
- }
- }
- // 喂狗
- if (wwdg_state == One)
- {
- HAL_WWDG_Refresh(&hwwdg);
- }
- //打印信息
- if (count % 100 == 0 && count != 0 && count >= timeout / 2 /*&& Node_Type != Monitor*/)
- {
- if (count * 2 >= timeout * 3)
- LOG_W(guard_head, count, timeout);// 说明没正常进入休眠
- else
- LOG_I(guard_head, count, timeout);// count >= timeout / 2 and count是一百的倍数
- }
- rt_thread_mdelay(300); //每秒一次 让出CPU
- //喂狗
- if (wwdg_state == One)
- {
- HAL_WWDG_Refresh(&hwwdg);
- }
- if(Expand_Guard_T == One && ET_EN == 1)//也就第一次可能进入
- {
- ET_EN = 0;
- Expand_Guard_T = Zero;
- timeout += 6600;
- }
- }
- }
- //
- int Guard_thread(void)
- {
- rt_thread_t tid1 = RT_NULL;
- tid1 = rt_thread_create("Guard",
- Guard_thread_entry, RT_NULL,
- 1024,
- 6, 5); //给足优先级
- // 如果获得线程控制块,启动这个线程
- if (tid1 != RT_NULL)
- rt_thread_startup(tid1);
- return 1;
- }
- INIT_ENV_EXPORT(Guard_thread); //警戒线程 保证进入低功耗的最后一道防线
|