• 【正点原子STM32连载】 第三十一章 睡眠模式实验 摘自【正点原子】APM32F407最小系统板使用指南


    1)实验平台:正点原子stm32f103战舰开发板V4
    2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
    3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html#

    第三十一章 睡眠模式实验

    本章介绍APM32F407低功耗模式中的睡眠模式,通过调用WFI命令进入睡眠模式后,ARM Corten-M4内核将停止以降低功耗,在该睡眠模式下可以被任意中断唤醒。通过本章的学习,读者将学习到低功耗模式中睡眠模式的使用。
    本章分为如下几个小节:
    31.1 硬件设计
    31.2 程序设计
    31.3 下载验证

    31.1 硬件设计
    31.1.1 例程功能

    1. 按下KEY0按键,点亮LED1并进入睡眠模式,按下KEY_UP按键,退出睡眠模式并熄灭LED1
    2. LED0闪烁,指示程序正在运行
      31.1.2 硬件资源
    3. LED
      LED0 - PF9
      LED1 - PF10
    4. 按键
      KEY0 - PE4
      KEY_UP - PA0
    5. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
      31.1.3 原理图
      本章实验介绍APM32F407低功耗模式中的睡眠模式,不涉及连接原理图。
      31.2 程序设计
      31.2.1 PMU驱动
      本章实验的PMU驱动主要负责向应用层提供睡眠模式唤醒按键的初始化和进入睡眠模式的函数,同时实现唤醒按键的中断回调函数。本章实验中,PMU的驱动代码包括pmu.c和pmu.h两个文件。
      PMU驱动中,睡眠模式唤醒按键的相关宏定义,如下所示:
    #define PMU_WKUP_GPIO_PORT		GPIOA
    #define PMU_WKUP_GPIO_PIN		GPIO_PIN_0
    #define PMU_WKUP_GPIO_CLK_ENABLE()							\
        do {														\
        		RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);	\
        } while (0)
    #define PMU_WKUP_SYSCFG_PORT	SYSCFG_PORT_GPIOA
    #define PMU_WKUP_SYSCFG_PIN		SYSCFG_PIN_0
    #define PMU_WKUP_EINT_LINE		EINT_LINE_0
    #define PMU_WKUP_INT_IRQn		EINT0_IRQn
    #define PMU_WKUP_INT_IRQHandler	EINT0_IRQHandler
    PMU驱动中,睡眠模式唤醒按键的初始化函数,如下所示:
    /**
     * @brief	初始化唤醒按键
     * @param	无
     * @retval	无
     */
    void pmu_wkup_key_init(void)
    {
        GPIO_Config_T gpio_init_struct;
        EINT_Config_T eint_init_struct;
        
        PMU_WKUP_GPIO_CLK_ENABLE();							/* 使能唤醒引脚端口时钟 */
        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);	/* 使能SYSCFG时钟 */
        
        gpio_init_struct.pin	= PMU_WKUP_GPIO_PIN;		/* 唤醒引脚 */
        gpio_init_struct.mode	= GPIO_MODE_IN;				/* 输入模式 */
        gpio_init_struct.pupd	= GPIO_PUPD_DOWN;			/* 下拉 */
        GPIO_Config(PMU_WKUP_GPIO_PORT, &gpio_init_struct);	/* 配置唤醒引脚 */
        
        /* 配置引脚作为事件线 */
        SYSCFG_ConfigEINTLine(SYSCFG_PORT_GPIOA, PMU_WKUP_SYSCFG_PIN);
        
        eint_init_struct.line		= PMU_WKUP_EINT_LINE;	/* EINT线 */
        eint_init_struct.mode		= EINT_MODE_INTERRUPT;	/* 中断模式 */
        eint_init_struct.trigger	= EINT_TRIGGER_RISING;	/* 上升沿 */
        eint_init_struct.lineCmd	= ENABLE;				/* 使能 */
        EINT_Config(&eint_init_struct);						/* 配置EINT */
        NVIC_EnableIRQRequest(PMU_WKUP_INT_IRQn, 2, 0);		/* 使能中断 */
    }
    因为调用WFI命令进入睡眠模式后,能够被任意的中断唤醒,因此睡眠模式唤醒按键的初始化只需要配置好按键的外部中断即可。
    PMU驱动中,睡眠模式唤醒按键对应的中断回调函数,如下所示:
    /**
     * @brief	唤醒引脚外部中断服务函数
     * @param	无
     * @retval	无
     */
    void PMU_WKUP_INT_IRQHandler(void)
    {
        /* 判断唤醒引脚事件线中断标志 */
        if (EINT_ReadIntFlag((EINT_LINE_T)PMU_WKUP_GPIO_PIN) == SET)
        {
        		/* 清除唤醒引脚事件线中断标志 */
        		EINT_ClearIntFlag((EINT_LINE_T)PMU_WKUP_GPIO_PIN);
        }
    }
    因为睡眠唤醒按键的中断只是为了唤醒睡眠模式,因此并不需要在中断回调函数中做任何处理。
    PMU驱动中,进入睡眠模式的函数,如下所示:
    /**
     * @brief	进入睡眠模式
     * @param	无
     * @retval	无
     */
    void pmu_enter_sleep(void)
    {
        /* 指令WFI,进入睡眠模式,等待任意中断唤醒 */
        __WFI();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    从上面的代码中可以看出,进入睡眠模式主要就是执行WFI命令,接下来MCU便会进入睡眠模式,等待任意的中断唤醒,因此在执行WFI命令之前,需要先关闭部分中断,以免误唤醒。
    31.2.2 实验应用代码
    本章实验的应用代码,如下所示:

    int main(void)
    {
        uint8_t key;
        uint8_t t = 0;
        
        NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_3);	/* 设置中断优先级分组为组3 */
        sys_apm32_clock_init(336, 8, 2, 7);					/* 配置系统时钟 */
        delay_init(168);										/* 初始化延时功能 */
        usart_init(115200);									/* 初始化串口 */
        led_init();											/* 初始化LED */
        key_init();											/* 初始化按键 */
        lcd_init();											/* 初始化LCD */
        pmu_wkup_key_init();								/* 初始化唤醒按键 */
        
        lcd_show_string(30, 50, 200, 16, 16, "APM32", RED);
        lcd_show_string(30, 70, 200, 16, 16, "SLEEP TEST", RED);
        lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
        lcd_show_string(30, 110, 200, 16, 16, "KEY0:Enter SLEEP MODE", RED);
        lcd_show_string(30, 130, 200, 16, 16, "KEY_UP:Exit SLEEP MODE", RED);
        
        while (1)
        {
        		key = key_scan(0);
        		
        		if (key == KEY0_PRES)
        		{
        			LED1(0);			/* 点亮LED1,提示进入睡眠模式 */
        			pmu_enter_sleep();	/* 进入睡眠模式 */
        			LED1(1);			/* 熄灭LED1,提示退出睡眠模式 */
        		}
        		
        		if ((t % 20) == 0)
        		{
        			LED0_TOGGLE();
        		}
        		
        		t++;
        		delay_ms(10);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    从上面的代码中可以看出,在完成相关的初始化操作后,并不断地扫描按键,若扫描到KEY0按键被按下,则会点亮LED1后进入睡眠模式,此时ARM Cortex-M4内核便停止了,从该睡眠模式唤醒需要有任意的中断产生,因此可以由KEY_UP按键产生外部中断来唤醒睡眠。退出睡眠模式后,LED1将被熄灭。
    31.3 下载验证
    在完成编译和烧录操作后,可以看到LED0闪烁提示系统程序正在运行,此时可以按下KEY0按键,可以看到LED1亮起,但LED0不再闪烁,这是因为系统已经进入睡眠模式了,此时再按下KEY_UP按键,即可从睡眠模式下唤醒,可以看到LED1熄灭,LED0继续闪烁。

  • 相关阅读:
    51单片机 数码管操作
    Linux——常用命令(2)
    DJango 学习(2)—— django引入:借助于wsgiref模块(web服务网关接口)搭建简易 web 框架
    [mysql]游标和触发器
    LocalDateTime、LocalDate、Date、String相互转化大全及其注意事项
    c单元语言测试--自定义代码、rspec 和Google test
    AOP 面向切面编程
    程序员怎样才能写出一篇好的博客或者技术文章?
    axios在vue3.x中的基础入门使用
    数据结构——常见链表算法题
  • 原文地址:https://blog.csdn.net/weixin_55796564/article/details/132827266