欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32外部中断、串口唤醒低功耗

程序员文章站 2022-07-02 09:48:37
...

STM32的低功耗模式共有三个:

  • 睡眠模式-(sleep): 睡眠模式的功耗是mA级别,一般在实际应用中较少使用
  • 停止模式-(stop): 停止模式的功耗为20uA,所有时钟关闭,寄存器不断电,依靠外部中断或RTC唤醒
  • 待机模式-(standby):待机模式的功耗为2uA,TAMPER引脚不关断,通过WKUP引脚唤醒

在项目中综合选择了停止模式,在该模式下使用两种唤醒方式:

  • WKUP引脚唤醒
  • 串口唤醒

进入停止模式配置

为了尽可能的降低功耗,需要进行IO口的配置,防止它们处于浮空状态,增大电流。STM32在复位后的IO口默认处于浮空输入状态,因此一定要对它们进行配置。实际过程中发现,同一配置成模拟输入状态和分别配置成上拉输入或下拉输入的功耗相同。因此为了精简代码,可统一配置成模拟输入

void DisablePeriph(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
	 /*PA*/  //模拟输入配置方法
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
	 GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	/*PB*/    //上拉输入配置方法
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	 GPIO_SetBits(GPIOB,GPIO_Pin_All);	
	 GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	/*PC*/    //下拉输入配置方法
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	 GPIO_SetBits(GPIOB,GPIO_Pin_All);	
	 GPIO_Init(GPIOC, &GPIO_InitStructure);

	 
	/*PD*/    //如果使用了外部晶振,也要进行配置
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	 
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; 
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	 GPIO_ResetBits(GPIOD,GPIO_Pin_0|GPIO_Pin_1);
	 GPIO_Init(GPIOD, &GPIO_InitStructure);
	
}

外部中断端口配置

  • WKUP按键唤醒

使用外部中断唤醒停止模式下的STM32,需要将该IO口配置到相应的中断线上。需要注意的是,WKUP按键与KEY0与KEY1不同的是,它是高电平有效,唤醒低功耗,因此在设置时设置为下拉模式

    GPIO_InitTypeDef GPIO_InitStructure; 
	NVIC_InitTypeDef NVIC_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;

	//使能GPIOA和复用使用
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//PA0
	GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD;//下拉输入
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//将PA0连接到中断事件A
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
	EXTI_InitStructure.EXTI_Line=EXTI_Line0;
	EXTI_InitStructure.EXTI_Mode= EXTI_Mode_Interrupt; 
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
	EXTI_InitStructure.EXTI_LineCmd= ENABLE;
	EXTI_Init(&EXTI_InitStructure);//初始化外部中断
	
	NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
  • 串口唤醒
    由于进入低功耗时为了降低功耗,会将外设USART1关闭。为了使用串口能够唤醒STM32,需要先将串口的RX口配置为普通IO口,接收串口信号唤醒后,再初始化为串口。在这种情况下,串口发送的第一次数据仅用于唤醒单片机,而丢失字符串。因此串口唤醒配置有两步:
    1、RX口配置为普通IO口,连接至中断事件,进入低功耗
    2、串口发送数据唤醒后,初始化串口,进行串口通信
    GPIO_InitTypeDef GPIO_InitStructure; 
	NVIC_InitTypeDef NVIC_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;

	//使能GPIOA和复用使用
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_10;//PA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入
 	GPIO_Init(GPIOA, &GPIO_InitStructure);//

	//RX连接至PA10
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource10);
	EXTI_InitStructure.EXTI_Line=EXTI_Line10;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);	 
	
	NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);

低功耗与低功耗中断

进入停止模式,除了配置对上述进行配置后,记得使能电源管理时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

然后就可以进入低功耗模式:

PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);

对于停止模式,低功耗模式唤醒进入外部中断服务子程序。执行完中断服务子程序后,会返回至进入低功耗模式的下一语句继续执行;而对于待机模式,当低功耗唤醒后,相当于复位,从程序的main开始执行。

在低功耗中断,需要重新配置系统的时钟,否则会系统选用HSI(内部高速时钟,8M)运行。

void EXTI0_IRQHandler(void)
{ 
	//SYSCLKConfig_STOP();     //时钟配置
	/*72M可以使用默认系统时钟*/
	SystemInit();
	EXTI_ClearITPendingBit(EXTI_Line0); 
}

void EXTI15_10_IRQHandler(void)
{
    //SYSCLKConfig_STOP();     //时钟配置
	/*72M可以使用默认系统时钟*/
	EXTI_ClearITPendingBit(EXTI_Line10); 	
	EXTIDisable();        	//RX外部中断失能
}
  • 具体不同频率的时钟配置下次详说。

串口唤醒后串口初始化

PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);
/*串口唤醒后向下执行*/
RS485_Config(9600);
delay_init();

串口的初始化记得放在主函数的进入低功耗模式后面,不要放在中断服务子程序里,尽管能够正常运行,但在串口通信中无法正常通信。

后续的通信过程,或是执行完任务再次进入低功耗,最好在while(1)里执行。