STM32 休眠模式下,难道 看门狗和低功耗模式没法同时使用?

 

0

在STM32开发中经常会用到独立看门狗(IWDG)和低功耗模式,看门狗是为了检测和解决由软件错误引起的故障,低功耗模式是为了在CPU不需要继续运行时进入到休眠模式用以节省电能。其中独立看门狗的时钟由独立的RC振荡器(STM32F10x一般为40kHz)提供,即使在主时钟出现故障时,也仍然有效,因此可以在停止和待机模式下工作。而且独立看门狗一旦启动,除了系统复位,它不能再被停止。但这样引发的一个问题是当MCU进入到低功耗模式后由于CPU停止运行无法喂狗,会导致系统频繁复位。那如何解决这个问题呢,难道独立看门狗和低功耗模式没法同时使用?

 

一个很好的方式是在休眠模式下通过RTC定时唤醒来喂狗,喂完够在进入继续进入到休眠模式。比如看门狗复位的时间间隔为10s。那么在进入休眠模式前设置RTC闹钟中断时间为5s。这样每隔5s唤醒一次喂一次狗。便可以很好的解决这个问题。
  1. while(1)
  2.   {
  3.     // 执行任务
  4.         Task1();
  5.         Task2();
  6.         // ..
  7.  
  8.         // 喂狗
  9.         dev_iwdg_feed();
  10.  
  11.         // 进入待机模式开关
  12.         if(m_bEnterStandByMode)
  13.         {        
  14.             // 使能外部中断,GPIOB3,用以MCU从待机模式唤醒
  15.             dev_exti_enable(TRUE);
  16. ENTERSTOPMODE:        
  17.                 // 设置RTC闹钟,5秒钟产生一次RTC闹钟中断*/
  18.                 dev_rtc_setAlarm(5);
  19.         
  20.                 // 进入停止模式(低功耗),直至外部中断触发时被唤醒
  21.                 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
  22.         
  23.                 // 是否是RTC闹钟中断唤醒
  24.                 if(dev_rtc_isAlarm())
  25.                 {
  26.                         // 喂狗
  27.                         dev_iwdg_feed();
  28.                         // 喂完狗继续进入停止模式
  29.                         goto ENTERSTOPMODE;        
  30.                 }
  31.                 // 禁止外部中断 
  32.                 dev_exti_enable(FALSE);
  33.                 // 从停止模式唤醒后恢复系统时钟
  34.                 dev_clk_restore();
  35.         }                      
  36.   }
