STM32F030的低功耗案例(RTC闹钟中断定时唤醒喂狗+按键外部中断唤醒)

最近使用到低功耗方案,采用的是STM32F030C8T6芯片,由于任务开启了看门狗,进入休眠后(采用的是STOP模式),需要及时喂狗,故而使用RTC闹钟中断定时唤醒来喂狗。

对比三种休眠模式:就设备的使用情况和功能需求,采用STOP模式

/* 三种休眠模式说明-各有不同
1.Sleep mode
	In Sleep mode, only the CPU is stopped. All peripherals continue to operate and can 
wake up the CPU when an interrupt/event occurs.
2.Stop mode
	Stop mode achieves very low power consumption while retaining the content of SRAM 
and registers. All clocks in the 1.8 V domain are stopped, the PLL, the HSI RC and the 
HSE crystal oscillators are disabled. The voltage regulator can also be put either in 
normal or in low power mode.
The device can be woken up from Stop mode by any of the EXTI lines. The EXTI line 
source can be one of the 16 external lines or the RTC alarm.
3.Standby mode
	The Standby mode is used to achieve the lowest power consumption. The internal 
voltage regulator is switched off so that the entire 1.8 V domain is powered off. The 
PLL, the HSI RC and the HSE crystal oscillators are also switched off. After entering 
Standby mode, SRAM and register contents are lost except for the Standby circuitry.
The device exits Standby mode when an external reset (NRST pin), an IWDG reset, a 
rising edge on the WKUP pins, or an RTC alarm occurs.	
*/	

见如下代码:

/*RTC定时唤醒设置*/
static void rtc_wakeup_set(void)
{
	/*RTC属于备份域,需要使能设备总线时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	/* Enable Access To The RTC & Backup Registers */
	PWR_BackupAccessCmd(ENABLE);
	RCC_LSICmd(ENABLE);  /*启动LSI晶振*/
	while(RESET==RCC_GetFlagStatus(RCC_FLAG_LSIRDY)){} /*等待LSI就绪*/
		
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);/*配置RTC时钟:选择LSI时钟*/		
	RCC_RTCCLKCmd(ENABLE);   /*使能RTC时钟   */
	RTC_WaitForSynchro();    /*等待RTC时间寄存器与RTC的APB总线时钟同步*/
		
	RTC_InitTypeDef RTC_InitStructure;
#if 1	
  /*
	 RTC的时钟源有3个:
	 > LSE(32.768kHz)
	 > LSI(40kHz)
	 > HSE/32。
	 > 秒输出计算:Tsec=LSI/[(RTC_AsynchPrediv+1)*(RTC_SynchPrediv +1)]
	*/
	//RTC_InitStructure.RTC_HourFormat=RTC_HourFormat_12;
	RTC_InitStructure.RTC_SynchPrediv=0x18F;//399
	RTC_InitStructure.RTC_AsynchPrediv=0x63;//99
    RTC_Init(&RTC_InitStructure);
#else	
    RTC_StructInit(&RTC_InitStructure);	//缺省配置,主要应用于LSE(32.768KHz) 
#endif	
		
	RTC_TimeTypeDef	  RTC_TimeStructure;
#if 0
//YYMMDD
	RTC_DateTypeDef RTC_DateStructure;
	RTC_DateStructure.RTC_Year=21;
	RTC_DateStructure.RTC_Month=RTC_Month_August;
	RTC_DateStructure.RTC_Date=1;
	RTC_DateStructure.RTC_WeekDay=RTC_Weekday_Monday;
	RTC_SetDate(RTC_Format_BCD,&RTC_DateStructure);
	RTC_DateStructInit(&RTC_DateStructure);	
//HHMMSS	
	RTC_TimeStructure.RTC_H12=RTC_H12_AM;
	RTC_TimeStructure.RTC_Hours=0;
	RTC_TimeStructure.RTC_Minutes=0;
	RTC_TimeStructure.RTC_Seconds=0;
	RTC_SetTime(RTC_Format_BCD,&RTC_TimeStructure);
#else
	RTC_TimeStructInit(&RTC_TimeStructure);/*缺省配置 (Time = 00h:00min:00sec).*/
#endif

  RTC_GetTime(RTC_HourFormat_12,&RTC_TimeStructure);//获取配置的时间参数
	
	RTC_AlarmTypeDef RTC_AlarmStructure;
	/*屏蔽日期和时分参数,仅采用秒参数*/
	RTC_AlarmStructure.RTC_AlarmMask             = RTC_AlarmMask_DateWeekDay|RTC_AlarmMask_Hours|RTC_AlarmMask_Minutes;
	RTC_AlarmStructure.RTC_AlarmTime.RTC_H12     = RTC_TimeStructure.RTC_H12;
//	RTC_AlarmStructure.RTC_AlarmTime.RTC_Hours   = RTC_TimeStructure.RTC_Hours;	
//	RTC_AlarmStructure.RTC_AlarmTime.RTC_Minutes = RTC_TimeStructure.RTC_Minutes;
	RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds = RTC_TimeStructure.RTC_Seconds+RTC_WKUP_TIME;
	RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmStructure);//配置参数数据是BIN格式	
	
	RTC_AlarmCmd(RTC_Alarm_A,DISABLE);//先关闭闹钟,等待一切先配置完成后再开启。
	
	/*EXTI线17是连接到RTC闹钟事件的,配置其中断也就是配置RTC闹钟中断*/
	EXTI_InitTypeDef  EXTI_InitStructure;
	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);
	 
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure); 

	/*开始前,先清除干扰残留以防误触发*/
	RTC_ClearFlag(RTC_FLAG_ALRAF);
	RTC_ClearITPendingBit(RTC_IT_ALRA);//清除RTC闹钟A的标志 
	EXTI_ClearITPendingBit(EXTI_Line17);//清除LINE17上的中断标志位

    RTC_ITConfig(RTC_IT_ALRA,ENABLE);//配置RTC闹钟中断并使能
	RTC_AlarmCmd(RTC_Alarm_A,ENABLE);//开启闹钟中断
	
