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

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

32
RTC.cpp
View File

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

27
Sys.cpp
View File

@ -432,6 +432,33 @@ bool TSys::SetTaskPeriod(uint taskid, int period)
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()
{
Started = true;

4
Sys.h
View File

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

View File

@ -59,13 +59,8 @@ WatchDog::~WatchDog()
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);
/* 检查系统是否从IWDG重置恢复 */
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
@ -75,6 +70,49 @@ bool WatchDog::Config(uint ms)
}
/* 打开IWDG_PR和IWDG_RLR寄存器的写访问 */
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;
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);
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计数器时钟周期
@ -125,13 +149,7 @@ bool WatchDog::Config(uint ms)
= ms * 40k / (mul * 1000)
= ms * 40 / mul
*/
IWDG_SetReload(ms * 40 / mul);
/* 重载 IWDG 计数器 */
IWDG_ReloadCounter();
/* 打开 IWDG (LSI将由硬件打开) */
IWDG_Enable();
SetWatchDog(pre, ms * 40 / mul);
Timeout = ms;
@ -140,13 +158,11 @@ bool WatchDog::Config(uint ms)
void WatchDog::ConfigMax()
{
/* 打开IWDG_PR和IWDG_RLR寄存器的写访问 */
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
OpenWatchDog();
// 独立看门狗无法关闭
IWDG_SetPrescaler(IWDG_Prescaler_256);
IWDG_SetReload(0x0FFF);
IWDG_ReloadCounter();
SetWatchDog(IWDG_Prescaler_256, 0x0FFF);
Timeout = 0x0FFF * 256 / 40;
}
void WatchDog::Feed()
@ -163,11 +179,16 @@ void FeedDogTask(void* param)
void WatchDog::Start(uint ms, uint msFeed)
{
static WatchDog dog;
dog.Config(ms);
static uint tid = 0;
// 减小一点,避免来不及喂狗
//int us = msFeed * 1000;
if(ms > 0x0FFF)
dog.ConfigMax();
else
dog.Config(ms);
debug_printf("WatchDog::Start ");
Sys.AddTask(FeedDogTask, &dog, msFeed, msFeed, "看门狗");
if(!tid && msFeed > 0 && msFeed <= 26000)
{
debug_printf("WatchDog::Start ");
tid = Sys.AddTask(FeedDogTask, &dog, msFeed, msFeed, "看门狗");
}
}