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

news2024/11/15 5:54:13
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 本身,外围电路的设计也是很重要的,所以大家在进行低功耗测试的时候,如果测量的结果不够满意,多注意一下文中提到的其他细节说明,而且还得结合外围电路一起分析。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2240655.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

接口自动化代码编写规范

命名规范 文件命名:测试文件应该以 test_ 开头,以 _test.py 结尾,例如:test_my_module_test.py。 函数命名:测试函数应该以 test_ 开头,描述清楚被测试的功能或行为,使用下划线分隔单词&#…

ESLint 使用教程(四):ESLint 有哪些执行时机?

前言 ESLint 作为一个静态代码分析工具,可以帮助我们发现和修复代码中的问题,保持代码风格的一致性。然而,ESLint的最佳实践不仅仅在于了解其功能,更在于掌握其执行时机。本文将详细介绍ESLint在不同开发阶段的执行时机&#xff…

Leetcode 存在重复元素II

这段代码的算法思想可以用以下步骤来解释: 算法思想 使用哈希表(HashMap)存储每个元素的索引: 遍历数组 nums 时,使用一个 HashMap 来记录每个元素的值和它的索引位置。这样可以快速查找之前出现过的相同元素的索引。…

1111111111待修改--大流量分析(三)-BUUCTF

总结摘要 题目来来源URL https://buuoj.cn/challenges#%E5%A4%A7%E6%B5%81%E9%87%8F%E5%88%86%E6%9E%90%EF%BC%88%E4%B8%89%EF%BC%89 答题过程 这道题是看大佬写着说查找phpinfo,我现在也不知道为什么能够一下子就定位到这里了 这里先按照phpinfo进行&#xff…

在Docker环境下为Nginx配置HTTPS

前言 配置HTTPS已经成为网站部署的必要步骤。本教程将详细介绍如何在Docker环境下为Nginx配置HTTPS,使用自签名证书来实现加密通信。虽然在生产环境中建议使用权威CA机构颁发的证书,但在开发测试或内网环境中,自签名证书是一个很好的选择。 …

Python →爬虫实践

爬取研究中心的书目 现在&#xff0c;想要把如下网站中的书目信息爬取出来。 案例一 耶鲁 Publications | Yale Law School 分析网页&#xff0c;如下图所示&#xff0c;需要爬取的页面&#xff0c;标签信息是“<p>”&#xff0c;所以用 itemssoup.find_all("p&…

expo5.2运行web报错Cannot find module ‘react‘

修改app.json中的web output 配置为 ‘single’ 可以解决 expo run web 这个错误问题 "web": {"bundler": "metro","output": "single","favicon": "./assets/images/favicon.png"},相关链接&#xff1…

信号保存和信号处理

目录 信号保存中重要的概念 内核中信号的保存 对sigset_t操作的函数 对block&#xff0c;pendding&#xff0c;handler三张表的操作 sigpromask ​编辑 sigpending 是否有sighandler函数呢&#xff1f; 案例 信号处理 操作系统是如何运行的&#xff1f; 硬件中断 …

C#从入门到放弃

C#和.NET的区别 C# C#是一个编程语言 .NET .NET是一个在window下创建程序的框架 .NET框架不仅局限于C#,它还可以支持很多语言 .NET包括了2个组件&#xff0c;一个叫CLR(通用语言运行时)&#xff0c;另一个是用来构建程序的类库 CLR 用C写一个程序&#xff0c;在一台8688的机器…

STM32 HAL 矩阵按键(轮询方式)

