cortex_m3_stm32嵌入式學習筆記(十五):待機喚醒實驗(WK_UP外部中斷)

ARM 626瀏覽

很多單片機都有低功耗模式, STM32 也不例外。在系統或電源復位以后,微控制器處于運行狀態。運行狀態下的 HCLK 為 CPU 提供時鐘,內核執行程序代碼。當 CPU 不需繼續運行時,可以利用多個低功耗模式來節省功耗,例如等待某個外部事件時。用戶需要根據最低電源消耗,最快速啟動時間和可用的喚醒源等條件,選定一個最佳的低功耗模式。


STM32 的低功耗模式有 3 種:
1)睡眠模式( CM3 內核停止,外設仍然運行)
2)停止模式(所有時鐘都停止)
3)待機模式( 1.8V 內核電源關閉)

? ?

在這三種低功耗模式中,最低功耗的是待機模式,在此模式下,最低只需要 2uA 左右的電流。停機模式是次低功耗的,其典型的電流消耗在 20uA 左右。最后就是睡眠模式了。用戶可以根據自己的需求來決定使用哪種低功耗模式。
本節實驗是待機模式的實驗,根據上表可以看到有4種方式進入待機模式,我們選擇第一種,即通過WK_UP的外部中斷來觸發進入待機模式的方式
配置步驟:
1)使能電源時鐘。
2) 設置 WK_UP 引腳作為喚醒源。
3)設置 SLEEPDEEP 位,設置 PDDS 位,執行 WFI 指令,進入待機模式。
4)最后編寫 WK_UP 中斷函數。


wkup.c?

#include "wkup.h" //待命模式 void Sys_Standby(void) { 	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能 PWR外設時鐘 	PWR_WakeUpPinCmd(ENABLE); //使能喚醒管腳功能 	PWR_EnterSTANDBYMode();  //進入待命( STANDBY)模式 } //系統進入待機模式 void Sys_Enter_Standby(void) { 	RCC_APB2PeriphResetCmd(0X01FC,DISABLE); //復位所有 IO 口 	Sys_Standby(); }  //檢測 WKUP 腳的信號 //返回值 1:連續按下 3s 以上 // 返回值 0:錯誤的觸發 u8 Check_WKUP(void) { 	u8 t=0; 	LED0=0; 	while(1) 	{ 		if(WKUP_KD) 		{ 			t++; 			delay_ms(30); 			if(t>=100) 			{ 				LED0=0; 				return 1; 			} 		} 		else 		{ 			LED0=1; 			return 0; 		} 	} } void EXTI0_IRQHandler(void) { 	EXTI_ClearITPendingBit(EXTI_Line0);// 清除 LINE10 上的中斷標志位 	if(Check_WKUP()) 	{ 		Sys_Enter_Standby(); 	} } void WKUP_Init(void) { 	GPIO_InitTypeDef GPIO_ist;  	NVIC_InitTypeDef NVIC_ist; 	EXTI_InitTypeDef EXTI_ist; 	//使能GPIOA和復用功能時鐘 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); 	GPIO_ist.GPIO_Pin=GPIO_Pin_0;//PA0 	GPIO_ist.GPIO_Mode =GPIO_Mode_IPD;//下拉輸入 	GPIO_Init(GPIOA,&GPIO_ist); 	//中斷線 0 連接 GPIOA.0 	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); 	EXTI_ist.EXTI_Line=EXTI_Line0; 	EXTI_ist.EXTI_Mode= EXTI_Mode_Interrupt;  	EXTI_ist.EXTI_Trigger=EXTI_Trigger_Rising; 	EXTI_ist.EXTI_LineCmd= ENABLE; 	EXTI_Init(&EXTI_ist);//初始化外部中斷 	 	NVIC_ist.NVIC_IRQChannel=EXTI0_IRQn; 	NVIC_ist.NVIC_IRQChannelPreemptionPriority=2; 	NVIC_ist.NVIC_IRQChannelSubPriority=2; 	NVIC_ist.NVIC_IRQChannelCmd=ENABLE; 	NVIC_Init(&NVIC_ist); 	if(!Check_WKUP())Sys_Standby(); }


