PMU电源域与节能模式:ARM32架构下的功耗管理实践(下)

     具体原理可以看我的上一篇

硬件准备

我们的硬件平台是基于GD32F4xx微控制器的开发板,该微控制器支持多种电源管理模式。我们将使用以下硬件资源:

  • LED连接到PB2引脚:用于闪烁指示。
  • 串口:通过串口切换 省电模式
  • 外部中断引脚: 为KEY2配置外部中断按键,按下时LED1自动切换开关

代码实现

1. 引入必要的头文件

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "USART0.h"
#include "EXTI.h"

这些头文件包含了必要的库和定义,用于访问GPIO、系统时钟、中断等硬件资源。

2. 任务目标

我们的目标是:

  • 让LED(连接在PB2引脚)闪烁。
  • 通过接收串口消息进入不同的节能模式:
    • 0x00:睡眠模式(任意中断可唤醒)
    • 0x01:深度睡眠模式(EXTI外部中断可唤醒)
    • 0x02:待机模式(4个特殊唤醒方式)

3. 实现节能模式

睡眠模式
void sleep_mode(){
	// RCU -------------------
	rcu_periph_clock_enable(RCU_PMU);
	
	printf("sleep_mode:1\n");
	
	// 进入睡眠模式
	pmu_to_sleepmode(WFI_CMD);
	// 唤醒中断的抢占优先级要比串口高才能唤醒
	// 因为此代码目前阻塞在串口的中断函数里
	
	printf("sleep_mode:2\n");
}

此函数使能PMU时钟,并调用pmu_to_sleepmode()进入睡眠模式。通过WFI_CMD指令等待中断唤醒。

深度睡眠模式
// 深度睡眠模式
void deep_sleep_mode(){
	
	rcu_periph_clock_enable(RCU_PMU);
	
	printf("deep_sleep_mode:1\n");
	// 进入深度睡眠模式
	pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, PMU_LOWDRIVER_ENABLE, WFI_CMD);
	
	// 把主频设置回来
	SystemInit();
	
	printf("deep_sleep_mode:2\n");
}

此函数使能PMU时钟,并调用pmu_to_deepsleepmode()进入深度睡眠模式。通过WFI_CMD指令等待中断唤醒,并在退出深度睡眠后重置系统时钟。

待机模式
// 待机模式
void standby_mode(){
	rcu_periph_clock_enable(RCU_PMU);
	
	/* 清理待机模式标记 */
	pmu_flag_clear(PMU_FLAG_RESET_STANDBY);
	
	/* 启用唤醒按钮 */
	pmu_wakeup_pin_enable();
	
	printf("standby mode:1\n");
	
	/* 进入待机模式 */
	pmu_to_standbymode();
	
	printf("standby mode:2\n");
	
}

此函数使能PMU时钟,清除待机模式标记,并启用唤醒引脚。调用pmu_to_standbymode()进入待机模式。

4. 外部中断处理

void EXTI_1_on_trig(){
    printf("EXTI_1\n");
}

此函数处理外部中断事件,当外部中断触发时,打印一条消息。

5. 串口接收处理

void USART0_on_recv(uint8_t* buffer, uint32_t len) {
    printf("recv[%d]-> %s\n", len, buffer);
    switch (buffer[0]) {
        case 0x00:
            sleep_mode();
            break;
        case 0x01:
            deep_sleep_mode();
            break;
        case 0x02:
            standby_mode();
            break;
        default:
            break;
    }
}

此函数处理接收到的串口数据,并根据接收到的命令字节调用相应的节能模式函数。

6. GPIO配置

static void GPIO_config(rcu_periph_enum rcu, uint32_t port, uint32_t pin) {
    rcu_periph_clock_enable(rcu);
    gpio_mode_set(port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, pin);
    gpio_output_options_set(port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, pin);
    gpio_bit_write(port, pin, RESET);
}

此函数用于配置GPIO引脚为输出模式,并设置默认输出电平为低电平。

7. 延时函数

void delay(){
    uint32_t i = 20000000;
    while(i--) __NOP();
}

此函数通过循环计数来实现延时效果。

8. 主函数

int main(void) {
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
    // systick_config();
    EXTI_init();
    USART0_init();
    printf("init\n");
    GPIO_config(RCU_GPIOB, GPIOB, GPIO_PIN_2);
    while(1) {
        gpio_bit_toggle(GPIOB, GPIO_PIN_2);
        // delay_1ms(500);
        delay();
    }
}

主函数初始化了NVIC优先级组、外部中断、串口,并配置了LED对应的GPIO引脚。然后进入一个无限循环,不断切换LED的状态,并调用延时函数来实现500毫秒的闪烁周期。

注意事项

在中断优先级配置为NVIC_PRIGROUP_PRE2_SUB2的情况下:

  1. 串口中断优先级

    • 串口中断的抢占优先级不能设置为0,否则系统可能无法正常进入睡眠模式,或者在睡眠模式下无法被正确唤醒。
  2. 深度睡眠模式下的外部中断优先级

    • 深度睡眠模式下的外部中断的抢占优先级需要设置为0或1(比串口中断的抢占优先级高),否则系统可能无法通过外部中断正确唤醒。

结论

通过上述代码,我们实现了基于GD32F4xx的嵌入式系统中的LED闪烁功能,并通过串口命令切换到了不同的节能模式。此外,还展示了如何通过外部中断唤醒系统。这些功能在实际应用中非常有用,尤其是在需要长期运行且功耗敏感的设备中

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值