STM32 使用 STM32CubeMX HAL库实现低功耗模式
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_WU
和 PWR_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 的话,可以直接全部擦除了以后(也需要按下复位键连接),再进行烧录。
当然,还有其他的一些方式, 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 本身,外围电路的设计也是很重要的,所以大家在进行低功耗测试的时候,如果测量的结果不够满意,多注意一下文中提到的其他细节说明,而且还得结合外围电路一起分析。
好了,本文就到这里!谢谢大家!
相关文章:
STM32 使用 STM32CubeMX HAL库实现低功耗模式
STM32 使用 HAL 库的低功耗模式测试使用 ...... 矜辰所致前言 上次画了一个 STM32L010F4 最小系统的板子,也做了一些基本测试,但是最重要的低功耗一直拖到现在,以前在使用 STM32L151 的时候用标准库做过低功耗的项目,现在都使…...
技术美术百人计划 | 《2.1 色彩空间介绍》笔记
总览 一、色彩发送器 色彩认知: 光源是出生点,光源发射出光线,光线通过直射反射折射等路径最终进入人眼。 但人眼接收到光线后,人眼的细胞产生了一系列化学反应。 由此把产生的信号传入大脑,最终大脑对颜色产生了认…...
如何在 Ubuntu 上安装 Mosquitto MQTT 代理
如何在 Ubuntu 上安装 Mosquitto MQTT 代理 Mosquitto 是一个开源的消息代理,实现了消息队列遥测传输 (MQTT) 协议。在 Ubuntu 22.04 上安装 MQTT 代理,您可以利用 MQTT 轻量级的 TCP/IP 消息平台,该平台专为资源有限的物联网 (IoT) 设备设计…...
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
css使用弹性盒,让每个子元素平均等分父元素的4/1大小 原本: ul {padding: 0;width: 100%;background-color: rgb(74, 80, 62);display: flex;justify-content: space-between;flex-wrap: wrap;li {/* 每个占4/1 */overflow: hidden;background-color: r…...
设计模式的学习思路
学习设计模式确实需要一定的时间和实践,尤其是对于刚入门的人来说,因为一开始可能会感到有些混淆,尤其是当多个设计模式看起来有相似之处时。本博客是博主学习设计模式的思路历程,大家可以一起学习进步。设计模式学习-CSDN博客 1…...
stereopy 查看 data.tl 的可用属性
为了查看 data.tl 的可用属性,您可以使用 Python 的内置函数,例如 dir() 或 vars(),具体操作如下: 1. 列出 data.tl 的所有属性 使用 dir() 来查看所有可用的属性和方法: # 列出所有属性 print(dir(data.tl))这将返回一个列表,包含所有可用的方法、属性和内部字段。 2.…...
【2024APMCM亚太杯A题】详细解题思路
A题 复杂场景下的水下图像增强研究 解题思路问题一图像统计分析技术一、检测 偏色 的技术二、检测 弱光 的技术三、检测 模糊 的技术 聚类算法 问题二问题三问题四完整论文与代码 解题思路 问题一 问题 1:请使用类似上文提到的图像统计分析技术,对附件 …...
用 React18 构建Tic-Tac-Toe(井字棋)游戏
下面是一个完整的 Tic-Tac-Toe(井字棋)游戏的实现,用 React 构建。包括核心逻辑和组件分离,支持两人对战。 1. 初始化 React 项目: npx create-react-app tic-tac-toe cd tic-tac-toe2.文件结构 src/ ├── App.js…...
数据结构及算法--排序篇
在 C 语言中,可以通过嵌套循环和比较运算符来实现常见的排序算法,比如冒泡排序、选择排序或插入排序 目录 基础算法: 1.冒泡排序(Bubble Sort) 2.选择排序(Selection Sort) 3.插入排序&…...
泷羽sec学习打卡-网络七层杀伤链1
声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 关于蓝队基础的那些事儿-Base1 基本的企业网络架构是怎样的呢?高层管理IT管理影子IT中央技术…...
【QT】绘图
个人主页~ 绘图 一、绘图1、基础内容2、绘制形状(1)线段(2)矩形(3)圆形(4)文本(5)画笔(6)画刷 3、绘制图片(1)…...
vue3+elementui-plus el-dialog全局配置点击空白处不关闭弹窗
在与main.ts同级下的plugins文件夹(如果没有,新建一个)下建一个element.js文件(名字随便取) element.js文件内容如下: import ElementPlus from element-plus export default (app) > {console.log(app…...
Markdown语法说明
这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…...
推荐一款专业电脑护眼工具:CareUEyes Pro
CareUEyes Pro是一款非常好用的专业电脑护眼工具,软件小巧,界面简单,它可以自动过滤电脑屏幕的蓝光,让屏幕显示更加的不伤眼,更加舒适,有效保护你的眼睛,可以自定义调节屏幕的色调,从…...
对subprocess启动的子进程使用VSCode python debugger
文章目录 1 情况概要(和文件结构)2 具体设置和启动步骤2.1 具体配置Step 1 针对attach debugger到子进程Step 2 针对子进程的暂停(可选) Step 3 判断哪个进程id是需要的子进程 2.2 启动步骤和过程 3 其他问题解决3.13.2 ptrace: Operation not permitted…...
Django启用国际化支持(2)—实现界面内切换语言:activate()
文章目录 ⭐注意⭐1. 配置项目全局设置:启用国际化2. 编写视图函数3. 配置路由4. 界面演示5、扩展自动识别并切换到当前语言设置语言并保存到Session设置语言并保存到 Cookie ⭐注意⭐ 以下操作依赖于 Django 项目的国际化支持。如果你不清楚如何启用国际化功能&am…...
基于单片机的多功能跑步机控制系统
本设计基于单片机的一种多功能跑步机控制系统。该系统以STM32单片机为主控制器,由七个电路模块组成,分别是:单片机模块、电机控制模块、心率检测模块、音乐播放模块、液晶显示模块、语音控制模块、电源模块。其中,单片机模块是整个…...
VSCode 如何选中包含某个字母的所有行
文章目录 写在前面一、需求描述二、解决方法参考链接 写在前面 自己的测试环境:VSCode 一、需求描述 由于需要处理文件,需求是删除文件中包含某个字母的所有行。 二、解决方法 在 Visual Studio Code (VSCode) 中,如果你想选中所有包含某…...
CSRF保护--laravel进阶篇
laravel对csrf非常重视,专门针对csrf作出了很多的保护。如果您是刚刚接触laravel的路由不久,那么您可能对于web.php路由文件的post请求很疑惑,因为get请求很顺利,而post请求则可能会遭遇失败。其中一个失败的原因是由于laravel的c…...
计算机网络-理论部分(二):应用层
网络应用体系结构 Client-Server客户-服务器体系结构:如Web,FTP,Telnet等Peer-Peer:点对点P2P结构,如BitTorrent 应用层协议定义了: 交换的报文类型,请求or响应报文类型的语法字段的含义如何…...
k8s1.31版本最新版本集群使用容器镜像仓库Harbor
虚拟机 rocky9.4 linux master node01 node02 已部署k8s集群版本 1.31 方法 一 使用容器部署harbor (1) wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo yum -y install docker-ce systemctl enable docker…...
QT中使用json格式存取矩阵数据
在 Qt 中,可以通过 QJsonDocument 和 QJsonArray 方便地存取 JSON 格式的矩阵数据。以下是存储和读取矩阵数据的完整实现示例。 1. 矩阵存储为 JSON 将矩阵(QVector<QVector<double>> 或其他二维数组)存储为 JSON 文件。 实现代码 #include <QJsonArray&g…...
k8s 集群安装
安装rockylinux https://www.jianshu.com/p/a5fe20318b8e https://www.cnblogs.com/haoee/p/18290506 配置VirtualBox双网卡 https://www.cnblogs.com/ShineLeBlog/p/17580311.html https://zhuanlan.zhihu.com/p/341328334 https://blog.csdn.net/qq_36544785/article/deta…...
Elasticsearch面试内容整理-核心概念与数据模型
在 Elasticsearch 中,理解核心概念与数据模型是非常重要的,因为它们定义了数据如何被组织、存储和搜索。以下是 Elasticsearch 的核心概念和数据模型的详细介绍。 核心概念 集群(Cluster) ● 集群是由一个或多个节点组成的,用于共同存储和搜索数据的集合。...
Spring Boot实现License生成和校验
Spring Boot实现License生成和校验 证书准备 # 1. 生成私钥库 # validity:私钥的有效期(天) # alias:私钥别称 # keystore:私钥库文件名称(生成在当前目录) # storepass:私钥库密码…...
es写入磁盘的过程以及相关优化
数据写入到内存buffer同时写入到数据到translog buffer,这是为了防止数据不会丢失每隔1s数据从buffer中refresh到FileSystemCache中,生成segment文件,这是因为写入磁盘的过程相对耗时,借助FileSystemCache,一旦生成segment文件,就能通过索引查询到了refresh完,memory bu…...
十大网络安全事件
一、私有云平台遭攻击,美国数千家公司工资难以发放 1月,专门提供劳动力与人力资本管理解决方案的美国克罗诺斯(Kronos)公司私有云平台遭勒索软件攻击,事件造成的混乱在数百万人中蔓延。 克罗诺斯母公司UKG集团…...
【数据结构】【线性表】栈的基本概念(附c语言源码)
栈的基本概念 讲基本概念还是回到数据结构的三要素:逻辑结构,物理结构和数据运算。 从逻辑结构来讲,栈的各个数据元素之间是通过是一对一的线性连接,因此栈也是属于线性表的一种从物理结构来说,栈可以是顺序存储和顺…...
修改ffmpeg实现https-flv内容加密
目录 1 前言 2 ffmpeg源码修改 2.1 增加头文件 2.2 http上下文增加解密密钥和AVAESCTR结构体 2.3 aes解密上下文初始化 2.4 对http数据部分解密 2.5 http关闭时清理资源 3 ffmpeg使用 1 前言 当前视频拉流已经通过URL鉴权方式来对访客身份进行识别和过滤,但…...
react中useMemo的使用场景
useMemo 是 React 的一个 Hook,用来优化性能,尤其是在计算复杂值时。它会记住(缓存)计算结果,只有在依赖项变化时才重新计算,避免不必要的重复计算。 import React, { useMemo } from react; function Ex…...
焦作网站建设公司排名/网络营销的主要手段和策略
这里我们记录下在实际工作中安装的mysql5.6版本的步骤,在安装过程中会遇到了一些问题,这里我们也记录下来,进行总结吧!! 文章目录1.mysql安装1.1.上传 mysql5.6包到要安装的服务器1.2. 安装mysql服务端1.2.1安装时报错…...
外贸网站建设 如何做/爱站网站长seo综合查询工具
2014年8月1日非常早曾经。悉尼社交媒体专家、战略公司L&A Social Media创办人吉娜雷德尼亚克(Gina Lednyak)就開始关注社交媒体的进化,看着它们的缔造者将其从简单想法变成巨额財富和媒体帝国。社交媒体进化的速度令雷德尼亚克感到惊讶,她预測了社交…...
怎么建设电子商城网站/正在播网球比赛直播
这里说说AutoScaleMode属性的用法: ① None : 禁用自动缩放。(默认时) ② Font :根据类使用的字体(通常为系统字体)的维度控制缩放。 如果希望控件或窗体根据操作系统中字体的大小进行拉伸或缩小,则按 Font…...
上海网站建设选缘魁/长沙网站seo报价
这个问题是因为您的zsh配置使用了某些不安全的目录或文件。为了解决这个问题,您可以执行以下步骤: 打开终端并输入以下命令: compaudit 这个命令会列出所有不安全的目录和文件,其中一些可能需要更改权限。 修复不安全的目录和…...
什么网站设计素材多/南京网站快速排名提升
刚开始学习jquery,可能一时会分不清楚哪些是jQuery对象,哪些是DOM对象。至于DOM对象不多解释,我们接触的太多了,下面重点介绍一下jQuery,以及两者相互间的转换。 什么是jQuery对象? ---就是通过jQuery包装D…...
上海做网站的月薪/seo全网营销的方式
比较小众的技术点,准备用来搞项目开发用的,一般不直接对外开放哈!纯属笔记类。可忽略的。。。 NFC 近场通信(Near Field Communication,简称NFC),是一种新兴的技术,使用了NFC技术的设备(例如移动电话)可以在彼此靠近的情况下进行数据交换,是由非接触式射频识别(R…...