STM32 使用 STM32CubeMX HAL库实现低功耗模式

时间:2024-11-15 12:36:49
STM32  使用 HAL 库的低功耗模式测试使用   ...... 矜辰所致

前言

上次画了一个 STM32L010F4 最小系统的板子,也做了一些基本测试,但是最重要的低功耗一直拖到现在,以前在使用 STM32L151 的时候用标准库做过低功耗的项目,现在都使用 STM32CubeMX 了,一直都未使用过。

那正好借着这次机会来记录一下,所以本文内容就是测试下在 STM32CubeMX 环境下如何实现 STM32 的低功耗模式。

以前 STM32L151 标准库低功耗文章:
STM32L151低功耗项目笔记(CO传感器TGS5042)
.
本次使用的测试芯片为 STM32L010F4 :
STM32L010F4 最小系统设计
.
我是矜辰所致,全网同名,尽量用心写好每一系列文章,不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开!

目录

  • 前言
  • 一、 STM32 低功耗模式
  • 二、 HAL 库休眠测试
    • 2.1 HAL 低功耗相关函数
    • 2.2 使用测试
      • 2.2.1 Sleep Mode 测试
      • 2.2.2 Stop Mode 按键唤醒
      • 2.2.3 Stop Mode RTC唤醒
        • 修改 RTC 唤醒周期
      • 2.2.4 Standby Mode 测试
        • 细节问题之如何节约内存空间
  • 三、 关于低功耗的其他细节说明
    • 3.1 `PWR_FLAG_WU` 和 `PWR_FLAG_SB`
    • 3.2 低功耗模式下的烧录问题
    • 3.3 休眠模式下的 IO 口问题
    • 3.4 关于 MCU 的时钟
  • 结语

一、 STM32 低功耗模式

关于 STM32 的低功耗模式,这个网络的文章一大堆,但是总的来说低功耗模式分为下面三类:

睡眠模式(Sleep Mode):

在睡眠模式下,只有 CPU 停止运行,内核时钟关闭,也就是程序暂停。

但外设和系统时钟继续工作。

这种模式适合于短时间内不需要 CPU 运算,但外设仍需保持活跃的场景。

IO 口状态保持和正常模式下一样。

可以通过任意一个中断或唤醒事件唤醒;唤醒后回到睡眠的位置向后执行。

停止模式(Stop Mode):

在停止模式中,关闭内核时钟、外设时钟,主时钟(HSE/HSI)被关闭,程序暂停,外设也停止工作。

只有低速时钟(LSI/LSE)继续运行。

保留内核1.8V供电,寄存器和 RAM 中的数据可以保持;

IO 口状态保持和正常模式下一样。

唤醒时间较短,适合需要较快响应的系统。

可以通过任意一个外部中断唤醒(EXTI);唤醒后可回到停止的代码处向后执行,但要重新初始化时钟和外设。

额外补充,ADC 和 DAC 不会自动停止工作,需要程序使其停止。 Flash 可以配置为 正常模式或者掉电模式。

待机模式(Standby Mode):

待机模式是最深的低功耗模式,关闭所有时钟,包括低速时钟,并且关闭了内部电压调节器 (内核1.8V供电) 。

寄存器和RAM数据不能保持(除了电源控制/状态寄存器(PWR_CSR)、备份寄存器,其他数据都丢失);

该模式适合长时间不需要响应的设备,唤醒后系统需完全重新初始化。

所有 IO 口均为高阻态,除了 RESET 引脚,以及使用了的 RTC 引脚和 启用了的 WAKEUP 引脚。

只有通过唤醒引脚(PA0)上升沿、RTC闹钟中断,或者复位唤醒;唤醒后相当于复位,从复位地址开始执行。

在上面的这些模式中:睡眠模式 适合于需要快速响应的场景,停止模式 和 待机模式 则适合于功耗要求较低且可以容忍较长唤醒时间的场景。

我们还需要知道,上面几个模式的 功耗由高到低 排序如下:

睡眠模式(Sleep Mode)> 停止模式(Stop Mode)> 待机模式(Standby Mode)

