在使用STM32做低功耗项目时,大概率会遇到一个问题:低功耗模式下想打印数据怎么办?

今天,学长给大家另辟蹊径,介绍一种使用串口唤醒低功耗的案例、方法。可设置三种唤醒方式:检测到起始位唤醒、检测到 RXNE 标志唤醒(即接收到数据)、检测到匹配地址时唤醒。

应用在低功耗项目上可实现在低功耗模式下也能打印调试数据,可谓低功耗调试神器。

1 串口唤醒低功耗介绍

1.1 唤醒源

关于低功耗,学长在这里就不单独做介绍了,改天单独开篇做低功耗相关的介绍,只需要知道低功耗模式总共有三种,按功耗由高到低分别为睡眠、停止、待机模式。

先抛出结论,USART和LPUART都可将STM32 MCU从低功耗模式唤醒,不同系列的MCU USART和LPUART 可唤醒的低功耗模式有差别,如下图所示:

esp 32 低功耗_嵌入式

大家先明白STM32有不同的USART/LPUART唤醒源可用于将MCU从低功耗模式唤醒:

  • 1、通过USART/LPUART_CR3寄存器的WUS位字段选择的特定事件。
  • 00:在地址匹配时唤醒(按照USART/LPUART_CR2寄存器的ADD[7:0]和ADDM7的定义)
  • 01:保留
  • 10:检测到Start位时唤醒
  • 11:在每次接收到数据时唤醒(即USART/LPUART_ISR寄存器中RXNE置位)

当唤醒事件得到验证时,通过硬件将USART/LPUART_ISR寄存器中的WUF标志置位,无论MCU处于低功耗模式还是运行模式。如果USART/LPUART_CR3寄存器中的相应中断使能位( WUFIE)置位,它将生成唤醒中断。

  • 2、RXNE中断

在进入低功耗模式前,必须通过USART/LPUART_CR1寄存器中的RXNEIE位置位来使能RXNE中断。

1.2 唤醒方式

根据上门说到的低功耗模式唤醒源可知,串口有三种唤醒方式可以将STM32从低功耗模式唤醒:

  • 检测到起始位唤醒。
  • 检测到 RXNE 标志唤醒,即接收到数据。
  • 检测到匹配地址时唤醒。

匹配地址支持 7bit 和 4bit 匹配两种方式,比如我们采用 7bit 匹配, 设置地址是 0x19,那么用户唤醒的时候要将最高 bit 设置为 1, 即发送地址 0x99( 0b1001 1001)才可以唤醒。

如果STM32 MCU处于低功耗模式且用作USART/LPUART内核时钟的HSI时钟关闭,当在USART/LPUART接收线路上检测到下降沿时,USART/LPUART接口请求重新开启HSI时钟。然后,将使用HSI时钟进行帧接收。

如果唤醒事件得到验证,将从低功耗模式唤醒MCU并进行正常的数据接收。

唤醒成功时的时序效果如下:

esp 32 低功耗_嵌入式_02

如果唤醒事件未得到验证, HSI时钟将重新关闭, MCU不唤醒并维持低功耗模式,内核时钟请求被释放。

唤醒失败时的时序效果:

esp 32 低功耗_stm32_03

注: tWUUSART或tWULPUART是唤醒时间参数

1.3 USART 与 LPUART 比较

LPUART 比 USART 特性更少,但可用更低功耗工作,并可更有效地使用 LSE 时钟。两种外设的主要特性总结如下:

esp 32 低功耗_串口_04

本文只讲述通过USART唤醒低功耗模式,LPUART唤醒低功耗模式的方法类似,但在低功耗模式下功能更为强大,本文暂不展开,后面开篇做详细介绍

2 USART唤醒低功耗流程

2.1 时钟设置

串口初始化的流程与正常串口的一致,唯一差别是串口唤醒低功耗时需要将串口的时钟设置为LSE 或者 HSI 时钟,其他的初始化流程不变。