复制代码以下是完整的参考代码:
  1. //**********************************************************************************************     
  2. //  STM32F10x StopMode RTC Feed Dog 
  3. //  compiler: Keil UV3     
  4. //  2013-01-04 , By friehood     
  5. //**********************************************************************************************  
  6. #include "stm32f10x_lib.h"
  7. #include "platform_config.h"
  8. static Boolean g_bRTCAlarm = FALSE;
  9.  
  10. /*******************************************************************************
  11. * Function Name  : RCC_Configuration
  12. * Description    : Configures the different system clocks.
  13. * Input          : None
  14. * Output         : None
  15. * Return         : None
  16. *******************************************************************************/
  17. void RCC_Configuration(void)
  18. {
  19.         /* RCC system reset(for debug purpose) */
  20.         RCC_DeInit();
  21.  
  22.         /* Enable HSE */
  23.         RCC_HSEConfig(RCC_HSE_ON);
  24.  
  25.         /* Wait till HSE is ready */
  26.         if(RCC_WaitForHSEStartUp() == SUCCESS)
  27.         {
  28.                 /* Enable Prefetch Buffer */
  29.                 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
  30.  
  31.                 //FLASH时序控制 
  32.         //推荐值:SYSCLK = 0~24MHz   Latency=0 
  33.         //        SYSCLK = 24~48MHz  Latency=1 
  34.         //        SYSCLK = 48~72MHz  Latency=2
  35.                 //FLASH_SetLatency(FLASH_Latency_1);                   //警告:修改为1会对DMA值有影响(如ADC采集值会错位)
  36.                 FLASH_SetLatency(FLASH_Latency_2);
  37.  
  38.                 /* HCLK = SYSCLK */
  39.                 RCC_HCLKConfig(RCC_SYSCLK_Div1); 
  40.  
  41.                 /* PCLK2 = HCLK */
  42.                 RCC_PCLK2Config(RCC_HCLK_Div1); 
  43.  
  44.                 /* PCLK1 = HCLK/2 */
  45.                 RCC_PCLK1Config(RCC_HCLK_Div2);
  46.  
  47.                 /* PLLCLK = 12MHz * 3 = 36 MHz */
  48.                 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_3);
  49.  
  50.                 /* Enable PLL */ 
  51.                 RCC_PLLCmd(ENABLE);
  52.  
  53.                 /* Wait till PLL is ready */
  54.                 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  55.                 {
  56.                 }
  57.  
  58.                 /* Select PLL as system clock source */
  59.                 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  60.  
  61.                 /* Wait till PLL is used as system clock source */
  62.                 while(RCC_GetSYSCLKSource() != 0x08)
  63.                 {
  64.                 }
  65.         }
  66.         /* Enable PWR and BKP clock */
  67.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  68.  
  69.         /* Enable AFIO clock */
  70.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  71. }
  72.  
  73. /*******************************************************************************
  74. * Function Name  : NVIC_Configuration
  75. * Description    : Configures the nested vectored interrupt controller.
  76. * Input          : None
  77. * Output         : None
  78. * Return         : None
  79. *******************************************************************************/
  80. void NVIC_Configuration(void)
  81. {
  82.   NVIC_InitTypeDef NVIC_InitStructure;
  83.  
  84. #ifdef  VECT_TAB_RAM
  85.   /* Set the Vector Table base location at 0x20000000 */
  86.   NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
  87. #else  /* VECT_TAB_FLASH  */
  88.   /* Set the Vector Table base location at 0x08000000 */
  89.   NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
  90. #endif
  91.  
  92.   /* Configure one bit for preemption priority */
  93.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  94. }
  95.  
  96. /*******************************************************************************
  97. * Function Name  : SysTick_Configuration
  98. * Description    : Configures the SysTick to generate an interrupt each 1 millisecond.
  99. * Input          : None
  100. * Output         : None
  101. * Return         : None
  102. *******************************************************************************/
  103. void SysTick_Configuration(void)
  104. {
  105.   /* Select AHB clock(HCLK) as SysTick clock source */
  106.   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
  107.  
  108.   /* Set SysTick Priority to 3 */
  109.   NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 3, 0);
  110.    
  111.   /* SysTick interrupt each 1ms with HCLK equal to 72MHz */
  112.   SysTick_SetReload(72000);
  113.  
  114.   /* Enable the SysTick Interrupt */
  115.   SysTick_ITConfig(ENABLE);
  116. }
  117.  
  118. /*******************************************************************************
  119. * Function Name  : Delay
  120. * Description    : Inserts a delay time.
  121. * Input          : nTime: specifies the delay time length, in milliseconds.
  122. * Output         : None
  123. * Return         : None
  124. *******************************************************************************/
  125. void Delay(u32 nTime)
  126. {
  127.   /* Enable the SysTick Counter */
  128.   SysTick_CounterCmd(SysTick_Counter_Enable);
  129.   
  130.   TimingDelay = nTime;
  131.  
  132.   while(TimingDelay != 0);
  133.  
  134.   /* Disable the SysTick Counter */
  135.   SysTick_CounterCmd(SysTick_Counter_Disable);
  136.   /* Clear the SysTick Counter */
  137.   SysTick_CounterCmd(SysTick_Counter_Clear);
  138. }
  139.  
  140.  
  141. /*******************************************************************************
  142. * Function Name  : RTC_Configuration
  143. * Description    : Configures RTC clock source and prescaler.
  144. * Input          : None
  145. * Output         : None
  146. * Return         : None
  147. *******************************************************************************/
  148. void RTC_Configuration(void)
  149. {
  150.         EXTI_InitTypeDef EXTI_InitStructure;
  151.         NVIC_InitTypeDef NVIC_InitStructure;
  152.         
  153.         /* RTC clock source configuration ------------------------------------------*/
  154.         /* Allow access to BKP Domain */
  155.         PWR_BackupAccessCmd(ENABLE);
  156.  
  157.         /* Reset Backup Domain */
  158.         BKP_DeInit();
  159.  
  160.         /* Enable the LSI OSC */
  161.         RCC_LSICmd(ENABLE);
  162.  
  163.         /* Wait till LSI is ready */
  164.         while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET){}
  165.         
  166.         /* Select the RTC Clock Source */
  167.         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
  168.  
  169.         /* Enable the RTC Clock */
  170.         RCC_RTCCLKCmd(ENABLE);
  171.  
  172.         /* RTC configuration -------------------------------------------------------*/
  173.         /* Wait for RTC APB registers synchronisation */
  174.         RTC_WaitForSynchro();
  175.  
  176.         /* Set RTC prescaler: set RTC period to 1sec */
  177.         RTC_SetPrescaler(40000);
  178.         
  179.         /* Wait until last write operation on RTC registers has finished */
  180.         RTC_WaitForLastTask();
  181.  
  182.         /* Enable the RTC Alarm interrupt */
  183.         RTC_ITConfig(RTC_IT_ALR, ENABLE);
  184.         
  185.         /* Wait until last write operation on RTC registers has finished */
  186.         RTC_WaitForLastTask();
  187.  
  188.         /* Configure EXTI Line17(RTC Alarm) to generate an interrupt on rising edge */
  189.     EXTI_ClearITPendingBit(EXTI_Line17);
  190.     EXTI_InitStructure.EXTI_Line = EXTI_Line17;
  191.         EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  192.     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  193.         EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  194.     EXTI_Init(&EXTI_InitStructure);
  195.  
  196.         /* Enable the RTC Interrupt */
  197.         NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQChannel;
  198.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  199.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  200.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  201.         NVIC_Init(&NVIC_InitStructure);
  202. }
  203.  
  204. /*******************************************************************************
  205. * Function Name  : RTCAlarm_IRQHandler
  206. * Description    : This function handles RTC Alarm interrupt request.
  207. * Input          : None
  208. * Output         : None
  209. * Return         : None
  210. *******************************************************************************/
  211. void RTCAlarm_IRQHandler(void)
  212. {
  213.         if(RTC_GetITStatus(RTC_IT_ALR) != RESET)
  214.         {
  215.             /* Set the RTC alarm flag */
  216.             g_bRTCAlarm = TRUE;
  217.  
  218.                 /* Clear EXTI line17 pending bit */
  219.                 EXTI_ClearITPendingBit(EXTI_Line17);
  220.  
  221.                 /* Check if the Wake-Up flag is set */
  222.                 if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET)
  223.                 {
  224.                         /* Clear Wake Up flag */
  225.                         PWR_ClearFlag(PWR_FLAG_WU);
  226.                 }                                                                                                                                                
  227.                                                                                                                  
  228.                 /* Wait until last write operation on RTC registers has finished */
  229.                 RTC_WaitForLastTask();   
  230.                 /* Clear RTC Alarm interrupt pending bit */
  231.                 RTC_ClearITPendingBit(RTC_IT_ALR);
  232.                 /* Wait until last write operation on RTC registers has finished */
  233.                 RTC_WaitForLastTask();
  234.         }
  235. }
  236.  
  237. /*******************************************************************************
  238. * Function Name  : dev_rtc_setAlarm
  239. * Description    : 设置RTC闹钟.
  240. * Input          : 闹钟时间
  241. * Output         : None
  242. * Return         : None
  243. *******************************************************************************/
  244. void dev_rtc_setAlarm(u32 AlarmValue)
  245. {
  246.         /* Clear the RTC SEC flag */
  247.         RTC_ClearFlag(RTC_FLAG_SEC);
  248.         /* Wait clear RTC flag sccess */
  249.     while(RTC_GetFlagStatus(RTC_FLAG_SEC) == RESET);
  250.            /* Wait until last write operation on RTC registers has finished */
  251.         RTC_WaitForLastTask(); 
  252.  
  253.         /* Sets the RTC alarm value */
  254.     RTC_SetAlarm(RTC_GetCounter() + AlarmValue);
  255.         /* Wait until last write operation on RTC registers has finished */
  256.         RTC_WaitForLastTask(); 
  257. }
  258.  
  259. /*******************************************************************************
  260. * Function Name  : dev_rtc_isAlarm
  261. * Description    : RTC闹钟是否触发
  262. * Input          : None
  263. * Output         : None
  264. * Return         : TRUE:已触发,FALSE,未触发
  265. *******************************************************************************/
  266. Boolean dev_rtc_isAlarm(void)
  267. {
  268.         if(g_bRTCAlarm)
  269.         {
  270.             /* Clear the RTC alarm flag */
  271.                 g_bRTCAlarm = FALSE;
  272.                 return TRUE;
  273.         }
  274.         return FALSE;                        
  275. }
  276.  
  277. void dev_iwdg_init(void)
  278. {
  279.         /* Enable write access to IWDG_PR and IWDG_RLR registers */
  280.         IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
  281.         /* IWDG counter clock: 40KHz(LSI) / 256 = 0.15625 KHz */
  282.     IWDG_SetPrescaler(IWDG_Prescaler_256);
  283.         /* Set counter reload value to 1562 */
  284.         IWDG_SetReload(1562);        // 10s
  285.         /* Reload IWDG counter */
  286.         IWDG_ReloadCounter();
  287.         /* Enable IWDG (the LSI oscillator will be enabled by hardware) */
  288.         IWDG_Enable();
  289. }
  290.  
  291. void dev_iwdg_feed(void)
  292. {
  293.         IWDG_ReloadCounter();
  294. }
  295.  
  296. /*******************************************************************************
  297. * Function Name  : dev_clk_restore
  298. * Description    : Restore system clock after wake-up from STOP: enable HSE, PLL
  299. *                  and select PLL as system clock source.
  300. * Input          : None
  301. * Output         : None
  302. * Return         : None
  303. *******************************************************************************/
  304. void dev_clk_restore(void)
  305. {
  306.   /* Enable HSE */
  307.   RCC_HSEConfig(RCC_HSE_ON);
  308.  
  309.   /* Wait till HSE is ready */
  310.   HSEStartUpStatus = RCC_WaitForHSEStartUp();
  311.  
  312.   if(HSEStartUpStatus == SUCCESS)
  313.   {
  314.     /* Enable PLL */ 
  315.     RCC_PLLCmd(ENABLE);
  316.  
  317.     /* Wait till PLL is ready */
  318.     while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  319.     {
  320.     }
  321.  
  322.     /* Select PLL as system clock source */
  323.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  324.  
  325.     /* Wait till PLL is used as system clock source */
  326.     while(RCC_GetSYSCLKSource() != 0x08)
  327.     {
  328.     }
  329.   }
  330. }
  331.  
  332. /*******************************************************************************
  333. * Function Name  : EXTI_Configuration
  334. * Description    : Configures EXTI Line3.
  335. * Input          : None
  336. * Output         : None
  337. * Return         : None
  338. *******************************************************************************/
  339. void EXIT_Configuration(void)
  340. {
  341.         EXTI_InitTypeDef EXTI_InitStructure;
  342.  
  343.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource3);
  344.         EXTI_ClearITPendingBit(EXTI_Line3);
  345.         EXTI_InitStructure.EXTI_Line = EXTI_Line3;
  346.         EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;                                                                                  
  347.         EXTI_InitStructure.EXTI_Trigger        = EXTI_Trigger_Falling;        
  348.         EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  349.         EXTI_Init(&EXTI_InitStructure);
  350. }
  351.  
  352. void dev_exti_enable(Boolean bEnable)
  353. {
  354.         NVIC_InitTypeDef NVIC_InitStructure;
  355.  
  356.         /* Clear the Key Button EXTI line pending bit */
  357.         EXTI_ClearITPendingBit(EXTI_Line3);
  358.  
  359.         NVIC_ClearIRQChannelPendingBit(EXTI3_IRQChannel);
  360.         NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQChannel;
  361.           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  362.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  363.         NVIC_InitStructure.NVIC_IRQChannelCmd = bEnable ? ENABLE : DISABLE;
  364.         NVIC_Init(&NVIC_InitStructure);        
  365. }
  366.  
  367. /*******************************************************************************
  368. * Function Name  : main
  369. * Description    : Main program.
  370. * Input          : None
  371. * Output         : None
  372. * Return         : None
  373. *******************************************************************************/
  374. int main(void)
  375. {
  376.   /* System Clocks Configuration */
  377.   RCC_Configuration();
  378.  
  379.   /* NVIC configuration */
  380.   NVIC_Configuration();
  381.  
  382.   /* Configure RTC clock source and prescaler */
  383.   RTC_Configuration();
  384.  
  385.   /* Configure the SysTick to generate an interrupt each 1 millisecond */
  386.   SysTick_Configuration();
  387.  
  388.   /* Configures EXTI Line3 */
  389.   EXIT_Configuration();
  390.  
  391.   /* IWDG initialize*/
  392.   dev_iwdg_init();
  393.  
  394.   while(1)
  395.   {
  396.     // 执行任务
  397.         Task1();
  398.         Task2();
  399.         // ..
  400.  
  401.         // 喂狗
  402.         dev_iwdg_feed();
  403.  
  404.         // 进入待机模式开关
  405.         if(m_bEnterStandByMode)
  406.         {        
  407.             // 使能外部中断,GPIOB3,用以MCU从待机模式唤醒
  408.             dev_exti_enable(TRUE);
  409. ENTERSTOPMODE:        
  410.                 // 设置RTC闹钟,5秒钟产生一次RTC闹钟中断*/
  411.                 dev_rtc_setAlarm(5);
  412.         
  413.                 // 进入停止模式(低功耗),直至外部中断触发时被唤醒
  414.                 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
  415.         
  416.                 // 是否是RTC闹钟中断唤醒
  417.                 if(dev_rtc_isAlarm())
  418.                 {
  419.                         // 喂狗
  420.                         dev_iwdg_feed();
  421.                         // 喂完狗继续进入停止模式
  422.                         goto ENTERSTOPMODE;        
  423.                 }
  424.                 // 禁止外部中断 
  425.                 dev_exti_enable(FALSE);
  426.                 // 从停止模式唤醒后恢复系统时钟
  427.                 dev_clk_restore();
  428.         }                      
  429.   }
  430. }
复制代码

 

摘自:http://bbs.elecfans.com/jishu_465531_1_1.html

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值