STM32串口唤醒STOP模式的实现

发布者:自由梦想最新更新时间:2019-07-08 来源: eefocus关键字:STM32  串口唤醒  STOP模式 手机看文章 扫描二维码
随时随地手机看文章

前言

STM32常见的低功耗模式有三种:睡眠模式、STOP模式以及待机模式,STM32L系列还有其他低功耗模式。这里主要讲的是STOP模式,STOP模式可以通过外部中断或事件唤醒,但是不能通过串口中断唤醒,因为串口中断本身不是外部中断,那么如何才能实现串口唤醒STOP模式呢?


因为我这里只是为了做验证,为了快速验证,我也就没有用RT-Thread的PM电源管理组件进入STOP模式,感兴趣的读者可以用RT-Thread的电源管理组件去实现进行STOP模式。


 

一、为什么要串口唤醒STOP模式?

想象一下,在某些场合,如果你有一个无线通信模块(例如ESP8266、SIM800C)和STM32通过串口发送AT命令来对接服务器实现与服务器的数据交互,那么如果在没有进行数据交互的时候,我们是不是可以让STM32进入STOP模式来达到省电的状态,从而让电池续航更长。例如:STM32+ESP8266与后台服务器进行数据交互,当不用发送数据完毕,等待下次发送数据或等待后台下发数据给设备的这段时间可以让STM32进入STOP模式来达到省电,当后台服务器下发数据给设备的时候,我们可以向让后台发送一个唤醒设备的指令,ESP8266接收到后台的这条指令之后通过串口下发给STM32,那么就可以唤醒STM32了,这时候STM32就可以继续接收后台下发的数据。


 


二、串口唤醒STOP模式的思路

1、我们知道STOP模式只能外部中断或事件唤醒,那么想象一下,在STM32进行STOP模式之前,是不是可以先将UART_RX对应的GPIO引脚配置为外部中断引脚,而串口接收到字符相当于接收到01010...这样的高低电平,从二可以唤醒串口,当唤醒之后,我们再马上重新初始化串口,把UART_RX对应的GPIO引脚配置为接收中断模式?答案当然是可以的。


2、唤醒之后的程序是从哪里开始执行?答案是从进行STOP模式之前的那个地方重新开始执行,一会进行验证。


 


三、串口唤醒STOP模式实验

光说不练都是假把式,接下来进行实验。


1、实验平台:中国移动物联网OneNET NB开发板(板载STM32)。


2、STM32F103RET6、12M外部晶振、串口3进行实验。


3、操作系统:RT-Thread。


4、用RT-Thread创建两个线程,一个线程用于读取按键是否按下,按下则调用进入STOP模式函数进入STOP模式,另一个线程读取串口接收到的数据。


1、如何进行STOP模式?


实验时用的是标准库,在这里主要实现在进入STOP模式前将RX对应的GPIO引脚配置为外部中断模式以及进入STOP模式,代码如下:


/**************************************************************

函数名称:system_enter_stop

函数功能:系统进入STOP模式

输入参数:无

返 回 值:无

备    注:无

**************************************************************/

void system_enter_stop(void)

{

        uart_exti_init(); /* 进入STOP模式前配置RX引脚为外部中断模式 */

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE); /* 开电源管理时钟 */

//PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); /* 进入STOP模式,外部中断唤醒 */

PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE); /* 进入STOP模式,外部中断或事件唤醒 */

}

 


2、配置RX对应的GPIO引脚为外部中断模式


这里采用RT-Thread的PIN设备进行配置,在配置之前需要先关闭UART中断、复位UART、复位GPIO,然后在进行配置为外部中断模式,代码如下:


/**************************************************************

函数名称:uart_exti_init

函数功能:RX引脚配置为外部中断

输入参数:无

返 回 值:无

备    注:无

**************************************************************/

void uart_exti_init(void)

{

        /* 关闭UART中断、复位UART、复位GPIO */

USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);

USART_Cmd(USART3, DISABLE);

GPIO_DeInit(GPIOB);

USART_DeInit(USART3);

 

/* 配置RX对应的GPIO引脚为外部中断模式 */

rt_pin_mode(PIN_UART3_RX, PIN_MODE_INPUT_PULLUP);

rt_pin_attach_irq(PIN_UART3_RX, PIN_IRQ_MODE_FALLING, uart_exti_callback, RT_NULL);

rt_pin_irq_enable(PIN_UART3_RX, PIN_IRQ_ENABLE);

}

 


3、接收中断回调函数


在上面的配置中,有一个接收回调函数uart_exti_callback,就是在发送中断的时候要执行的事情,在接收回调函数里面,我们主要实现SystemInit,重新初始化串口,代码如下:


/**************************************************************

函数名称:uart_exti_callback

函数功能:RX引脚外部中断唤醒回调函数

输入参数:args:回调函数入口参数

返 回 值:无

备    注:无

**************************************************************/

