STM32低功耗实验学习日记

STM32低功耗实验学习日记

写于2024/9/25晚

文章目录

  • STM32低功耗实验学习日记
    • [1. 简介](#1. 简介)
    • [2. STM32F1电源系统](#2. STM32F1电源系统)
      • [2.1 电源系统](#2.1 电源系统)
      • [2.2 电源管理](#2.2 电源管理)
        • [2.2.1 睡眠模式](#2.2.1 睡眠模式)
        • [2.2.2 停止模式](#2.2.2 停止模式)
        • [2.2.3 待机模式](#2.2.3 待机模式)
      • [2.3 相关寄存器介绍](#2.3 相关寄存器介绍)
        • [2.3.1 系统控制寄存器(SCB_SCR)](#2.3.1 系统控制寄存器(SCB_SCR))
        • [2.3.2 电源控制寄存器(PWR_CR)](#2.3.2 电源控制寄存器(PWR_CR))
        • [2.3.3 电源控制/状态寄存器(PWR_CSR)](#2.3.3 电源控制/状态寄存器(PWR_CSR))
        • [2.3.4 WFI与WFE指令](#2.3.4 WFI与WFE指令)
    • [3. 进入低功耗模式的使用步骤](#3. 进入低功耗模式的使用步骤)
    • [4. 代码解析](#4. 代码解析)

1. 简介

我们将介绍 STM32F103 的电源控制(PWR),并实现低功耗模式相关功能。我们将通过四个实验来学习并实现低功耗相关功能,分别是 PVD 电压监控实验、睡眠模式实验、停止模式实验和待机模式实验

2. STM32F1电源系统

电源控制部分(PWR)概述了不同电源域的电源架构以及电源配置控制器。PWR 的内容比较多,我们把它们的主要特性概括为以下 3 点:

  • 电源系统:VDDA供电区域、VDD供电区域、1.8V 供电区域、后备供电区域。

  • 电源监控:POR/PDR 监控器、PVD 监控器。

  • 电源管理:低功耗模式。

下面将分别对这 3 个特性进行简单介绍。

2.1 电源系统

在电源概述框图中我们划分了 3 个区域①②③,分别是独立的 A/D 转换器供电和参考电压、电压调节器、电池备份区域。下面分别进行简单介绍:

① 独立的 A/D转换器供电和参考电压(VDDA供电区域)

VDDA 供电区域,主要是 ADC 电源以及参考电压,STM32 的 ADC 模块配备独立的供电方式,使用了 VDDA 引脚作为输入 ,使用 VSSA 引脚作为独立地连接VREF 引脚为提供给 ADC 的参考电压

② 电压调节器(VDD /1.8V供电区域)

电压调节器是 STM32 的电源系统中最核心部分,连接 VDD供电区域1.8 V供电区域 。VDD供电来自于 VSS 和 VDD ,给 I/O 电路 以及待机电路 供电,电压调节器主要为备份域 以及待机电路以外的所有数字电路 供电,其中包括内核、数字外设以及RAM,调节器的输出电压约为1.8V,因此由调压器供电的区域称为 1.8V 供电区域 。电压调节器根据应用方式不同有三种不同的工作模式 。在运行模式 下,调节器以正常工作模式为内核、内存和外设提供 1.8V;在停止模式 下,调节器以低功耗模式提供 1.8V 电源,以保存寄存器和 SRAM 的内容。在待机模式下,调节器停止供电,除了备用电路和备份域外,寄存器和 SRAM 的内容全部丢失。

③ 电池备份区域(后备供电区域)

电池备份区域也就是后备供电区域 ,使用电池或者其他电源连接到 VBAT脚上,当 VDD断电时,可以保存备份寄存器的内容维持 RTC 的功能 。同时 VBAT 引脚也为 RTCLSE 振荡器供电,这保证了当主要电源被切断时,RTC 能够继续工作。切换到 VBAT 供电由复位模块中的掉电复位功能控制。

2.2 电源管理

电源管理的部分我们要关注低功耗模式,在 STM32 的正常工作中,具有四种工作模式,运行、睡眠、停止以及待机。在上电复位后,STM32 处于运行状态时,当内核不需要继续运行,就可以选择进入后面的三种模式降低功耗。

这三种低功耗模式电源消耗不同、唤醒时间不同和唤醒源不同,我们要根据自身的需要选择合适的低功耗模式。下面是低功耗模式汇总介绍,如下表所示。

2.2.1 睡眠模式

进入睡眠模式,Cortex_M3 内核停止,所有外设包括 Cortex_M3 核心的外设,如 NVIC、系统时钟(SysTick)等仍在运行,有两种进入睡眠模式的模式 WFI 和 WFE。WFI(Wait for interrupt等待中断)和 WFE(Wait for event等待事件)是内核指令,会调用一些汇编指令,会使用即可。睡眠后唤醒的方式即由等待"中断"唤醒和"事件"唤醒。

2.2.2 停止模式

进入停止模式,所有的时钟都关闭,所有的外设也就停止了工作。但是 VDD电源是没有关闭的,所以内核的寄存器和内存信息都保留下来,等待重新开启时钟就可以从上次停止的地方继续执行程序。

值得注意的是:当电压调节器处于低功耗模式下,当系统从停止模式退出时,将会有一段额外的启动延时。如果在停止模式期间保持内部调节器开启,则退出启动时间会缩短,但相应的功耗会增加。

2.2.3 待机模式

待机模式可实现最低功耗。该模式是在 CM3 深睡眠模式时关闭电压调节器,整个 1.8V 供电区域被断电。PLL、HSI 和 HSE 振荡器也被断电。除备份域(RTC 寄存器、RTC 备份寄存器和备份 SRAM)和待机电路中的寄存器外,SRAM 和其他寄存器内容都将丢失。不过如果我们使能了备份区域(备份 SRAM、RTC、LSE),那么待机模式下的功耗,将达到 3.8uA 左右。

2.3 相关寄存器介绍

2.3.1 系统控制寄存器(SCB_SCR)
2.3.2 电源控制寄存器(PWR_CR)
2.3.3 电源控制/状态寄存器(PWR_CSR)
2.3.4 WFI与WFE指令

内核指令,使用函数的格式__WFI()__WFE()来调用。__wfi__wfe是编译器内置的函数,函数内部调用了相对应的汇编指令。

驱动函数 关联寄存器 功能描述
HAL_PWR_EnterSLEEPMode(...) SCB_SCR 进入睡眠模式
HAL_PWR_EnterSTOPMode(...) PWR_CR/SCB_SCR 进入停止模式
HAL_PWR_EnterSTANDBYMode(...) PWR_CR/SCB_SCR 进入待机模式
HAL_PWR_EnableWakeUpPin(...) PWR_CSR 使能WKUP管脚唤醒功能
__HAL_PWR_CLEAR_FLAG(...) PWR_CR 清除PWR的相关标记
__HAL_RCC_PWR_CLK_ENABLE(...) RCC_APB1ENR 使能电源时钟

3. 进入低功耗模式的使用步骤

在退出停止模式后,需要重新设置时钟、重新选择滴答时钟源、失能systick中断

待机模式配置步骤

  1. 初始化WKUP为中断触发源
  2. 使能电源时钟:__HAL_RCC_PWR_CLK_ENABLE
  3. 使能WKUP的唤醒功能:HAL_PWR_EnableWakeUpPin
  4. 清除唤醒标记WUF:__HAL_PWR_CLEAR_FLAG
  5. 进入待机模式:HAL_PWR_EnterSTANDBYMode

4. 代码解析

驱动函数 关联寄存器 功能描述
HAL_PWR_EnterSLEEPMode(...) SCB_SCR 进入睡眠模式
HAL_PWR_EnterSTOPMode(...) PWR_CR/SCB_SCR 进入停止模式
HAL_PWR_EnterSTANDBYMode(...) PWR_CR/SCB_SCR 进入待机模式
HAL_PWR_EnableWakeUpPin(...) PWR_CSR 使能WKUP管脚唤醒功能
__HAL_PWR_CLEAR_FLAG(...) PWR_CR 清除PWR的相关标记
__HAL_RCC_PWR_CLK_ENABLE(...) RCC_APB1ENR 使能电源时钟
c 复制代码
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/BEEP/beep.h"
#include "./BSP/KEY/key.h"
#include "./BSP/PWR/pwr.h"



void pwr_wkup_key_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    
    PWR_WKUP_GPIO_CLK_ENABLE();                             /* WKUP引脚时钟使能 */

    gpio_init_struct.Pin = PWR_WKUP_GPIO_PIN;               /* WKUP引脚 */
    gpio_init_struct.Mode = GPIO_MODE_IT_RISING;            /* 中断,上升沿 */
    gpio_init_struct.Pull = GPIO_PULLDOWN;                  /* 下拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
    HAL_GPIO_Init(PWR_WKUP_GPIO_PORT, &gpio_init_struct);   /* WKUP引脚初始化 */

    HAL_NVIC_SetPriority(PWR_WKUP_INT_IRQn, 2, 2);          /* 抢占优先级2,子优先级2 */
    HAL_NVIC_EnableIRQ(PWR_WKUP_INT_IRQn); 
}

void PWR_WKUP_INT_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(PWR_WKUP_GPIO_PIN);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == PWR_WKUP_GPIO_PIN)
    {
        /* HAL_GPIO_EXTI_IRQHandler()函数已经为我们清除了中断标志位,所以我们进了回调函数可以不做任何事 */
    }
}


int main(void)
{
    uint8_t key;
    uint8_t t = 0;
    
    HAL_Init();                             /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    delay_init(72);                         /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化 */
    led_init();                             /* 初始化LED */
    key_init();                             /* 初始化按键 */
    pwr_wkup_key_init();                    /* WKUP引脚初始化 */
    pwr_pvd_init();                         /* PVD配置 */
    
    printf("Enter to LowPower Test \r\n");
    
    while(1)
    {
        key = key_scan(0);                  /* 得到键值 */

        if (key)
        {
            switch (key)
            {
                /* 进入待机模式 */
                case KEY2_PRES:
                
                    /* 使能电源时钟 */
                    __HAL_RCC_PWR_CLK_ENABLE();
                
                    /* 使能WKUP上升沿的唤醒功能 */
                    HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
                
                    /* 清除唤醒标记 */
                    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
                
                    printf("Enter STANDBY Mode \r\n");
                    
                    HAL_PWR_EnterSTANDBYMode();
                
                    printf("Exit STANDBY Mode \r\n");

                    break;

                /* 进入停止模式 */
                case KEY1_PRES:
                    
                    LED1(0);        /* 点亮绿灯,提示进入停止模式 */
                    
                    printf("Enter STOP Mode \r\n");
                    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
                    
                    sys_stm32_clock_init(RCC_PLL_MUL9);     /* 重新设置时钟, 72Mhz */
                    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);
                    HAL_SuspendTick();
                
                    printf("Exit STOP Mode \r\n");
                
                    LED1(1);
                    break;
                
                /* 进入睡眠模式 */
                case KEY0_PRES:
                    
                    printf("Enter SLEEP Mode \r\n");
                    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
                    printf("Exit SLEEP Mode \r\n");
                
                    break;
            } 
        }
        
        if ((t % 20) == 0)
        {
            LED0_TOGGLE();              /* 每200ms,翻转一次LED0 */
        }

        delay_ms(10);
        t++;
    
    }
}
相关推荐
@小博的博客18 分钟前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
南宫生1 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
scan12 小时前
单片机串口接收状态机STM32
stm32·单片机·串口·51·串口接收
懒惰才能让科技进步2 小时前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝
love_and_hope2 小时前
Pytorch学习--神经网络--搭建小实战(手撕CIFAR 10 model structure)和 Sequential 的使用
人工智能·pytorch·python·深度学习·学习
Chef_Chen2 小时前
从0开始学习机器学习--Day14--如何优化神经网络的代价函数
神经网络·学习·机器学习
芊寻(嵌入式)2 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
Qingniu012 小时前
【青牛科技】应用方案 | RTC实时时钟芯片D8563和D1302
科技·单片机·嵌入式硬件·实时音视频·安防·工控·储能
hong1616883 小时前
跨模态对齐与跨领域学习
学习
Mortal_hhh3 小时前
VScode的C/C++点击转到定义,不是跳转定义而是跳转声明怎么办?(内附详细做法)
ide·vscode·stm32·编辑器