stm32f103 RTC周期性待机唤醒(一)

做一个低功耗的东西,搞了好几天,程序一直卡在一个地方(见下图),今天终于发现问题出在哪里了,对待机唤醒的问题做一个总结(只针对我遇到的问题,其他部分网上都有,基于stm32f103)


1、解决我遇到的问题
       我的RTC初始化部分有个“保存在备份寄存器的RTC标志是否已经被配置过的判断”,如果已经配置过,则进入else部分,但是这个else部分没有“要使能电源时钟,使能备份时钟,取消后备区的写保护”这些配置语句,而待机唤醒后程序从主函数执行,会执行到else部分,因为没有那些配置语句,所以再次对闹钟赋值就会不成功,就会卡在那里。(那些配置语句在clock_ini函数里,有注释)

2、待机用不用加extiline17事件
如果把闹钟中断的服务程序放在void RTC_IRQHandler(void)里面处理的话,不需要extiline17事件也可以唤醒(亲测),如果闹钟中断的服务程序放在void RTCAlarm_IRQHandler(void)里面处理的话,需要extiline17事件

3、RTCAlarm_IRQn和RTC_IRQn优先级
我见到网上说要把RTCAlarm_IRQn的优先级设置比RTC_IRQn优先级高,但是把闹钟中断的服务程序放在void RTC_IRQHandler(void)里面处理的话,不用这样设置也可以。如果闹钟中断的服务程序放在void RTCAlarm_IRQHandler(void)里面处理的话需要设置优先级,最好根据情况先把优先级的问题解决清楚

4、下面是我的一些代码

void Clock_ini(void)
{
  if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)		     //判断保存在备份寄存器的RTC标志是否已经被配置过
  {
     printf("\r\n\n RTC not yet configured....");
     RTC_Configuration();			<span style="white-space:pre">	</span>//RTC初始化	 
     printf("\r\n RTC configured....");
     Time_Adjust();					//设置RTC 时钟参数
     BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);    	      //RTC设置后,将已配置标志写入备份数据寄存器 
  }
  else
  {	     
     if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)	  //检查是否掉电重启
     {
       printf("\r\n\n Power On Reset occurred....");
     }												     
     else if(RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET) //检查是否reset复位
     {
       printf("\r\n\n External Reset occurred....");
     }
     printf("\r\n No need to configure RTC....");  
/***新加的,测试,待机唤醒后,程序不经过上面的if部分,所以没有这三步(两个语句),所以程序会卡,所以加上,果然***/
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);  
  	  /* 允许访问BKP区域 */
  	 PWR_BackupAccessCmd(ENABLE);	</span>
	 
	 RTC_WaitForSynchro();				 //等待RTC寄存器被同步 
     RTC_ITConfig(RTC_IT_SEC, ENABLE);			//使能秒中断
	 RTC_WaitForLastTask();	
	 RTC_ITConfig(RTC_IT_ALR, ENABLE);	 //naozhong
     RTC_WaitForLastTask();		<span style="white-space:pre">	</span>//等待写入完成
  }
  RCC_ClearFlag();				//清除复位标志
void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;	
  EXTI_InitTypeDef EXTI_InitStructure;

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	
   
  /* Enable the RTC Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;			//配置外部中断源(秒中断) 
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);	  
  
    /* Enable the RTC Alarm Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;		//配置外部中断源(闹钟中断) 
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);  
  
  //闹钟中断接到第17线外部中断
   EXTI_ClearITPendingBit(EXTI_Line17);
   EXTI_InitStructure.EXTI_Line = EXTI_Line17;
   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
   EXTI_InitStructure.EXTI_LineCmd = ENABLE;
   EXTI_Init(&EXTI_InitStructure); 
}
void RTC_Configuration(void)
{ 
  /* 使能 PWR 和 BKP 的时钟 */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); 
  /* 允许访问BKP区域 */
  PWR_BackupAccessCmd(ENABLE);
  /* 复位BKP */
  BKP_DeInit();
#ifdef RTCClockSource_LSI
  /* 使能内部RTC时钟 */ 
  RCC_LSICmd(ENABLE);
  /* 等待RTC内部时钟就绪 */
  while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  {
  }
  /* 选择RTC内部时钟为RTC时钟 */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);  
#elif defined	RTCClockSource_LSE  
  /* 使能RTC外部时钟 */
  RCC_LSEConfig(RCC_LSE_ON);
  /* 等待RTC外部时钟就绪 */
  while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
  {	    
  }
  /* 选择RTC外部时钟为RTC时钟 */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);  
#endif
  /* 使能RTC时钟 */
  RCC_RTCCLKCmd(ENABLE);


#ifdef RTCClockOutput_Enable  
  /* Disable the Tamper Pin */
  BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/64 on Tamper pin, the tamper
                               functionality must be disabled */
                               
  /* 使能在TAMPER脚输出RTC时钟 */
  BKP_RTCCalibrationClockOutputCmd(ENABLE);
#endif 

  /* 等待RTC寄存器同步 */
  RTC_WaitForSynchro();	  

  /* 等待写RTC寄存器完成 */
  RTC_WaitForLastTask();
  
  /* 使能RTC  naozhong中断 */  
  RTC_ITConfig(RTC_IT_ALR, ENABLE);

  /* 等待写RTC寄存器完成 */
  RTC_WaitForLastTask();
  
  /* 使能RTC秒中断 */  
  RTC_ITConfig(RTC_IT_SEC, ENABLE);

  /* 等待写RTC寄存器完成 */
  RTC_WaitForLastTask();
  
  /* 设置RTC预分频 */
#ifdef RTCClockSource_LSI
  RTC_SetPrescaler(31999);            /* RTC period = RTCCLK/RTC_PR = (32.000 KHz)/(31999+1) */
#elif defined	RTCClockSource_LSE
  RTC_SetPrescaler(32767);            /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
#endif
  
  /* 等待写RTC寄存器完成 */
  RTC_WaitForLastTask();
}
void RTCAlarm_IRQHandler(void)
{
  RTC_WaitForSynchro();
  if(RTC_GetITStatus(RTC_IT_ALR) != RESET)
  {
  	 //printf("mmmmmm");
	 EXTI_ClearITPendingBit(EXTI_Line17);
	 RTC_WaitForLastTask();
	 if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET)
        {
			// 清除唤醒标志
            PWR_ClearFlag(PWR_FLAG_WU);
			RTC_WaitForLastTask();
        }
	RTC_ClearITPendingBit(RTC_IT_ALR);
	RTC_WaitForLastTask();
	printf("\nIt will wake up after %d s\n",standbytime);
	RTC_Enter_StandbyMode(standbytime);//standbytime秒后唤醒
  }
}
void RTC_Enter_StandbyMode(u32 s)
{
	RTC_WaitForLastTask();
    RTC_SetAlarm(RTC_GetCounter()+s);
    RTC_WaitForLastTask();
    // 进入待机模式, 此时所有1.8V域的时钟都关闭,HIS和HSE的振荡器关闭, 电压调节器关闭.
    // 只有WKUP引脚上升沿,RTC警告事件,NRST引脚的外部复位,IWDG复位.
	/* Request to enter STANDBY mode (Wake Up flag is cleared in PWR_EnterSTANDBYMode function) */
    PWR_EnterSTANDBYMode();
}
5、接下来几天我要研究一下停机模式和功耗问题





  • 9
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是基于STM32CubeMX和HAL库的RTC定时唤醒代码: 1. 首先,在STM32CubeMX中配置RTC模块。打开“Pinout & Configuration”窗口,选择“RTC”模块,并确保“RTC Clock Source”被配置为“LSE”(低速外部晶体)或“LSI”(低速内部晶体),这取决于你的硬件。接下来,打开“Configuration”选项卡,启用“RTC”和“RTC Wakeup”,然后设置你需要的唤醒周期。最后,生成代码。 2. 在生成的代码中,打开“main.c”文件,找到“MX_RTC_Init”函数。在此函数中,你可以设置RTC时钟源、时钟预分频器和时钟分频器。例如,如果你使用的是LSE晶体,你可以设置如下的代码: ``` /* Enable the LSE clock */ RCC_OscInitTypeDef RCC_OscInitStruct; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.LSEState = RCC_LSE_ON; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /* Configure the RTC clock source */ RCC_PeriphCLKInitTypeDef RCC_RTCCLKInit; RCC_RTCCLKInit.PeriphClockSelection = RCC_PERIPHCLK_RTC; RCC_RTCCLKInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; if (HAL_RCCEx_PeriphCLKConfig(&RCC_RTCCLKInit) != HAL_OK) { Error_Handler(); } /* Enable the RTC peripheral clock */ __HAL_RCC_RTC_ENABLE(); ``` 此外,你还可以设置RTC唤醒定时器的时钟预分频器和分频器。例如,如果你需要1秒钟的唤醒周期,你可以设置如下的代码: ``` /* Configure the RTC wakeup timer */ hrtc.Init.HourFormat = RTC_HOURFORMAT_24; hrtc.Init.AsynchPrediv = 0x7F; hrtc.Init.SynchPrediv = 0x00FF; hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } /* Configure the RTC wakeup timer with a 1-second period */ RTC_WakeUpTypeDef RTC_InitStruct; RTC_InitStruct.WakeUpClock = RTC_WAKEUPCLOCK_RTCCLK_DIV16; RTC_InitStruct.WakeUpTime = 0x7FFF; /* 1 second */ if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, &RTC_InitStruct) != HAL_OK) { Error_Handler(); } ``` 3. 最后,在“RTC_WKUP_IRQHandler”中断处理程序中添加你需要执行的代码。例如,你可以使用GPIO口控制LED灯的状态: ``` void RTC_WKUP_IRQHandler(void) { HAL_RTCEx_DeactivateWakeUpTimer(&hrtc); HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0xFFFF, RTC_WAKEUPCLOCK_RTCCLK_DIV16); } ``` 此代码将在RTC唤醒时将LED灯的状态切换为反转,并重新设置RTC唤醒定时器。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值