我们在实际使用 STM32 不同的系列内核芯片的时候,虽然大体上来说低功耗模式都差不多,但是我们还是有必要看一下对应的芯片手册中 Low-power modes 这一章节,排除有些芯片有些特除的模式。比如 本次测试使用的 STM32L010 手册如下(作为示例,没有把全部的模式截图上来):

在这里插入图片描述

本文我们的目的是怎么用,更深的一些相关理论与技术大家可以自行网上探究。

说明,本文以 STM32L010F4 芯片作为测试 。

二、 HAL 库休眠测试

我们本次使用 STM32CuBeMX 生成的代码对上面的三种模式进行实验测试,告诉大家怎么在生成的工程上面来使得 STM32 进入休眠模式。

我们知道使用 STM32CubeMX 可以一键生成代码,但是对于我们低功耗使用来说,我们还是要自己添加休眠程序的,HAL 库只是帮我们封装好了进入休眠的函数,我们什么时候进入休眠,如何唤醒还是需要自己写逻辑的!

2.1 HAL 低功耗相关函数

在 HAL 库中,有一个 stm32l0xx_hal_pwr.c 文件(这里是以 STM32L0 系列为例),里面包行了 HAL 写好的进入退出休眠函数,在 stm32l0xx_hal_pwr.h 头文件我们可以直接查看到这几个与低功耗有关的函数:

在这里插入图片描述

在上图中,我们已经做了基本的解释,实际上大家自己可以进入到函数原型,看一下官方的注释,基本上所有的问题都写的很清楚了 ,如下图:

(再一次说明官方资料的重要性,实际上只要告诉你东西在什么地方,然后剩下的直接可以阅读官方提供的东西,比很多网上文章更权威,也更加全面 )

在这里插入图片描述

2.2 使用测试

上面需要介绍的也介绍完毕了,接下来就开始来实际的测试一下这几种低功耗模式怎么操作。

2.2.1 Sleep Mode 测试

由上文我们可以知道, Sleep Mode 的进入函数为HAL_PWR_EnterSLEEPMode(),可以通过任意一个中断唤醒。

那我们做如下实验:

运行一段时间,让他进入 sleep mode ,然后通过外部中断(按钮)唤醒 。

为了演示效果,我们直接用 printf 通过串口助手看效果。

我们在 CubeMX 中做好几本设置,对于本次实验,我们可以直接使用芯片内部的时钟,虽然我们板子上外接了 32.768KHz 的低速时钟,但是这里用不用都不影响本次实验,所以在 CubeMX 中RCC 这一块什么都不选:

在这里插入图片描述

另外通过按钮唤醒,要根据原理图定义一下,下降沿触发中断,就是按键按下触发:

在这里插入图片描述

然后生成工程,编辑我们的工程如下:

在这里插入图片描述

上面我们可以看到,进入循环以后,打印一个消息就进入 sleep 模式,然后等待按钮按下,才会打印第二段消息。

但实际的情况是,我什么都没操作,他就循环的执行,这是为什么呢?

这是因为 Sleep Mode 是所有中断都可以唤醒,而我们系统运行 Systick 会一直运行,它每隔 1ms 中断一次,也会唤醒 MCU。 所以我们在进入 Sleep Mode 之前要关闭 Systick 定时器,睡眠过后再打开。

在 HAL 库中,关闭打开 Systick 定时器的函数为:

void HAL_SuspendTick(void);  //Suspends the Tick increment.
void HAL_ResumeTick(void);  // Resumes the Tick increment.

所以我们的程序应该改成如下:

while (1)
  {
    LED_ON;
    printf("get into sleep mode!\r\n");
    HAL_SuspendTick();
    HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);
    HAL_ResumeTick();
    printf("wakeup by exit key button !!!\r\n");
    LED_OFF;
    HAL_Delay(1000);
    LED_ON;
    HAL_Delay(1000);
    LED_OFF;
    HAL_Delay(1000);
    //
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

现在如果不按按键,程序就会一直在 Sleep mode ,串口输出也会一直处于下面的状态直到按键按下为止:

在这里插入图片描述

这里还需要说明一下的是,程序上我们并没有去写按键中断的程序,因为不需要,我们只要设定了按键下降沿触发中断就可以,即便触发了中断什么都不做,系统也会唤醒。