void uart_exti_callback(void *args)

{

SystemInit();

uart_reinit(); /* 重新初始化串口 */

rt_kprintf("wake uprn");

 

}

 


4、进入STOP模式的线程


这里,创建一个线程来实现判断是否按键按下,按下则调用system_enter_stop函数进入STOP模式,同时为了验证唤醒之后时钟正常以及程序是从进行STOP模式之前的那个地方重新开始执行,我们设计LED灯500ms亮500ms灭,再一个计数变量,每隔1秒自动加1并打印,代码如下:


static void sleep_thread_entry(void *parameter)

{

unsigned char key;

unsigned int count=0;

while(1)

{

key = key_scan(0);

 

if(key == KEY4_PRES)

{

rt_kprintf("system_enter_stoprn");

system_enter_stop();

}

LED1(1);

rt_thread_mdelay(500);

LED1(0);

rt_thread_mdelay(500);

rt_kprintf("count:%drn",count);

count++;

}

}

 


5、实验操作和现象


1、开机之后,LED闪烁,串口打印count每隔1秒加1的值,等待一小会按下按键KEY4进入STOP模式:


FinSH抓取的串口打印信息

2、对比进入STOP模式前和STOP模式之后的电流情况(这里进入STOP模式之后电流还是很大是因为我们板子还接了其他耗电的模块,我们这对比电流有没有降下来就可以了),很明显,电流降下来了:


进入STOP模式前的电流

 


进入STOP模式后的电流

进入STOP模式后的电流

 


3、通过串口发送一个字符“A”,唤醒了STM32,这时候串口并不会打印字符“A”,因为唤醒之后要重新初始化串口,第二次发送字符“A”才能显示,这时候,我们观察FinSH打印出来的信息,可以看到count是从9开始打印,说明STOP唤醒之后会从原来进入STOP模式之前的地方重新执行代码:


验证代码的执行情况

 


唤醒之后第二次发一个字符能正常打印

 


4、接下来,我们再次按下KEY4重新然STM32进入STO模式,然后发送一个比较长的字符串来唤醒STM32,例如发“ABCDEFGHIJKLMNOPQ1234567890”,这时候,我们发现第一次发送之后,竟然会有字符出来,不是说没有吗?而且这些字符和我们发送的不一样,少了,第二次才正常:


唤醒之后打印字符不正常

 

四、串口唤醒存在的问题

1、上面我们提到,发送一个字符唤醒就很正常,而发送比较长的字符串唤醒却出现了不然正常的现象,这是为什么呢?想象一下m如果你是发一串很长的数据来唤醒串口,这串数据也是通过0101010等二进制来发送的,当RX引脚被触发中断唤醒MCU之后,唤醒之后串口初始化完成了,剩余的数据也就会接着以010101的高低电平发给STM32的串口,有可能导致有些字符的01丢失了一部分(例如上面出现了K567890),从而可以接下来的字符会打印出来。如果是发一个字符,一个字符的01010101其实也就8位,发送很快的,唤醒之后都已经发送结束了,所以就会直接唤醒,也就不会接收这个字符,只有第二次发送的时候才会接收到这个字符。


关键字:STM32  串口唤醒  STOP模式 引用地址:STM32串口唤醒STOP模式的实现

上一篇:stm32l051低功耗之stop模式
下一篇:stm32从停止模式唤醒到系统稳定需要多少时间

推荐阅读最新更新时间:2024-11-17 04:44