可以看到我們設定的是3秒有效,即按下WK_UP鍵3秒以上才會進入待機模式(關機)然后再按3秒以上便會開機。。

可能對開機有點不大理解 我們找到關機函數中復位IO口那個函數源碼

void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState) {   /* Check the parameters */   assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));   assert_param(IS_FUNCTIONAL_STATE(NewState));   if (NewState != DISABLE)   {     RCC->APB2RSTR |= RCC_APB2Periph;   }   else   {     RCC->APB2RSTR &= ~RCC_APB2Periph;   } }
因為我們傳進去的第二個參數是DISABLE 所以它會執行?RCC->APB2RSTR &= ~RCC_APB2Periph;
可以看到每次都對?APB2Periph取反后按位與, 達到開關機的效果。。

wkup.h

#ifndef _WKUP_H #define _WKUP_H #include "led.h" #include "delay.h" #include "sys.h" #include "usart.h"  #define WKUP_KD PAin(0)//PA0 檢測是否外部 WK_UP 按鍵按下 u8 Check_WKUP(void);//檢測 WKUP 腳的信號 void WKUP_Init(void);//PA0 WKUP 喚醒初始化 void Sys_Enter_Standby(void);//系統進入待機模式 #endif

主函數直接保留上一節時鐘的代碼(加了WKUP的初始化)。。在LCD上顯示時間,按WP_UP3秒關機

#include "led.h" #include "delay.h" #include "sys.h" #include "usart.h" #include "lcd.h" #include "usmart.h" #include "rtc.h" #include "wkup.h" void init(void) { 	NVIC_Configuration(); 	delay_init(); 	uart_init(9600); 	LED_Init(); 	LCD_Init(); 	WKUP_Init(); 	usmart_dev.init(72);//初始化SMART組件 } int main(void) { 	u8 t; 	init();   POINT_COLOR=RED; 	while(RTC_Init())		//RTC初始化	,一定要初始化成功 	{  		LCD_ShowString(60,130,200,16,16,"RTC ERROR!   ");	 		delay_ms(800); 		LCD_ShowString(60,130,200,16,16,"RTC Trying...");	 	} 	//顯示時間 	POINT_COLOR=BLUE;//設置字體為藍色					  	LCD_ShowString(60,130,200,16,16,"    -  -     ");	    	LCD_ShowString(60,162,200,16,16,"  :  :  ");	 		     	while(1) 	{								     		if(t!=calendar.sec) 		{ 			t=calendar.sec; 			LCD_ShowNum(60,130,calendar.w_year,4,16);									   			LCD_ShowNum(100,130,calendar.w_month,1,16);									   			LCD_ShowNum(124,130,calendar.w_date,2,16);	  			switch(calendar.week) 			{ 				case 0: 					LCD_ShowString(60,148,200,16,16,"Sunday   "); 					break; 				case 1: 					LCD_ShowString(60,148,200,16,16,"Monday   "); 					break; 				case 2: 					LCD_ShowString(60,148,200,16,16,"Tuesday  "); 					break; 				case 3: 					LCD_ShowString(60,148,200,16,16,"Wednesday"); 					break; 				case 4: 					LCD_ShowString(60,148,200,16,16,"Thursday "); 					break; 				case 5: 					LCD_ShowString(60,148,200,16,16,"Friday   "); 					break; 				case 6: 					LCD_ShowString(60,148,200,16,16,"Saturday "); 					break;   			} 			LCD_ShowNum(60,162,calendar.hour,2,16);									   			LCD_ShowNum(84,162,calendar.min,2,16);									   			LCD_ShowNum(108,162,calendar.sec,2,16); 			LED0=!LED0; 		}	 		delay_ms(10);								   	}  } 

七星彩走势图2元网官网