意思就是,对于 HAL 库工程而言,只要 stm32l0xx_it.c 中里面的中断只要触发了,就会把 MCU 从 Sleep mode 唤醒,不用管触发中断后有没有任何的操作。

2.2.2 Stop Mode 按键唤醒

接下来我们来看看 Stop Mode,该模式进入函数为HAL_PWR_EnterSTOPMode(),可以通过任意一个外部中断唤醒。

那我们做如下实验:

运行一段时间,让他进入 stop mode ,然后通过外部中断(按钮)唤醒 。

这里 Systick 我们就不需要单独关闭了,因为它唤醒不了,再者外设时钟停止了,其实 Systick 定时器也停止了。

第一次写和 sleep mode 一样,还是粗心大意,忘了唤醒后需要重新初始化时钟和外设。

在这里插入图片描述

最后加上时钟初始化就正常了,代码如下:

while (1)
  {
    LED_ON;
    printf("get into stop mode!\r\n");
    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);
    SystemClock_Config();
    printf("wakeup by exit key button !!!\r\n");
    LED_OFF;
    HAL_Delay(1000);
    LED_ON;
    HAL_Delay(1000);
    LED_OFF;
    HAL_Delay(1000);
    //
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

那这里有个疑问,命名是需要重新初始化时钟和外设,为什么我这里只重新初始化时钟就好了。

我们知道在 STOP 模式下,IO 状态会保持和正常模式下一致,比如在我的 STOP 模式下面,LED 灯会保持点亮也说明了这一点 。 在我示例中的串口和 IO 口(LED)没有关闭,配置也没有改变,所以唤醒以后不需要重新初始化他们。

但是这只是测试,实际使用低功耗设备不可能保持 LED 灯常亮。

2.2.3 Stop Mode RTC唤醒

测试完按键唤醒,我们还需要测试一个比较常用的方法, RTC 唤醒。

那么这时候我们得重新在 STM32CubeMX 里面设置一下,先设置一下 RCC :

在这里插入图片描述

然后在设置下 RTC ,具体操作如下图:

在这里插入图片描述

上面的 Wake Up Counter 设置说明有错误,如果想要为 5s ,应该把 Wake Up Counter 设置为 4。

还得记得把中断打开,可以看到 RTC 中断也是挂载 EXTI 外部中断线上的:

在这里插入图片描述

最后别忘了在时钟配置界面,把 RTC 选择为外部晶振 ,如下图:

在这里插入图片描述

设置完成以后,我们在写一下程序,我们可以看到工程里面会多了rtc.c 文件,这里包含了 RTC 的初始化 ,我们首先在main.c 里面写上如下代码:

	...
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
  // HAL_TIM_Base_Start_IT(&htim2); 
  
  printf("STM32L010F4 lowpower test!!!\r\n");
  printf("reset delay 3s for down load!!!\r\n");
  HAL_Delay(3000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    LED_ON;
    printf("get into stop mode!\r\n");
    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);
    printf("wakeup by RTC !!!\r\n");
    LED_OFF;
    HAL_Delay(500);
    //
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

然后在 rtc.c 里面实现以下 RTC 的中断回调函数,其实这个回调函数放在main.c 中也一样,当然记得,操作之前先打开时钟:

/* USER CODE BEGIN 1 */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
  RTC_TimeTypeDef sTime;
  RTC_DateTypeDef sData;
  SystemClock_Config();
  if(HAL_RTC_GetTime(hrtc,&sTime,RTC_FORMAT_BIN) == HAL_OK){
    HAL_RTC_GetDate(hrtc,&sData,RTC_FORMAT_BIN);
    printf("RTC current time: %02d:%02d:%02d\r\n",sTime.Hours,sTime.Minutes,sTime.Seconds);
  }

}
/* USER CODE END 1 */

然后实际测试结果如下:

在这里插入图片描述

发现了一个错误,在设置 Wake Up Counter 值的时候,我们设置的是 5, 这里中断一次为 6s ,如果要是5s ,Wake Up Counter 应该为4。

修改 RTC 唤醒周期

然后还要说明一下,如果想修改唤醒周期,在不修改频率的情况下,修改 Wake Up Counter 的值也可以实现,比如改成 10s 一次中断,那么使用如下函数:


HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 9, RTC_WAKEUPCLOCK_CK_SPRE_16BITS)

第一个参数为 RTC 对象指针,第二个参数就是 Wake Up Counter ,第三个参数为 Wake Up Clock

比如在执行完一次以后,就把时间修改为 10s:

在这里插入图片描述

当然,也可以放在唤醒之后在主函数中,根据其他条件按需求修改,这里只是一个示例。

除了上面这种办法,我在网上也参考了网上的一个修改时间的代码,可以直接设定为在多少秒以后实现下一次唤醒,代码如下:

/*
读取当前 RTC 值,再加上需要延时的 秒数,再指定下一次 RTC 报警的 RTC 时钟
因为有一个函数 STM32L010 没有,本人没有测试,大家复制使用起来需要自行测试。
*/
void set_next_time_Alarm_IT(unsigned int Seconds)
{
  RTC_TimeTypeDef rTime;
  RTC_AlarmTypeDef ATime;
  unsigned char Minutes,Hours;
  if(HAL_RTC_GetTime(&hrtc,&rTime,RTC_FORMAT_BIN) != HAL_OK) Error_Handler();
  Hours = (u8)(Seconds/3600);
  Minutes = (u8)((Seconds % 3600) / 60);
  Seconds = (u8)((Seconds % 3600) % 60);

  rTime.Seconds += (u8)Seconds;
  if(rTime.Seconds >= 60){
    rTime.Seconds -= 60;
    Minutes += 1;
  }
  rTime.Minutes += Minutes;
  if(rTime.Minutes >= 60){
    rTime.Minutes -= 60;
    Hours += 1;
  }
  rTime.Hours += Hours;

  ATime.AlarmTime = rTime;
  ATime.Alarm = RTC_ALARM_A;  

  // HAL_RTCEx_SetSecond_IT(&hrtc);// STM32L010没有

  HAL_RTC_SetAlarm_IT(&hrtc,&ATime,RTC_FORMAT_BIN);

}

以上就是 Stop Mode 的测试示例,主要需要注意的就是,从 Stop Mode 唤醒,要记得重新初始化时钟和外设(有必要的话)。

2.2.4 Standby Mode 测试

最后到了最低功耗的 Standby Mode 模式,Standby Mode 模式有点类似于关机,休眠后唤醒会从头开始制执行。

我们可以直接在上面一个工程上直接修改,整体效果如下:

在这里插入图片描述

上面的示例中有几点需要说明一下:

  • 上面代码中判断了一个标志位PWR_FLAG_SB ,这个表示为 Standby Flag ,这个标志位专门用于指示微控制器是否从待机模式(STANDBY Mode)唤醒。如果微控制器是从待机模式唤醒的,这个标志位会被设置为SET。
    所以可以通过这个位判断是从什么模式唤醒。

  • 在进入Standby 模式之前,我使用了HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1|PWR_WAKEUP_PIN3); 禁用 Wakeup 引脚。因为我们使用 RTC 唤醒,禁用这两个引脚可以使得它们变成高阻态,相对来说,更能节约那么一点电。
    至于为什么这里是 1 和 3 ,没有2 ,这个是不同的芯片决定的,虽然在手册中官方是这么说的:
    在这里插入图片描述
    但实际上他根本没有 PWR_WAKEUP_PIN2 ,因为写上去会报错= =!然后通过 CubeMX 的图形话界面也可以验证这一点。

  • 这里我们可以看到串口根本没有打印出 RTC 时间,这是因为通过 RTC 中断唤醒以后, MCU直接就从头开始运行了,它不会运行到中断处理函数中去。

如果我们想要看到 RTC 时间,我们需要再次修改一下,我们直接改成如下 :

在这里插入图片描述

看一下结果,好像有点问题:

在这里插入图片描述

我们命名是定义的每 5 S 唤醒一次,这里怎么变成 3S 了,这里稍微测试了一下,是因为我忽略了一个标志位:PWR_FLAG_WU ,在进入低功耗模式钱,需要清除一下这个标志位,这个标志位表示微控制器是由于外部唤醒信号(如外部中断或RTC闹钟)而从低功耗模式(如待机模式STANDBY或停止模式STOP)唤醒的。

最后代码修改成如下:

