您的位置:首页 > 其它

cortex_m3_stm32嵌入式学习笔记(十五):待机唤醒实验(WK_UP外部中断)

2015-01-24 16:46 976 查看
很多单片机都有低功耗模式, 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);								  
	} 
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