增加深度睡眠、停止、待机三种低功耗模式,借助看门狗唤醒

This commit is contained in:
nnhy 2015-11-06 08:19:55 +00:00
parent e560a40b15
commit e3c576d191
4 changed files with 109 additions and 51 deletions

26
RTC.cpp
View File

@ -284,27 +284,32 @@ int HardRTC::Sleep(int ms)
RTC_AlarmStructInit(&alr); RTC_AlarmStructInit(&alr);
int second = ms / 1000; int second = ms / 1000;
int minute = second / 60;
RTC_AlarmCmd( RTC_Alarm_A, DISABLE ); /* Disable the Alarm A */ // 关闭警报
RTC_AlarmCmd( RTC_Alarm_A, DISABLE );
alr.RTC_AlarmTime.RTC_H12 = RTC_H12_AM; alr.RTC_AlarmTime.RTC_H12 = RTC_H12_AM;
alr.RTC_AlarmTime.RTC_Hours = second / 60 / 60; alr.RTC_AlarmTime.RTC_Hours = minute / 60;
alr.RTC_AlarmTime.RTC_Minutes = (second / 60) % 60; alr.RTC_AlarmTime.RTC_Minutes = minute % 60;
alr.RTC_AlarmTime.RTC_Seconds = second % 60; alr.RTC_AlarmTime.RTC_Seconds = second % 60;
/* Set the Alarm A */ // 设置警报
alr.RTC_AlarmDateWeekDay = 0x31; alr.RTC_AlarmDateWeekDay = 31;
alr.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date; alr.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;
alr.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay; alr.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay;
RTC_SetAlarm( RTC_Format_BIN, RTC_Alarm_A, &alr ); /* Configure the RTC Alarm A register */ RTC_SetAlarm( RTC_Format_BIN, RTC_Alarm_A, &alr );
RTC_ITConfig( RTC_IT_ALRA, ENABLE ); /* Enable the RTC Alarm A Interrupt */ // 打开警报中断
RTC_ITConfig( RTC_IT_ALRA, ENABLE );
RTC_AlarmCmd( RTC_Alarm_A, ENABLE ); /* Enable the alarm A */ // 打开警报
RTC_AlarmCmd( RTC_Alarm_A, ENABLE );
#endif #endif
/* Wait until last write operation on RTC registers has finished */ // 等待写入操作完成
RTC_WaitForLastTask2(); RTC_WaitForLastTask2();
Sys.Trace(1);
// 进入低功耗模式 // 进入低功耗模式
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
@ -370,6 +375,7 @@ void AlarmHandler(ushort num, void* param)
{ {
SmartIRQ irq; SmartIRQ irq;
Sys.Trace(4);
HardRTC* rtc = (HardRTC*)param; HardRTC* rtc = (HardRTC*)param;
if(RTC_GetITStatus(RTC_IT_ALR) != RESET) if(RTC_GetITStatus(RTC_IT_ALR) != RESET)
@ -384,7 +390,7 @@ void AlarmHandler(ushort num, void* param)
SYSCLKConfig_STOP(); SYSCLKConfig_STOP();
rtc->LoadTicks(); rtc->LoadTicks();
//debug_printf("离开低功耗模式\r\n"); debug_printf("离开低功耗模式\r\n");
} }
HardRTC* HardRTC::Instance() HardRTC* HardRTC::Instance()

27
Sys.cpp
View File

@ -432,6 +432,33 @@ bool TSys::SetTaskPeriod(uint taskid, int period)
void TSys::Reset() { NVIC_SystemReset(); } void TSys::Reset() { NVIC_SystemReset(); }
#include "WatchDog.h"
void TSys::Stop(uint msTime)
{
debug_printf("TSys::Stop Time=%d \r\n", msTime);
if(!msTime) msTime = 0xFFFF;
WatchDog::Start(msTime);
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
}
void TSys::DeepSleep(uint msTime)
{
debug_printf("TSys::DeepSleep Time=%d \r\n", msTime);
PWR_EnterSleepMode(PWR_SLEEPEntry_WFI);
}
void TSys::Standby(uint msTime)
{
debug_printf("TSys::Standby Time=%d \r\n", msTime);
if(!msTime) msTime = 0xFFFF;
WatchDog::Start(msTime);
PWR_EnterSTANDBYMode();
}
void TSys::Start() void TSys::Start()
{ {
Started = true; Started = true;

4
Sys.h
View File

@ -121,6 +121,10 @@ public:
bool Started; bool Started;
void Start(); // 开始系统大循环 void Start(); // 开始系统大循环
void Stop(uint msTime = 0);
void DeepSleep(uint msTime = 0);
void Standby(uint msTime = 0);
}; };
extern TSys Sys; //创建一个全局的Sys对象 会在main函数之前执行构造函数 extern TSys Sys; //创建一个全局的Sys对象 会在main函数之前执行构造函数

View File