printf("STM32L010F4 lowpower test!!!\r\n");

  if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB) == SET){
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
    if(HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN) == HAL_OK){
      printf("RTC current time: %02d:%02d:%02d\r\n",sTime.Hours,sTime.Minutes,sTime.Seconds);
    }
    printf("standby reset\r\n");
  }
  else{
    printf("normal reset!!!\r\n");
  }
  printf("reset delay 3s for down load!!!\r\n");
  LED_ON;
  HAL_Delay(1000);
  LED_OFF;
  HAL_Delay(1000);
  LED_ON;
  HAL_Delay(1000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    printf("get into standby mode!\r\n");
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
    HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1|PWR_WAKEUP_PIN3);
    HAL_PWR_EnterSTANDBYMode();
    //printf("wakeup by RTC !!!\r\n");  不会走到这一步
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

最后看下结果,才是正常的:

在这里插入图片描述

细节问题之如何节约内存空间

这里我还有个细节问题,在上面的测试中,我都使用了 printf ,但是 STM32L010 的 Flash 非常小,只有 16K,使用 printf 函数非常占用 flash 空间,虽然测试无所谓,但是在这种简单测试上,我再加上点传感器驱动,就放不下了。

这里呢我们可以使用 函数HAL_UART_Transmit 来实现 printf 同样的效果,所以我把上面的程序改成下面这种方式:

  /* USER CODE BEGIN 2 */
  // HAL_TIM_Base_Start_IT(&htim2); 
  // printf("STM32L010F4 lowpower test!!!\r\n");
  HAL_UART_Transmit(&hlpuart1, (uint8_t *)"STM32L010F4 lowpower test!!!\r\n", strlen("STM32L010F4 lowpower test!!!\r\n"), 100);

  if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB) == SET){
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
    if(HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN) == HAL_OK){
      // printf("RTC current time: %02d:%02d:%02d\r\n",sTime.Hours,sTime.Minutes,sTime.Seconds);
      size_t len = snprintf((char *)buffer, sizeof(buffer), "RTC current time: %02d:%02d:%02d\r\n", sTime.Hours,sTime.Minutes,sTime.Seconds);
      HAL_UART_Transmit(&hlpuart1, buffer, len, 100);
    }
    // printf("standby reset\r\n");
    HAL_UART_Transmit(&hlpuart1, (uint8_t *)"standby reset\r\n", strlen("standby reset\r\n"), 100);
  }
  else{
    // printf("normal reset!!!\r\n");
    HAL_UART_Transmit(&hlpuart1, (uint8_t *)"normal reset!!!\r\n", strlen("normal reset!!!\r\n"), 100);
  }
  // printf("reset delay 3s for down load!!!\r\n");
  HAL_UART_Transmit(&hlpuart1, (uint8_t *)"reset delay 3s for down load!!!\r\n", strlen("reset delay 3s for down load!!!\r\n"), 100);
  LED_ON;
  HAL_Delay(1000);
  LED_OFF;
  HAL_Delay(1000);
  LED_ON;
  HAL_Delay(1000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    // printf("get into standby mode!\r\n");
    HAL_UART_Transmit(&hlpuart1, (uint8_t *)"get into standby mode!\r\n", strlen("get into standby mode!\r\n"), 100);
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
    HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1|PWR_WAKEUP_PIN3);
    HAL_PWR_EnterSTANDBYMode();
    //printf("wakeup by RTC !!!\r\n");  不会走到这一步
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

编译过后看一下 text 段,这么一点点代码就已经节约了差不多 2K 的内存空间 = =!:

在这里插入图片描述

好了,到这里 Standby Mode 的测试也完成了。

三、 关于低功耗的其他细节说明

最后呢,我们还有一些其他的细节问题,来补充说明一下。

3.1 PWR_FLAG_WUPWR_FLAG_SB

在上面我们没有特意的对这两个标志位做说明,然而在测试过程中也确实因为标志位出现了问题,所以在这里补充说明一下:

  • PWR_FLAG_WU(Wakeup Flag)

这个标志位表示微控制器是由于外部唤醒信号(如外部中断或 RTC 闹钟)而从低功耗模式(如待机模式STANDBY或停止模式STOP)唤醒的。在微控制器从低功耗模式唤醒后,这个标志位会被设置为SET。

