STM32低功耗模式下的三种串口通信方式

在嵌入式设备中,常涉及到低功耗下的串口通信,本文以STM32L4作为硬件平台,讲解3种低功耗下的串口通信,希望对做低功耗的嵌入式开发者有所启发或帮助。笔者才疏学浅,难免有错误或遗漏之处,望读者能不吝指正。

下文所涉及的低功耗模式都是指STM32的停机模式,在该模式下PLL停止工作,仅LSI和HSI继续运行(进休眠前已经打开的话),所有IO状态、内部RAM数据保持不变,所有外部IO中断、内部RTC定时唤醒、LPUART、LPTIM可以将MCU唤醒,唤醒后程序从进入低功耗的地方继续运行,默认刚唤醒后会使用HSI作为系统时钟,因此唤醒后需要立即配置时钟。

一、低功耗串口(LPUART)

STM32L4系列有LPUART,可以在停止模式下直接唤醒MCU。LPUART中断可以设置为接收到1个bit位唤醒或接受到1个byte唤醒,具体可以参考STM32L4参考手册或官方的相关文档,以下是下载链接:

https://www.stmcu.com.cn/Designresource/design_resource_download/file_id/513641/file/DM00355687_ENV1.pdf/token/90db775645fe1ad7c3004bd795aae6d9

STM32系列LPUART资源
LPUART时钟源使用LSE或HSI时从低功耗唤醒

使用32.768KHz的LSE作为LPUART的时钟时,波特率最大只能是9600;使用16MHz的HSI作为LPUART的时钟时,波特率可以比较高,实测波特率为115200时低功耗唤醒是没有问题的,波特率为256000时已经出现首字节丢失的情况。推荐使用HSI作为LPUART的时钟,因为从停止模式唤醒时,MCU默认使用的就是HSI时钟。注意:进入低功耗前需要使能低功耗串口的唤醒功能,不要关闭串口。有篇帖子专门计算了STM32的LPUART的波特率计算:http://www.elecfans.com/lab/MCU/20171031573087.html

LPUART唤醒的三种方式

从上图可以看出,将MCU从低功耗唤醒有3种匹配方式:

  1. 地址匹配唤醒,我也没搞懂这个地址是指什么地址,猜测可能就是接收的第一个字节,只有匹配上了,才会产生WUF中断,否则将重新进入低功耗。
  2. 起始位唤醒,显然就是指接收到串口的起始位就立即唤醒,这种方式应该是这三种里唤醒最快的。
  3. 字节唤醒,类似于RXNE,收到一个字节后产生WUF唤醒。

注意:进入低功耗前需要使能低功耗串口的唤醒功能,不要关闭串口。仅在使用LSE或HSI作为LPUART时钟源时允许LPUART从STOP模式唤醒,其他时钟源是不可以的

HAL库提供了几个函数供我们使用:

1、用于配置LPUART唤醒的方式:地址匹配、起始位唤醒或字节唤醒,需要在进低功耗前配置好
HAL_StatusTypeDef HAL_UARTEx_StopModeWakeUpSourceConfig(UART_HandleTypeDef *huart, UART_WakeUpTypeDef WakeUpSelection); 

2、用于开启LPUART的低功耗唤醒功能,需要在进低功耗前开启
HAL_StatusTypeDef HAL_UARTEx_EnableStopMode(UART_HandleTypeDef *huart); 

3、用于关闭LPUART的低功耗唤醒功能
HAL_StatusTypeDef HAL_UARTEx_DisableStopMode(UART_HandleTypeDef *huart);

4、LPUART低功耗唤醒中断回调函数,程序运行到这里说明WUF中断标记被置位,MCU被LPUART唤醒
void HAL_UARTEx_WakeupCallback(UART_HandleTypeDef *huart);

优点:无需额外的GPIO,发送端无需关心如何唤醒对端(对端是指有LPUART唤醒的一端)。

缺点:STM32的LPUART资源较少,一个芯片可能只有一个LPUAT外设,有些芯片甚至没有LPUART外设。

二、串口RX作为GPIO中断

此种唤醒方式需要连接通信两端的TX、RX、GND。当通信两端都处于空闲状态时,接收方的RX设为GPIO上拉输入,并检测下降沿中断。当发送方需要发送数据时,先发一些0x00、0x55或0xAA等带有bit位带0的数据,接收方检测到下降沿中断后,将RX引脚重新初始化为串口RX开始接收数据。需要注意的是,这种情况下,接收方一开始接收的可能不是真正想要的数据,需要靠协议解析器去过滤(一般都是接收然后先放入环形buffer,然后在主循环或某一线程中从该buffer中取数据并解析)。

注意:一般接收方被唤醒并完成初始化所需的时间为5~10ms(只是保守值,实际比这快得多),因此发送方在发送真正的数据前,应该先发几个0x00等数据,延时5~10ms,再发真正的数据。当然也可以不采用上述的延时方式,可以由接收方唤醒并初始化完成后告诉发送方已做好接受准备,相当于接收方告诉发送方“我已经被你唤醒且准备好了,你快发数据给我吧!”。采用何种方式取决于使用者的设计,最终目的都是一样的。

优点:不要求接收方的串口是低功耗串口,而且节省IO。

缺点:需要改变发送方的发送逻辑,且唤醒有延时。

三、使用额外的GPIO唤醒

这种方式实际上与串口RX作为GPIO中断唤醒是差不多的,只不过使用了额外的GPIO作为唤醒IO。建议串口空闲时,两边的唤醒IO都设为上拉输入检测下降沿中断,当发送方需要发送数据时,将该GPIO设为推挽输出,反复拉高拉低几次唤醒对端,发送完后将该引脚重新设为上拉输入检测下降沿中断。如果引脚足够多,也可以使用两组唤醒IO,每一组指定了一个唤醒方向,即引脚1用于A唤醒B,引脚2用于B唤醒A。

建议使用一个标志位来记录串口的使能状态,当需要发送数据时,初始化一下串口(如果标志位已经置位,则无需重新初始化,下同)。同理,当收到唤醒中断时,建议直接在中断里根据标志位初始化一下串口,因为在裸机的情况下,如果使用中断标志来通知串口需要重新初始化,可能会由于主循环里某个函数有阻塞导致串口没有及时初始化而丢包;如果使用RTOS的信号量来通知,则等待该信号量的线程的优先级应该尽量高。

优点:使用起来方便,无需修改串口引脚的设置。

缺点:使用了额外的GPIO。

发布了6 篇原创文章 · 获赞 3 · 访问量 237

猜你喜欢

转载自blog.csdn.net/qq_27575841/article/details/104133828