STM32的IO口的8种配置
1 STM32的输入输出管脚有下面8种可能的配置:(4输入+2输出+2复用输出) ① 浮空输入_IN_FLOATING ② 带上拉输入_IPU ③ 带下拉输入_IPD ④ 模拟输入_AIN ⑤ 开漏输出_OUT_OD ⑥ 推挽输出_OUT_PP ⑦ 复用功能的推挽输出_AF_PP ⑧ 复用功能的开漏输出_AF_OD 1.1 I/O口的输出模式下,有3种输出速度可选(2MHz、10MHz和50MHz),这个速度是指I/O口驱动电路的响应速度而不是输出信号的速度,输出信号的速度与程序有关(芯片内部在I/O口 的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路)。通过选择速度来选择
[单片机]
STM32 USB固件库结构
STM32 USB固件库结构如下图所示: 可见,STM32 USB固件库分为3层:Low Layer、Medium Layer和High Layer,下面分析下这三层分别的角色: (1)Low Layer usb_regs(.h,.c):实现了硬件抽象层,提供了一个函数集合来操作USB外设寄存器,这个集合包括Commmom resister functions、Endpoint register functions、Buffer description table functions和Double-buffered endpoints functions四个函数集; usb_int(.h,.c):模块处理正确中
[单片机]
STM32-GPRS模块连接系统主站
一、GPRS基础讲解(GSM/CDMA/GPRS介绍) 1、通信专业术语 BSS--基站子系统,通过无线接口与移动台直接联系,负责在一定区域内和移动台通信。(GSM) BTS--基站收发台,可以看作一复杂的无线调制器,BSS的主要部分,每个分配有若干信道。(GSM) RBS--Radio Base Station,无线基站:RBS是基站内所有设备的总称,在GSM规范中对应的主要部分是BTS,它由BSC来控制,用来提供移动台与系统的无线接口,它是CME20系统中的无线设备部分,主要由无线收发信机构成。 BSC--基站控制器,其功能是作为无线电设备与MSC的控制和通信的接口,直接控制BTS。(GSM) GPRS--Ge
[单片机]
STM32-GPRS模块连接系统主站
基于STM32物联网开发板(3)--红外测温MLX90614
1.MLX90614简介 MX90614是一款由迈来芯公司提供的低成本,无接触温度计。输出数据和物体温度呈线性比例,具有高精度和高分辨率。TO-39金属封装里同时集成了红外感应热电堆探测器芯片MLX81101(温度是通过PTC或是PTAT元件测量)和信号处理专用集成芯片MLX90302,专门用于处理红外传感器输出信号。用以阻碍可见光和近红外光辐射的光学滤波器(可传播长波)集成在封装内提供对环境和日光的免疫。滤波器的波长通带为5.5到14μm。由于集成了低噪声放大器、17位模数转换器和强大的数字信号处理芯片 MLX90302,使得高精度和高分辨度的温度计得以实现。一个附加的片上温度传感器用来测量芯片的温度。测量完两个传感器的输出后,
[单片机]
基于<font color='red'>STM32</font>物联网开发板(3)--红外测温MLX90614
STM32串口IAP实验中的地址问题
if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)和if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)分析 首先要清楚:0x8000000是Flash的起始地址,0x20000000是SRAM的起始地址。jump2app()是一个虚拟函数(函数指针) (*(vu32*)(0X20001000+4))== (*(__IO uint32_t*)(0X20001000+4)) ==(*(volatile unsigned int*)(0X20001000+4)) (*(vu32*)(0X20001000+4)) 通过内存寻
[单片机]
<font color='red'>STM32</font><font color='red'>串口</font>IAP实验中的地址问题
STM32下SysTick的一个容易发生的错误,时钟频率设置
今天同事测试我之前写的一个小程序,发生了奇怪的错误,先是Uart通讯接收操作,出现了接收数据不全的问题:2个字节的应答帧,在实际运行中只能收到1个字节,导致程序死循环。检查后发现,是接收部分代码留的延时太短,造成了芯片误以为通讯已结束,但实际应答帧尚未传输完毕。(此处接收代码的工作模式是:当Uart接收到1个字节后,即开始一个定长的延时,该延时长度与通讯波特率相关,当正常通讯还在继续时,则应在延时结束前收到下一个字节数据,如延时结束仍未收到下一个字节数据,说明当前一帧数据已完成,可开始对已接收数据进行处理) 发现了问题后,进行相应的针对性操作,对延时长度进行了增加,即解决了此问题。但仍然觉得疑惑,因此段程序是已经通过测试的,运
[单片机]
基于STM32的USB枚举过程学习笔记(三)
上一篇介绍到了主机上电复位USB设备,在控制传输的建立过程,发送了8个字节的数据给设备,这8个字节为0x80 0x06 0x00 0x01 0x00 0x00 0x40 0x00,该请求为USB标准设备请求中的GET_DESCRIPTOR请求。0x80表示标准设备请求,数据方向是设备到主机。0x60表示请求类型GET_DESCRIPTOR。0x01表示描述符类型是设备描述符。0x40表示描述符长度。 设备在收到该请求以后,首先进行解析,根据请求中的0x40表示该控制传输有数据过程,因此进入到Data_Setup0()函数。该函数根据请求的不同描述符,执行不同的回调函数 CopyRoutine(),并在DataStage
[单片机]
基于<font color='red'>STM32</font>的USB枚举过程学习笔记(三)
STM32看门狗--窗口看门狗
stm32有两个看门狗,独立看门狗和窗口看门狗,其实两者的功能是类似的,只是喂狗的限制时间不同。 独立看门狗是限制喂狗时间在0-x内,x由你的相关寄存器决定。喂狗的时间不能过晚。 窗口看门狗,所以称之为窗口就是因为其喂狗时间是一个有上下限的范围内,你可以通过设定相关寄存器,设定其上限时间和下限时间。喂狗的时间不能过早也不能过晚。 图1 窗口看门狗的 上窗口就是配置寄存器WWDG- CFR里设定的W ; 下窗口是固定的0x40; 当窗口看门狗的计数器在上窗口值之外,或是低于下窗口值都会产生复位。 图2 && 上窗口的值可以只有设定,7位二进制数最大只可以设定为127(0x7F),最小又必须大于下窗口的0x40,所以其
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved