STM32低功耗串口唤醒(RS485)
@[TOC]STM32低功耗串口唤醒(RS485)
STM32的低功耗模式
对于STM32的低功耗模式,有睡眠模式,停止模式以及待机模式三种,可以根据实际需求选择对应的模式,这三种模式的特点是,功耗P(睡眠)>P(停止)>P(待机),响应时间为T(睡眠)>T(停止)>T(待机)。本次采用常用的停止模式,其唤醒方式更多,并且和待机模式功耗接近,官方手册给出的停止模式功耗为20uA,待机模式为2uA,而睡眠模式为mA级。使用串口唤醒的方式进行唤醒。
RS485通讯唤醒
串口唤醒方式网上的例程有很多,但是使用RS485进行通讯的时候,需要注意一点,当我们将RX配置成外部中断的引脚之后,我们还必须确定接收使能的引脚,下图为485硬件电路,使能引脚为SP3485的2,3引脚。 以下是进入停止模式的自定义函数,在该函数中,最后一句 语句表示进入停止模式,在之前需要将485的接收引脚配置为低电平,一些可能消耗的外设引脚可根据具体项目设计,如此例中的风扇控制引脚,旨在将功耗降到最低。 根据停止模式的特性,进入停止模式之后各个IO状态是保持进入之前的IO状态且之后无法更改,所以可以在此处配置以便无法进行串口唤醒功能。
// An highlighted block
void system_enter_stopmode(void)
{
//进入停止模式之前,设置以下IO口状态;停止模式保持IO状态不变
GPIO_ResetBits(GPIOA,GPIO_Pin_11); //485接收引脚,设为0才能实现串口接收唤醒
delay_ms(1);
GPIO_ResetBits(GPIOA,GPIO_Pin_15); //风扇控制引脚,避免该回路产生多余功耗
uart_exti_int();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR外设时钟
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE);
}
下图为RX配置为外部触发引脚部分代码,上升沿触发,触发之后进入外部中断中,在中断中为了不影响之后的串口通讯等功能,需要将各个时钟重新初始化,最简单粗暴的方法就是直接系统复位。
//串口外部中断配置
void uart_exti_int(void)
{
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_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);
}
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line10) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line10);
NVIC_SystemReset(); //复位重启
}
}
如何在主函数中进入停止模式? 只需要在对应位置调用函数system_enter_stopmode()即可。本例程在while循环中用标志位判断的方式进入停止模式。
while(1)
{
if(flag_stop_mode == 1) //系统判断需要进入停止模式
{
system_enter_stopmode();
}
