STM32低功耗实验:学习日记与心得分享

STM32低功耗实验学习日记

写于2024/9/25晚

文章目录

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

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

    2. STM32F1电源系统

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

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

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

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

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

    2.1 电源系统

    image-20240925220620902

    在电源概述框图中我们划分了 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 处于运行状态时,当内核不需要继续运行,就可以选择进入后面的三种模式降低功耗。

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

    image-20240925221804613

    2.2.1 睡眠模式

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

    image-20240925222025162

    image-20240926215958124

    2.2.2 停止模式

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

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

    image-20240926220653052

    image-20240926220842031

    2.2.3 待机模式

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

    image-20240926220950578

    image-20240926221020206

    image-20240926221116457

    2.3 相关寄存器介绍

    2.3.1 系统控制寄存器(SCB_SCR)

    image-20240926221315109

    2.3.2 电源控制寄存器(PWR_CR)

    image-20240926221441770

    2.3.3 电源控制/状态寄存器(PWR_CSR)

    image-20240926222647713

    2.3.4 WFI与WFE指令

    image-20240926222930635

    内核指令,使用函数的格式__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. 进入低功耗模式的使用步骤

    image-20240926223519705

    image-20240926223555882

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

    image-20240926223650224

    待机模式配置步骤

    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 使能电源时钟
    #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++;
        
        }
    }
    
    
    

    作者:dianfu233

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32低功耗实验:学习日记与心得分享

    发表回复