1、简介 最近准备做个门禁系统,首先通过4x4矩阵按键实现密码的设定,查看网上资料完成了4x4矩阵按键的初步使用,整理一个傻瓜式操作方便后续的使用与复习。 2、实物图 3、STM32CubeMX配置 4、KEY.C /******************************************************************…

linux网络编程9——无锁队列

文章目录 无锁队列1. 无锁队列原理1.1 多线程并发控制策略介绍1.2 无锁队列概念1.3 无锁队列的分类1.3.1 以生产者消费者数量划分1.3.2 以底层数据结构划分1.3.3 侵入式与非侵入式链表队列 1.4 无锁队列应用场景 2. 无锁队列的实现2.1 MPSCQueue2.2 rte_ring 学习参考 无锁队列…

【电子设计】按键LED控制与FreeRTOS

1. 安装Keilv5 打开野火资料,寻找软件包 解压后得到的信息 百度网盘 请输入提取码 提取码:gfpp 安装526或者533版本都可以 下载需要的 F1、F4、F7、H7 名字的 DFP pack 芯片包 安装完 keil 后直接双击安装 注册操作,解压注册文件夹后根据里面的图示步骤操作 打开说明 STM…

(四)P2Link内置HTTP服务,分享本地文件

P2Link可快速为本地文件目录提供公网HTTP服务地址&#xff0c;用于远程浏览和下载本地文件&#xff0c;类似于nginx等服务器软件的静态资源功能。 相较于前两篇&#xff0c;Windows连接P2Link的WebDAV服务和Windows连接P2Link的FTP服务中描述的方案&#xff0c;通过HTTP分享文件…

Charles抓https包-配置系统证书(雷电)

1、导出证书 2、下载 主页上传资源中有安装包&#xff0c;免费的 openssl 安装教程自己搜 openssl x509 -subject_hash_old -in charles.pem 3、修改证书名、后缀改成点0 雷电打开root和磁盘写入 4、导入雷电证书根目录 证书拖进去&#xff0c;基本就完成了&#xff…

认证鉴权框架SpringSecurity-1--概念和原理篇

1、基本概念 Spring Security 是一个强大且高度可定制的框架&#xff0c;用于构建安全的 Java 应用程序。它是 Spring 生态系统的一部分&#xff0c;提供了全面的安全解决方案&#xff0c;包括认证、授权、CSRF防护、会话管理等功能。 2、认证、授权和鉴权 &#xff08;1&am…

动态规划一>子数组系列

题目&#xff1a; 2.解析&#xff1a; 代码&#xff1a; public int maxSubArray(int[] nums) {int n nums.length;int[] dp new int[n 1];int ret Integer.MIN_VALUE;for(int i 1; i < n; i){dp[i] Math.max(nums[i - 1], dp[i - 1] nums[i - 1]);ret Math.max(…

ctfshow DSBCTF web部分wp

ctfshow 单身杯 web部分wp web 签到好玩的PHP 源码&#xff1a; <?php error_reporting(0); highlight_file(__FILE__);class ctfshow {private $d ;private $s ;private $b ;private $ctf ;public function __destruct() {$this->d (string)$this->d;$this…

【How AI Works】读书笔记2 出发吧! AI纵览 第一部分

目录 1.说明 2.第一部分(P5~P8) 如何控制几乎所有计算机的方式 三个计算机的先驱人物 AI,机器学习和深度学习之间的关系 机器学习的介绍 深度学习的介绍 AI的介绍 模型 3.单词 4.专业术语 1.说明 书全名:How AI Works From Sorcery to Science 作者 Ronald T.Kneus…

MQ集群

目录 MQ集群 集群分类 普通集群 集群结构和特征 集群的部署 获取cookie 准备集群配置 启动集群 镜像模式 镜像模式的特征 镜像模式的配置 exactly模式 仲裁队列 集群特征仲裁队列&#xff1a;仲裁队列是3.8版本以后才有的新功能&#xff0c;用来替代镜像队列&#…

【excel】easy excel如何导出动态列

动态也有多重含义&#xff1a;本文将描述两种动态场景下的解决方案 场景一&#xff1a;例如表头第一列固定为动物&#xff0c;且必定有第二列&#xff0c;第二列的表头可能为猫 也可能为狗&#xff1b;这是列数固定&#xff0c;列名不固定的场景&#xff1b; 场景二&#xff1…