@ -59,13 +59,8 @@ WatchDog::~WatchDog()
ConfigMax(); ConfigMax();
} }
bool WatchDog::Config(uint ms) void OpenWatchDog()
{ {
if(ms == 0)
{
debug_printf("WatchDog msTimeout %dms must larger than 0ms\r\n", ms);
return false;
}
RCC_LSICmd(ENABLE); RCC_LSICmd(ENABLE);
/* 检查系统是否从IWDG重置恢复 */ /* 检查系统是否从IWDG重置恢复 */
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET) if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
@ -75,6 +70,49 @@ bool WatchDog::Config(uint ms)
} }
/* 打开IWDG_PR和IWDG_RLR寄存器的写访问 */ /* 打开IWDG_PR和IWDG_RLR寄存器的写访问 */
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
}
void SetWatchDog(byte pre, uint reload)
{
IWDG_SetPrescaler(pre);
/*if(ms < (0x0FFF * 32 / 40))
{
// IWDG计数器时钟: LSI/32=40KHz/32=1250Hz每周期0.8ms
IWDG_SetPrescaler(IWDG_Prescaler_32);
}
else
{
// IWDG计数器时钟: LSI/64=40KHz/64=625Hz每周期0.4ms
IWDG_SetPrescaler(IWDG_Prescaler_64);
// 直接除以2后面不用重复计算
ms >>= 2;
}*/
/* 设置计数器重载值为超时时间
Counter Reload Value = ms / 1000 / IWDG计数器时钟周期
= ms / 1000 / (1/(LSI/mul))
= ms * LSI / (mul * 1000)
= ms * 40k / (mul * 1000)
= ms * 40 / mul
*/
IWDG_SetReload(reload);
/* 重载 IWDG 计数器 */
IWDG_ReloadCounter();
/* 打开 IWDG (LSI将由硬件打开) */
IWDG_Enable();
}
bool WatchDog::Config(uint ms)
{
if(ms == 0)
{
debug_printf("WatchDog msTimeout %dms must larger than 0ms\r\n", ms);
return false;
}
OpenWatchDog();
byte pre = IWDG_Prescaler_4; byte pre = IWDG_Prescaler_4;
int mul = 4; int mul = 4;
@ -103,20 +141,6 @@ bool WatchDog::Config(uint ms)
debug_printf("WatchDog msTimeout must smaller than %dms\r\n", 0x0FFF * 256 / 40); debug_printf("WatchDog msTimeout must smaller than %dms\r\n", 0x0FFF * 256 / 40);
return false; return false;
} }
IWDG_SetPrescaler(pre);
/*if(ms < (0x0FFF * 32 / 40))
{
// IWDG计数器时钟: LSI/32=40KHz/32=1250Hz每周期0.8ms
IWDG_SetPrescaler(IWDG_Prescaler_32);
}
else
{
// IWDG计数器时钟: LSI/64=40KHz/64=625Hz每周期0.4ms
IWDG_SetPrescaler(IWDG_Prescaler_64);
// 直接除以2后面不用重复计算
ms >>= 2;
}*/
/* 设置计数器重载值为超时时间 /* 设置计数器重载值为超时时间
Counter Reload Value = ms / 1000 / IWDG计数器时钟周期 Counter Reload Value = ms / 1000 / IWDG计数器时钟周期
@ -125,13 +149,7 @@ bool WatchDog::Config(uint ms)
= ms * 40k / (mul * 1000) = ms * 40k / (mul * 1000)
= ms * 40 / mul = ms * 40 / mul
*/ */
IWDG_SetReload(ms * 40 / mul); SetWatchDog(pre, ms * 40 / mul);
/* 重载 IWDG 计数器 */
IWDG_ReloadCounter();
/* 打开 IWDG (LSI将由硬件打开) */
IWDG_Enable();
Timeout = ms; Timeout = ms;
@ -140,13 +158,11 @@ bool WatchDog::Config(uint ms)
void WatchDog::ConfigMax() void WatchDog::ConfigMax()
{ {
/* 打开IWDG_PR和IWDG_RLR寄存器的写访问 */ OpenWatchDog();
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
// 独立看门狗无法关闭 SetWatchDog(IWDG_Prescaler_256, 0x0FFF);
IWDG_SetPrescaler(IWDG_Prescaler_256);
IWDG_SetReload(0x0FFF); Timeout = 0x0FFF * 256 / 40;
IWDG_ReloadCounter();
} }
void WatchDog::Feed() void WatchDog::Feed()
@ -163,11 +179,16 @@ void FeedDogTask(void* param)
void WatchDog::Start(uint ms, uint msFeed) void WatchDog::Start(uint ms, uint msFeed)
{ {
static WatchDog dog; static WatchDog dog;
static uint tid = 0;
if(ms > 0x0FFF)
dog.ConfigMax();
else
dog.Config(ms); dog.Config(ms);
// 减小一点,避免来不及喂狗 if(!tid && msFeed > 0 && msFeed <= 26000)
//int us = msFeed * 1000; {
debug_printf("WatchDog::Start "); debug_printf("WatchDog::Start ");
Sys.AddTask(FeedDogTask, &dog, msFeed, msFeed, "看门狗"); tid = Sys.AddTask(FeedDogTask, &dog, msFeed, msFeed, "看门狗");
}
} }