//	PWR_BackupAccessCmd(DISABLE);
	PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_SLEEPEntry_WFI);//设置中断唤醒方式,并且设备随之进入停止模式而休眠
}

#define RTC_WKUP_TIME  (10) /*定时唤醒时间:10s*/

static void dev_sleep_set(void)
{
  //1.配置所有IO引脚为模拟输入方式,实现引脚0消耗
	#define GPIO_ALL_PIN     (GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7\
	|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15)

	GPIO_InitTypeDef GPIO_InitStructure;

	GPIO_DeInit(GPIOA);//关闭所有设备时钟
	GPIO_DeInit(GPIOB);
	GPIO_DeInit(GPIOC);
	GPIO_DeInit(GPIOF);
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_ALL_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;		  
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB,ENABLE);
	GPIO_InitStructure.GPIO_Pin  = GPIO_ALL_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;		   
	GPIO_Init(GPIOB,&GPIO_InitStructure);

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE);
	GPIO_InitStructure.GPIO_Pin  = GPIO_ALL_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;		   
	GPIO_Init(GPIOC,&GPIO_InitStructure);

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF,ENABLE);
	GPIO_InitStructure.GPIO_Pin  = GPIO_ALL_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;		   
	GPIO_Init(GPIOF,&GPIO_InitStructure); 
	
	 //2.配置中断唤醒引脚
	GPIO_InitStructure.GPIO_Pin  = KEY_FUNC_PIN;//
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;		  
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	 NVIC_InitTypeDef NVIC_InitStructure;	 
	 NVIC_InitStructure.NVIC_IRQChannel = EXTI4_15_IRQn;
	 NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
	 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	 
	 NVIC_Init(&NVIC_InitStructure); 
	 
	 EXTI_InitTypeDef  EXTI_InitStructure;
	 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	 EXTI_InitStructure.EXTI_Line =EXTI_Line5;
	 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//原理图上按键是上拉的,故而采用下降沿触发
	 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	 EXTI_Init(&EXTI_InitStructure);
}


/*设备正常状态初始化*/
static void dev_normal_init(void)
{
	f0xx_rcc_configuration();	
	timer15_init();	
	batt_init();
	all_adc_init();		
	led_init();
//	buzzer_init(&buzzer);
	key_init();
	at24c_register(AT24C02,&at24c02);
	lcd_init(&lcd);
	uart1_init();	
}

/*正常模式*/
static void dev_normal_entry(void)
{
   while(0==lcd.sleep_flag)
   {
		task_handler();
		iwtd_feed();
   }
	 iwtd_feed();//跳出主任务,进入休眠前先喂狗一次	 
}

/*休眠模式*/
static void dev_sleep_entry(void)
{
	dev_sleep_set();//设备休眠设置
	rtc_wakeup_set();//RTC唤醒设置
	dev_normal_init();//唤醒后->恢复IO引脚功能		
}

/*入口函数*/
int main(void)
{
	dev_normal_init();
 	iwtd_init();
	HR_DEBUG("Hey,I was born today!\r\n");	
	__TODO:		
	dev_normal_entry();//正常状态任务
	HR_DEBUG("Nothing to do, I'm going to sleep!\r\n");	
	dev_sleep_entry();//休眠状态
	HR_DEBUG("Call me? I have wokenup!\r\n");	
	goto __TODO;
}

/*外部中断入口*/
void EXTI4_15_IRQHandler(void)
{
	if((SET==EXTI_GetITStatus(EXTI_Line4))||(SET==EXTI_GetITStatus(EXTI_Line5)))
	{
		lcd.sleep_flag=0;
		lcd.sleep_timer=0;
		EXTI_ClearITPendingBit(EXTI_Line4);
		EXTI_ClearITPendingBit(EXTI_Line5);		
	}
}

/*RTC中断*/
void RTC_IRQHandler(void)
{
  if(SET==RTC_GetITStatus(RTC_IT_ALRA))
  {
	iwtd_feed();//喂狗
	//测试
	//lcd.sleep_flag=0;
	//lcd.sleep_timer=0;
	
	RTC_TimeTypeDef	  RTC_TimeStructure;
	RTC_TimeStructInit(&RTC_TimeStructure);//使用缺省函数 重置RTC时间 (RTC_Time = 00h:00min:00sec).
	RTC_GetTime(RTC_HourFormat_12,&RTC_TimeStructure);//获取重置的时间参数
	
	RTC_AlarmTypeDef RTC_AlarmStructure;//重置闹钟  (Alarm_Time = 00h:00min:10sec).
	RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds = RTC_TimeStructure.RTC_Seconds+RTC_WKUP_TIME;
	RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmStructure);	
	
	RTC_ClearFlag(RTC_FLAG_ALRAF);
	RTC_ClearITPendingBit(RTC_IT_ALRA);
  }	
  /*EXTI线17连接到RTC闹钟事件,所以发生中断后需要手动清除标志*/
  EXTI_ClearITPendingBit(EXTI_Line17);		
}

上一篇:[SRS+docker]实现直播服务器 3 基于webRTC协议的srs低延迟直播研究


下一篇:webrtc源码分析-线程任务管理