在STM32開(kāi)發(fā)中經(jīng)常會(huì)用到獨(dú)立看門狗(IWDG)和低功耗模式,看門狗是為了檢測(cè)和解決由軟件錯(cuò)誤引起的故障,低功耗模式是為了在CPU不需要繼續(xù)運(yùn)行時(shí)進(jìn)入到休眠模式用以節(jié)省電能。其中獨(dú)立看門狗的時(shí)鐘由獨(dú)立的RC振蕩器(STM32F10x一般為40kHz)提供,即使在主時(shí)鐘出現(xiàn)故障時(shí),也仍然有效,因此可以在停止和待機(jī)模式下工作。而且獨(dú)立看門狗一旦啟動(dòng),除了系統(tǒng)復(fù)位,它不能再被停止。但這樣引發(fā)的一個(gè)問(wèn)題是當(dāng)MCU進(jìn)入到低功耗模式后由于CPU停止運(yùn)行無(wú)法喂狗,會(huì)導(dǎo)致系統(tǒng)頻繁復(fù)位。那如何解決這個(gè)問(wèn)題呢,難道獨(dú)立看門狗和低功耗模式?jīng)]法同時(shí)使用?
一個(gè)很好的方式是在休眠模式下通過(guò)RTC定時(shí)喚醒來(lái)喂狗,喂完夠在進(jìn)入繼續(xù)進(jìn)入到休眠模式。比如看門狗復(fù)位的時(shí)間間隔為10s。那么在進(jìn)入休眠模式前設(shè)置RTC鬧鐘中斷時(shí)間為5s。這樣每隔5s喚醒一次喂一次狗。便可以很好的解決這個(gè)問(wèn)題。
while(1)
{
// 執(zhí)行任務(wù)
Task1();
Task2();
// ..
// 喂狗
dev_iwdg_feed();
// 進(jìn)入待機(jī)模式開(kāi)關(guān)
if(m_bEnterStandByMode)
{
// 使能外部中斷,GPIOB3,用以MCU從待機(jī)模式喚醒
dev_exti_enable(TRUE);
ENTERSTOPMODE:
// 設(shè)置RTC鬧鐘,5秒鐘產(chǎn)生一次RTC鬧鐘中斷*/
dev_rtc_setAlarm(5);
// 進(jìn)入停止模式(低功耗),直至外部中斷觸發(fā)時(shí)被喚醒
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
// 是否是RTC鬧鐘中斷喚醒
if(dev_rtc_isAlarm())
{
// 喂狗
dev_iwdg_feed();
// 喂完狗繼續(xù)進(jìn)入停止模式
goto ENTERSTOPMODE;
}
// 禁止外部中斷
dev_exti_enable(FALSE);
// 從停止模式喚醒后恢復(fù)系統(tǒng)時(shí)鐘
dev_clk_restore();
}
}
以下是完整的參考代碼:
//**********************************************************************************************
// STM32F10x StopMode RTC Feed Dog
// compiler: Keil UV3
// 2013-01-04 , By friehood
//**********************************************************************************************
#include "stm32f10x_lib.h"
#include "platform_config.h"
static Boolean g_bRTCAlarm = FALSE;
/*******************************************************************************
* Function Name : RCC_Configuration
* Description : Configures the different system clocks.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void RCC_Configuration(void)
{
/* RCC system reset(for debug purpose) */
RCC_DeInit();
/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON);
/* Wait till HSE is ready */
if(RCC_WaitForHSEStartUp() == SUCCESS)
{
/* Enable Prefetch Buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//FLASH時(shí)序控制
//推薦值:SYSCLK = 0~24MHz Latency=0
// SYSCLK = 24~48MHz Latency=1
// SYSCLK = 48~72MHz Latency=2
//FLASH_SetLatency(FLASH_Latency_1); //警告:修改為1會(huì)對(duì)DMA值有影響(如ADC采集值會(huì)錯(cuò)位)
FLASH_SetLatency(FLASH_Latency_2);
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* PLLCLK = 12MHz * 3 = 36 MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_3);
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
/* Enable PWR and BKP clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/* Enable AFIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
}
/*******************************************************************************
* Function Name : NVIC_Configuration
* Description : Configures the nested vectored interrupt controller.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
/* Set the Vector Table base location at 0x20000000 */
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else /* VECT_TAB_FLASH */
/* Set the Vector Table base location at 0x08000000 */
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
}
/*******************************************************************************
* Function Name : SysTick_Configuration
* Description : Configures the SysTick to generate an interrupt each 1 millisecond.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SysTick_Configuration(void)
{
/* Select AHB clock(HCLK) as SysTick clock source */
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
/* Set SysTick Priority to 3 */
NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 3, 0);
/* SysTick interrupt each 1ms with HCLK equal to 72MHz */
SysTick_SetReload(72000);
/* Enable the SysTick Interrupt */
SysTick_ITConfig(ENABLE);
}
/*******************************************************************************
* Function Name : Delay
* Description : Inserts a delay time.
* Input : nTime: specifies the delay time length, in milliseconds.
* Output : None
* Return : None
*******************************************************************************/
void Delay(u32 nTime)
{
/* Enable the SysTick Counter */
SysTick_CounterCmd(SysTick_Counter_Enable);
TimingDelay = nTime;
while(TimingDelay != 0);
/* Disable the SysTick Counter */
SysTick_CounterCmd(SysTick_Counter_Disable);
/* Clear the SysTick Counter */
SysTick_CounterCmd(SysTick_Counter_Clear);
}
/*******************************************************************************
* Function Name : RTC_Configuration
* Description : Configures RTC clock source and prescaler.
* Input : None
* Output : None