在程序中,通常需要清除这个标志位,以避免微控制器被立即重新唤醒。使用 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

  • PWR_FLAG_SB(Standby Flag)

这个标志位专门用于指示微控制器是否从待机模式(STANDBY Mode)唤醒。如果微控制器是从待机模式唤醒的,这个标志位会被设置为 SET。

这个标志位可以用来区分微控制器是正常上电复位还是从待机模式唤醒的复位。

在程序中,也需要清除这个标志位,以准备下一次可能的待机模式进入。

总结来说,PWR_FLAG_WU 是一个通用的唤醒标志,用于指示任何低功耗模式下的唤醒事件,而PWR_FLAG_SB是专门用于指示从待机模式唤醒的情况。

在实际使用中,进入 stop 或者 standby 模式之前,都得记得清除一下 PWR_FLAG_WU 标志位!!!

3.2 低功耗模式下的烧录问题

在进入休眠状态后,STM32 是无法进行烧录的。

所以在上面测试的时候可以看到,我都会在复位后预留一点时间给与烧录。当然实际使用中唤醒工作基本也就是瞬间的事情,是无法采用这种方式的。这时候需要一直按住复位按键,在下载进行的时候松开,也是一种办法。

如果我们使用 JLink 的话,不管 STM32 是否休眠,可以直接全部擦除了以后,再进行烧录。

当然,还有其他的一些方式, ISP 下载啊, 使用 STLINK 下载等等。

3.3 休眠模式下的 IO 口问题

在休眠模式下 ,IO 口的配置也会影响着功耗。

我们知道在 Standby Mode 模式下面, STM32 会将除了 复位引脚,被使能的唤醒引脚,和 RTC 引脚意外,都设置为高阻态,这有利于把功耗保持在最低的状态。

除了这个模式,在其他低功耗模式中,我们其实也有必要注意一下 不用的 IO 口,我们可以手动的将其他 IO 口设置为高阻态,一般模拟输入(虽然是说 不用的 IO 默认就是这种状态)。在 CuBeMX 中,我们有一个选项可以勾选上,可以自动完成这种配置:

在这里插入图片描述

在休眠过程中,有些需要用到的 IO 口也可以进行一定的配置来节约功耗,有几点要注意一下:

  • 如果外部晶振不用的话,连接晶振的 IO 口不能配置为浮空输入,除非你的外部有下拉电阻。需要配置为输入上拉或者下拉,或者输出低电平。
  • 输入引脚,如果高阻状态端口是高电平,就设成上拉输入,如果高阻状态是低电平,设成下拉输入,如果高阻是中间状态,设成模拟输入;
  • 输出引脚会耗电,如果在休眠之后不需要用到,可以设置为输入,唤醒后再初始化;
  • 中断输入的引脚如果有上下拉,则会消耗电流,这时候可以在合适的情况下增大上下拉电阻,相对能够节能;

3.4 关于 MCU 的时钟

我们的 系统时钟都是可以设置的,一般对于普通应用,或许大家都习惯性的给到他最大的时钟周期,比如 72M ,32M 之类的。

但是时钟越大,功耗越大,当然,他响应速度也是最快的。 时钟越慢,功耗越低,但是运行速度也更低。

所以在实际应用中,需要根据自己的实际情况,根据需求选择合适的时钟周期,也能在一定程度上节约功耗。

这里举个例子,对于一些传感器采集的模型,完全可以使用低速率的时钟周期,因为在很多时候,采集传感器也会需要一定时间的等待,这等待的过程运行速度就不重要了,反而速度越快,额外消耗的功耗就越多。

结语

本文不仅对 STM32 的低功耗模式进行了一个介绍,然后还在 STM32CubeMX 环境下面对每个模式进行了详细的使用说明。

看完本文,相信大家应该都知道如何使用 HAL 库进行 STM32 的低功耗开发了。当然真正的低功耗,除了 MCU 本身,外围电路的设计也是很重要的,所以大家在进行低功耗测试的时候,如果测量的结果不够满意,多注意一下文中提到的其他细节说明,而且还得结合外围电路一起分析。

好了,本文就到这里!谢谢大家!