以设置HSI为串口时钟为例:

 /*# Enable the HSI clock  #*/
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!= HAL_OK)
  {
    /* Error */
    while(1); 
  }
  
  /*# Configure HSI as USART clock source #*/
  USARTx_RCC_CONFIG(RCC_USARTxCLKSOURCE_HSI);
  
  /* Select HSI as wakeup clock from stop mode */
  __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI);

2.2 进入低功耗模式前配置

选择合适的唤醒方式,在STM32进入低功耗前,进行相应配置,三种唤醒方式的配置案例代码如下:

  • 接收到数据唤醒
  /* make sure that no UART transfer is on-going */ 
  while(__HAL_UART_GET_FLAG(&UartHandle, USART_ISR_BUSY) == SET);
  /* make sure that UART is ready to receive
   * (test carried out again later in HAL_UARTEx_StopModeWakeUpSourceConfig) */
  while(__HAL_UART_GET_FLAG(&UartHandle, USART_ISR_REACK) == RESET);

  /* set the wake-up event:
   * specify wake-up on RXNE flag */
  WakeUpSelection.WakeUpEvent = UART_WAKEUP_ON_READDATA_NONEMPTY;
  if (HAL_UARTEx_StopModeWakeUpSourceConfig(&UartHandle, WakeUpSelection)!= HAL_OK)
  {
    Error_Handler(); 
  }
 
  /* Enable the UART Wake UP from STOP1 mode Interrupt */
  __HAL_UART_ENABLE_IT(&UartHandle, UART_IT_WUF);
  • 检测到起始位唤醒
 /* make sure that no UART transfer is on-going */ 
  while(__HAL_UART_GET_FLAG(&UartHandle, USART_ISR_BUSY) == SET);
  /* make sure that UART is ready to receive 
   * (test carried out again later in HAL_UARTEx_StopModeWakeUpSourceConfig) */
  while(__HAL_UART_GET_FLAG(&UartHandle, USART_ISR_REACK) == RESET);
  
  /* set the wake-up event:
   * specify wake-up on start-bit detection */
  WakeUpSelection.WakeUpEvent = UART_WAKEUP_ON_STARTBIT;
  if (HAL_UARTEx_StopModeWakeUpSourceConfig(&UartHandle, WakeUpSelection)!= HAL_OK)
  {
    Error_Handler();
  }

  /* Enable the UART Wake UP from STOP1 mode Interrupt */
  __HAL_UART_ENABLE_IT(&UartHandle, UART_IT_WUF);
  • 检测到匹配地址唤醒
/* make sure that no UART transfer is on-going */ 
  while(__HAL_UART_GET_FLAG(&UartHandle, USART_ISR_BUSY) == SET);
  /* make sure that UART is ready to receive
   * (test carried out again later in HAL_UARTEx_StopModeWakeUpSourceConfig) */
  while(__HAL_UART_GET_FLAG(&UartHandle, USART_ISR_REACK) == RESET);
     
  /* set the wake-up event:  
   * specify address-to-match type. 
   * The address is 0x29, meaning the character triggering the 
   * address match is 0xA9 */
  WakeUpSelection.WakeUpEvent = UART_WAKEUP_ON_ADDRESS;
  WakeUpSelection.AddressLength = UART_ADDRESS_DETECT_7B;
  WakeUpSelection.Address = 0x29;  
  if (HAL_UARTEx_StopModeWakeUpSourceConfig(&UartHandle, WakeUpSelection)!= HAL_OK)
  {
    Error_Handler(); 
  }

  /* Enable the UART Wake UP from stop mode Interrupt */
  __HAL_UART_ENABLE_IT(&UartHandle, UART_IT_WUF);

2.3 退出低功耗之后配置

退出低功耗之后,调用这个函数就可以啦。

HAL_UARTEx_DisableStopMode(&UartHandle);

就这么简单三个步骤,就可实现串口唤醒低功耗模式,可谓知者不难,难者不知。