电源管理
实验目的
- 掌握STM32电源管理实现降低功耗的有效方法及原理。
- 掌握STM32三种低功耗模式进入和退出的方法、区别及相关程序设计。
实验内容
- 编写程序观察进入待机模式后如何退出待机模式。编写程序观察进入停止模式后如何退出停止模式。编写程序观察进入睡眠模式后如何退出睡眠模式。
电源管理原理介绍
STM32时钟树介绍
时钟系统是处理器的核心,在学习STM32F103系列MCU过程中,时钟系统的熟练掌握会有助于对很多知识点的学习。
STM32F103系列MCU中,有五个时钟源,分别为HSI、HSE、LSI、LSE和PLL。
- HSI是高速内部时钟,RC振荡器,频率为8MHz。HSE是高速外部时钟,接外部时钟源,频率范围为4MHz~16MHz。LSI是低速内部时钟,RC振荡器,频率为40KHz。LSE是低速外部时钟,接外部时钟源,频率为32.768kHz晶振。PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
- 注:因PLL时钟源也是由HSI或HSE提供的,所以也有说法STM32F103系列MCU的时钟源是四个,即HSI、HSE、LSI和LSE。
STM32F103系列MCU时钟系统有个非常形象的称呼叫“时钟树”,这个 “时钟树”非常直观和清晰地诠释出各时钟之间的关系、各个外设的时钟来源以及需要注意的配置事项。下图即是STM32F103系列MCU时钟树的示意图。
图1:STM32时钟树示意图
- 注:能为系统时钟SYSCLK提供时钟源的只有HSI、HSE和PLL。使用HSI内部8MHZ的RC振荡器可以省下外部晶振电路,但该振荡器精度有限,通常HSI精度比使用HSE差十倍以上。所以我们一般是选择使用外部晶振给PLL提供时钟源,再对PLL进行倍频后给系统时钟提供时钟源。
STM32低功耗模式
STM32F103系列MCU在系统或电源复位以后,微控制器处于运行状态。当CPU不需要继续运行时,可以利用多种低功耗模式来节省功耗,针对STM32F103系列MCU,有三种低功耗模式:待机模式、停止模式和睡眠模式。
另外,还可以通过降低系统时钟、关闭APB和AHB总线上未被使用的外设时钟等方法来降低功耗。比如:将GPIO设置为输出模式,其最大速度设置为2MHz要比最大速度设置50MHz要省电。
关于STM32F103系列MCU三种低功耗模式一览表如下:
表1:三种低功耗模式
- 注:STM32L1系列MCU采用ST专有的超低泄漏制程,具有创新型自主动态电压调节功能和5种低功耗模式,为各种应用提供了无与伦比的平台灵活性。STM32L1系列MCU扩展了超低功耗的理念,并且不会牺牲性能。
STM32F103系列待机模式
STM32F103系列MCU的待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。
- 如何进入待机模式?
需要进行下面3个步骤。
1、设置Cortex-M3系统控制寄存器中的SLEEPDEEP位。
2、设置电源控制寄存器(PWR_CR)中的PDDS位。
3、清除电源控制/状态寄存器(PWR_CSR)中的WUF位。
- 注:用户在实际使用时只需调用库函数void PWR_EnterSTANDBYMode(void)即可进入待机模式。无需关注程序是如何操作相关寄存器控制进入待机模式的,这也是使用库函数相对于操作寄存器的一大优势。
- 如何退出待机模式?
下列任何一种都可唤醒待机模式的MCU。
1、WKUP引脚的上升沿。
2、RTC闹钟事件的上升沿。
3、NRST引脚上外部复位。
4、IWDG复位。
- 注:例程会演示使用WKUP引脚(PA0)的上升沿和NRST引脚上外部复位。
- 在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
1、复位引脚(始终有效)。
2、当被设置为防侵入或校准输出时的TAMPER引脚。
3、被使能的唤醒引脚。
STM32F103系列停止模式
STM32F103系列MCU的停止模式是在Cortex-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止,PLL、HSI和HSE RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
- 如何进入停止模式?
在以下条件下执行WFI(等待中断)或WFE(等待事件)指令:
1、设置Cortex-M3系统控制寄存器中的SLEEPDEEP位。
2、清除电源控制寄存器(PWR_CR)中的PDDS位。
3、通过设置PWR_CR中LPDS位选择电压调节器的模式。
- 注:用户在实际使用时只需调用库函数void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)即可进入停止模式。
- 如何退出停止模式?
1、如果执行WFI进入停止模式:
设置任一外部中断线为中断模式(在NVIC中必须使能相应的外部中断向量)。
2、如果执行WFE进入停止模式:
设置任一外部中断线为事件模式。
- 注:例程会演示外部中断线为中断模式退出停止模式。
- 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
STM32F103系列睡眠模式
STM32F103系列MCU的睡眠模式是三种低功耗模式中最耗电的。STM32F103系列MCU的睡眠模式下,电压调节器是打开的,只有CPU时钟是关闭的,其他时钟都是打开的。
- 如何进入睡眠模式?
按照下列任何一种操作均可进入睡眠模式:
1、执行WFI指令进入睡眠状态。
2、执行WFE指令进入睡眠状态。
- 注:用户在实际使用时只需调用__WFI()或__WFE()即可进入睡眠模式。
- 如何退出睡眠模式?
1、执行WFI进入睡眠模式后需任一中断去唤醒。
2、执行WFE进入睡眠模式后需唤醒事件去唤醒。
- 注:例程会演示外部中断去退出睡眠模式。
- 在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
软件设计
PWR寄存器汇集
STM32F103提供了3个用于操作PWR的寄存器,如下表所示:
表1:PWR相关寄存器
序号 |
寄存器名 |
读/写 |
功能描述 |
1 |
PWR_CR |
读/写 |
电源控制寄存器。 |
2 |
PWR_CSR |
读/写 |
电源控制/状态寄存器。 |
每一种寄存器详细的描述在这里不做具体的介绍,大家可以参考目录:“第1部分:开发板硬件资料”“2 - 芯片资料”中“STM32英文参考手册_V15”或“STM32中文参考手册_V10”对应的PWR章节的寄存器部分认真研读。
PWR库函数汇集
ST官方提供的最终库函数版本是V3.5版本,该版本库函数提供了9个与PWR操作有关的库函数,如下表所示:
表2:PWR相关库函数汇集
序号 |
函数名 |
功能描述 |
1 |
PWR_DeInit |
将外设PWR寄存器重设为缺省值。 |
2 |
PWR_BackupAccessCmd |
使能或者失能RTC和后备寄存器访问。 |
3 |
PWR_PVDCmd |
使能或者失能可编程电压探测器(PVD)。 |
4 |
PWR_PVDLevelConfig |
设置PVD的探测电压阈值。 |
5 |
PWR_WakeUpPinCmd |
使能或者失能唤醒管脚功能。 |
6 |
PWR_EnterSTOPMode |
进入停止(STOP)模式。 |
7 |
PWR_EnterSTANDBYMode |
进入待命(STANDBY)模式。 |
8 |
PWR_GetFlagStatus |
检查指定PWR标志位设置与否。 |
9 |
PWR_ClearFlag |
清除PWR的待处理标志位。 |
其他库函数详细的描述在这里不做具体的介绍,大家可以参考目录:“第1部分:开发板硬件资料”--->“2 - 芯片资料”中“STM32固件库使用手册的中文翻译版”对应的PWR章节的库函数部分认真研读。
STANDBY待机模式实验
- 注:本节的实验源码是在“实验2-1-3:流水灯”的基础上修改。本节对应的实验源码是:“实验2-10-1:STANDBY待机模式”。
工程需要用到的库文件
本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。
表4:实验需要用到的c文件
序号 |
文件名 |
后缀 |
功能描述 |
1 |
stm32f10x_rcc |
.c |
复位与时钟控制器。 |
2 |
stm32f10x_gpio |
.c |
通用输入输出。 |
3 |
stm32f10x_exti |
.c |
外部中断事件控制器。 |
4 |
stm32f10x_pwr |
.c |
电源管理。 |
5 |
misc |
.c |
中断向量控制器。 |
按下图所示将需要的c文件添加到工程。
图5:在新建工程中添加所需库函数c文件
头文件引用和路径设置
- 需要引用的头文件
因为在“main.c”文件中使用了标准库和我们自己建的软件延时函数,所以需要引用下面的头文件。
- #include "stm32f10x.h"
- //delay这里报错的原因是:delay函数用汇编实现的,导致了MDK误报。
- #include "delay.h"
- 需要包含的头文件路径
本例需要包含的头文件路径如下表:
表5:头文件包含路径
序号 |
路径 |
描述 |
1 |
..\\Lib\\F10x_FWLIB\\inc |
标准库头文件路径。 |
2 |
..\\User |
stm32f10x_conf.h头文件在该路径,所以要包含。 |
3 |
..\\User\\bsp |
自建的板卡相关的驱动文件路径。 |
MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。
图6:添加头文件包含路径
编写代码
首先是对4个用户按键对应GPIO的外部中断功能进行配置并设置中断优先级,再分别给每一个中断服务函数设计不同的任务。按键S1的外部中断2对应的中断任务是使能WKUP唤醒引脚并调用函数进入待机模式,按键S2的外部中断3对应的中断任务是控制指示灯D2闪两次,按键S3的外部中断4对应的中断任务是控制指示灯D3闪两次,按键S4的外部中断5对应的中断任务是控制指示灯D4闪两次,具体代码如下。
代码清单:外部中断2中断服务函数
- /******************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- *****************************************************************************/
- void EXTI2_IRQHandler(void)
- {
- PWR_WakeUpPinCmd(ENABLE); //使能WKUP引脚的唤醒功能(PA0引脚)
- PWR_EnterSTANDBYMode(); //进入待机模式
- EXTI_ClearITPendingBit(EXTI_Line2); //清除EXTI中断线路挂起位
- }
代码清单:外部中断3中断服务函数
- /*****************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- ****************************************************************************/
- void EXTI3_IRQHandler(void)
- {
- led_on(LED_2); //点亮指示灯D2
- sw_delay_ms(200); //延时200ms
- led_off(LED_2); //熄灭指示灯D2
- sw_delay_ms(200); //延时200ms
- led_on(LED_2); //点亮指示灯D2
- sw_delay_ms(200); //延时200ms
- led_off(LED_2); //熄灭指示灯D2
- sw_delay_ms(200); //延时200ms
- EXTI_ClearITPendingBit(EXTI_Line3); //清除EXTI中断线路挂起位
- }
代码清单:外部中断4中断服务函数
- /*****************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- ***************************************************************************/
- void EXTI4_IRQHandler(void)
- {
- led_on(LED_3); //点亮指示灯D3
- sw_delay_ms(200); //延时200ms
- led_off(LED_3); //熄灭指示灯D3
- sw_delay_ms(200); //延时200ms
- led_on(LED_3); //点亮指示灯D3
- sw_delay_ms(200); //延时200ms
- led_off(LED_3); //熄灭指示灯D3
- sw_delay_ms(200); //延时200ms
- EXTI_ClearITPendingBit(EXTI_Line4); //清除EXTI中断线路挂起位
- }
代码清单:外部中断5中断服务函数
- /***************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- ***************************************************************************/
- void EXTI9_5_IRQHandler(void)
- {
- led_on(LED_4); //点亮指示灯D4
- sw_delay_ms(200); //延时200ms
- led_off(LED_4); //熄灭指示灯D4
- sw_delay_ms(200); //延时200ms
- led_on(LED_4); //点亮指示灯D4
- sw_delay_ms(200); //延时200ms
- led_off(LED_4); //熄灭指示灯D4
- sw_delay_ms(200); //延时200ms
- EXTI_ClearITPendingBit(EXTI_Line5); //清除EXTI中断线路挂起位
- }
然后主函数中会对各外部中断进行初始化,打开电源管理的时钟,在主循环中是控制用户指示灯D1闪烁。
代码清单:主函数
- int main(void)
- {
- //初始化用于驱动指示灯D1、D2、D3、D4的引脚
- leds_init();
- //初始化PE2为外部中断2
- EXTI_PE2_Init();
- //初始化PE3为外部中断3
- EXTI_PE3_Init();
- //初始化PE4为外部中断4
- EXTI_PE4_Init();
- //初始化PE5为外部中断5
- EXTI_PE5_Init();
- //配置嵌套向量中断控制器
- NVIC_Configuration();
- //使能电源管理单元的时钟
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE);
- //主循环
- while(1)
- {
- led_on(LED_1); //点亮用户指示灯D1
- sw_delay_ms(200) ; //延时200ms
- led_off(LED_1); //熄灭用户指示灯D1
- sw_delay_ms(200) ; //延时200ms
- }
- }
实验步骤
- 解压“…\\第3部分:标准库教程和实验源码\\ 1 - 基础实验程序\\”目录下的压缩文件“实验2-10-1:STANDBY待机模式”,将解压后得到的文件夹拷贝到合适的目录,如“D\\STM32F103ZET6”。
- 启动MDK5.23。
- 在MDK5中执行“Project→Open Project”打开“…\\STANDBY\\projec”目录下的工程“STANDBY.uvproj”。
- 点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“STANDBY.hex”位于工程目录下的“Objects”文件夹中。
- 点击下载按钮下载程序。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。
- 程序运行后,可以观察到D1指示灯不停闪烁。
- 按下开发板按键S1,可观察到指示灯D1熄灭。
- 按下开发板按键S2,可观察到指示灯D1、D2均不会闪烁。
- 按下开发板按键S3,可观察到指示灯D1、D3均不会闪烁。
- 按下开发板按键S4,可观察到指示灯D1、D4均不会闪烁。
- 按下开发板按键S6,可观察到指示灯D1恢复闪烁。
- 再按下开发板按键S1,可观察到指示灯D1再次熄灭。
- 按下开发板按键S5,可观察到指示灯D1恢复闪烁。
- 实验现象分析: 正常没有按键按下时,程序一直执行while循环中的控制指示灯D1间隔200ms闪烁一次的程序。按下按键S1,会进入外部中断2的中断服务程序,在外部中断2的中断服务程序中使能了WKUP引脚的唤醒功能(PA0引脚),又同时控制单片机进入待机模式。所以进入待机模式的单片机不会再执行while循环中的语句,指示灯D1不再闪烁。按下按键S2、S3、S4均不能唤醒处于待机模式的单片机,也无法执行外部中断3、外部中断4和外部中断5的中断服务函数的程序,故有上述实验现象。按下按键S6,有开发板原理图可知是将WKUP唤醒引脚PA0给了一个上升沿,该上升沿可达到唤醒待机模式的单片机的效果,所以重新执行while循环中的语句,指示灯D1闪烁。按键S5是复位按键,连接的是单片机复位引脚,按下按键S5,单片机复位程序重头开始执行,所以会重新执行while循环中的语句,指示灯D1闪烁。
STOP停止模式实验
- 注:本节的实验源码是在“实验2-10-1:STANDBY待机模式”的基础上修改。本节对应的实验源码是:“实验2-10-2:STOP停止模式”。
工程需要用到的库文件
本实验需要用到的c文件以及添加头文件包含路径的方法与介绍“实验2-10-1:STANDBY待机模式”完全一样,在此不再赘述。
编写代码
首先是对4个用户按键对应GPIO的外部中断功能进行配置并设置中断优先级,再分别给每一个中断服务函数设计不同的任务。按键S1的外部中断2对应的中断任务是重新配置系统时钟,按键S2的外部中断3对应的中断任务是控制指示灯D2闪两次,按键S3的外部中断4对应的中断任务是重新配置系统时钟和控制指示灯D3闪两次,按键S4的外部中断5对应的中断任务是重新配置系统时钟和控制指示灯D4闪两次,具体代码如下。
代码清单:外部中断2中断服务函数
- /******************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- ******************************************************************************/void EXTI2_IRQHandler(void)
- {
- SystemInit(); //重新配置系统时钟
- EXTI_ClearITPendingBit(EXTI_Line2); //清除EXTI中断线路挂起位
- }
代码清单:外部中断3中断服务函数
- /******************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- *****************************************************************************/
- void EXTI3_IRQHandler(void)
- {
- led_on(LED_2); //点亮指示灯D2
- sw_delay_ms(200); //延时200ms
- led_off(LED_2); //熄灭指示灯D2
- sw_delay_ms(200); //延时200ms
- led_on(LED_2); //点亮指示灯D2
- sw_delay_ms(200); //延时200ms
- led_off(LED_2); //熄灭指示灯D2
- sw_delay_ms(200); //延时200ms
- EXTI_ClearITPendingBit(EXTI_Line3); //清除EXTI中断线路挂起位
- }
代码清单:外部中断4中断服务函数
- /****************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- ****************************************************************************/
- void EXTI4_IRQHandler(void)
- {
- SystemInit(); //重新配置系统时钟
- led_on(LED_3); //点亮指示灯D3
- sw_delay_ms(200); //延时200ms
- led_off(LED_3); //熄灭指示灯D3
- sw_delay_ms(200); //延时200ms
- led_on(LED_3); //点亮指示灯D3
- sw_delay_ms(200); //延时200ms
- led_off(LED_3); //熄灭指示灯D3
- sw_delay_ms(200); //延时200ms
- EXTI_ClearITPendingBit(EXTI_Line4); //清除EXTI中断线路挂起位
- }
代码清单:外部中断5中断服务函数
- /***************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- **************************************************************************/
- void EXTI9_5_IRQHandler(void)
- {
- SystemInit(); //重新配置系统时钟
- led_on(LED_4); //点亮指示灯D4
- sw_delay_ms(200); //延时200ms
- led_off(LED_4); //熄灭指示灯D4
- sw_delay_ms(200); //延时200ms
- led_on(LED_4); //点亮指示灯D4
- sw_delay_ms(200); //延时200ms
- led_off(LED_4); //熄灭指示灯D4
- sw_delay_ms(200); //延时200ms
- EXTI_ClearITPendingBit(EXTI_Line5); //清除EXTI中断线路挂起位
- }
然后主函数中会对各外部中断进行初始化,使能PA0引脚的WKUP唤醒功能,并进入停止模式。在主循环中是控制用户指示灯D1闪烁。
代码清单:主函数
- int main(void)
- {
- //初始化用于驱动指示灯D1、D2、D3、D4的引脚
- leds_init();
- //初始化PE2为外部中断2
- EXTI_PE2_Init();
- //初始化PE3为外部中断3
- EXTI_PE3_Init();
- //初始化PE4为外部中断4
- EXTI_PE4_Init();
- //初始化PE5为外部中断5
- EXTI_PE5_Init();
- //配置嵌套向量中断控制器
- NVIC_Configuration();
- //使能WKUP引脚的唤醒功能(PA0引脚)
- PWR_WakeUpPinCmd(ENABLE);
- //进入停止模式,设置电压调节器为低功耗模式,等待中断唤醒
- PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);
- //主循环
- while(1)
- {
- led_on(LED_1); //点亮用户指示灯D1
- sw_delay_ms(200) ; //延时200ms
- led_off(LED_1); //熄灭用户指示灯D1
- sw_delay_ms(200) ; //延时200ms
- }
- }
实验步骤
- 解压“…\\第3部分:标准库教程和实验源码\\ 1 - 基础实验程序\\”目录下的压缩文件“实验2-10-2:STOP停止模式”,将解压后得到的文件夹拷贝到合适的目录,如“D\\STM32F103ZET6”。
- 启动MDK5.23。
- 在MDK5中执行“Project→Open Project”打开“…\\STOP\\projec”目录下的工程“STOP.uvproj”。
- 点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“STOP.hex”位于工程目录下的“Objects”文件夹中。
- 点击下载按钮下载程序。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。
- 程序运行后,可以观察到指示灯D1、D2、D3、D4熄灭。
- 按下开发板按键S1,可观察到指示灯D1会间隔200ms一直闪烁。
- 按下开发板按键S2,可观察到指示灯D2会间隔200ms闪烁两次,之后指示灯D1再间隔200ms一直闪烁。
- 按下开发板按键S3,可观察到指示灯D3会间隔200ms闪烁两次,之后指示灯D1再间隔200ms一直闪烁。
- 按下开发板按键S4,可观察到指示灯D4会间隔200ms闪烁两次,之后指示灯D1再间隔200ms一直闪烁。
- 按下开发板按键S5,可观察到没有指示灯闪烁的情况。
- 按下开发板按键S6,可观察到依然没有指示灯闪烁的情况。
- 按下开发板按键S2,可观察到指示灯D2会间隔约1.2s闪烁两次,之后指示灯D1再间隔约1.2s一直闪烁。
- 按下开发板按键S1,可观察到指示灯D1会间隔200ms一直闪烁。
- 按下开发板按键S2,可观察到指示灯D2会间隔200ms闪烁两次,之后指示灯D1再间隔200ms一直闪烁。
- 按下开发板按键S3,可观察到指示灯D3会间隔200ms闪烁两次,之后指示灯D1再间隔200ms一直闪烁。
- 按下开发板按键S4,可观察到指示灯D4会间隔200ms闪烁两次,之后指示灯D1再间隔200ms一直闪烁。
- 实验现象分析: 初始化程序后,在没有进入while循环前,已经控制单片机进入停止模式,所以不会有指示灯闪烁的情况(指示灯全灭)。按下按键S1,外部中断2会唤醒停止模式下的单片机,并执行外部中断2中断服务函数中的语句,而外部中断2中断服务函数中首先会将系统时钟重新配置(因为停止模式唤醒后系统时钟被改变),所以程序执行while循环中的控制指示灯D1闪烁的程序,闪烁间隔是200ms。按下按键S2、S3、S4则是正常的触发外部中断,程序会首先执行外部中断3、外部中断4和外部中断5中的服务函数的程序,即控制对应用户指示灯闪烁,然后才会执行while循环中的控制指示灯D1闪烁的程序。按键S5是复位按键,连接的是单片机复位引脚,按下按键S5,单片机复位程序重头开始执行,所以在执行while前,单片机就进入停止模式。按下按键S6,WKUP唤醒引脚上升沿不能唤醒停止模式下的单片机,所以依然没有指示灯闪烁的现象。按下按键S2,外部中断3会唤醒停止模式下的单片机,并执行外部中断3中断服务函数中的语句,而外部中断3中断服务函数中没有重新配置系统时钟的语句(而停止模式唤醒后系统时钟被改变),所以此时的200ms的延时函数不再是200ms,而是约1.2s,所以指示灯D2和指示灯D1闪烁的时间间隔被延长。再按下按键S1,会执行外部中断2中断服务函数中的语句,而外部中断2中断服务函数中首先会将系统时钟重新配置,所以此时指示灯闪烁的间隔恢复成200ms。(因为按键3和按键4对应的中断服务函数中都会重新配置系统时钟,所以操作按键S3或按键4与按键1的作用是一样的)
SLEEP睡眠模式实验
- 注:本节的实验源码是在“实验2-10-1:STANDBY待机模式”的基础上修改。本节对应的实验源码是:“实验2-10-3:SLEEP睡眠模式”。
工程需要用到的库文件
本实验需要用到的c文件以及添加头文件包含路径的方法与介绍“实验2-10-1:STANDBY待机模式”完全一样,在此不再赘述。
编写代码
首先是对4个用户按键对应GPIO的外部中断功能进行配置并设置中断优先级,再分别给每一个中断服务函数设计不同的任务。按键S1的外部中断2对应的中断任务是使能WKUP唤醒引脚,按键S2的外部中断3对应的中断任务是控制指示灯D2闪两次,按键S3的外部中断4对应的中断任务是控制指示灯D3闪两次,按键S4的外部中断5对应的中断任务是控制指示灯D4闪两次,具体代码如下。
代码清单:外部中断2中断服务函数
- /*************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- *************************************************************************/
- void EXTI2_IRQHandler(void)
- {
- PWR_WakeUpPinCmd (ENABLE); //使能WKUP引脚的唤醒功能(PA0引脚)
- EXTI_ClearITPendingBit(EXTI_Line2); //清除EXTI中断线路挂起位
- }
代码清单:外部中断3中断服务函数
- /**************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- *************************************************************************/
- void EXTI3_IRQHandler(void)
- {
- led_on(LED_2); //点亮指示灯D2
- sw_delay_ms(200); //延时200ms
- led_off(LED_2); //熄灭指示灯D2
- sw_delay_ms(200); //延时200ms
- led_on(LED_2); //点亮指示灯D2
- sw_delay_ms(200); //延时200ms
- led_off(LED_2); //熄灭指示灯D2
- sw_delay_ms(200); //延时200ms
- EXTI_ClearITPendingBit(EXTI_Line3); //清除EXTI中断线路挂起位
- }
代码清单:外部中断4中断服务函数
- /*****************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- ****************************************************************************/
- void EXTI4_IRQHandler(void)
- {
- led_on(LED_3); //点亮指示灯D3
- sw_delay_ms(200); //延时200ms
- led_off(LED_3); //熄灭指示灯D3
- sw_delay_ms(200); //延时200ms
- led_on(LED_3); //点亮指示灯D3
- sw_delay_ms(200); //延时200ms
- led_off(LED_3); //熄灭指示灯D3
- sw_delay_ms(200); //延时200ms
- EXTI_ClearITPendingBit(EXTI_Line4); //清除EXTI中断线路挂起位
- }
代码清单:外部中断5中断服务函数
- /**************************************************************************
- * 描 述 : 外部中断服务程序
- * 入 参 : 无
- * 返回值 : 无
- *************************************************************************/
- void EXTI9_5_IRQHandler(void)
- {
- led_on(LED_4); //点亮指示灯D4
- sw_delay_ms(200); //延时200ms
- led_off(LED_4); //熄灭指示灯D4
- sw_delay_ms(200); //延时200ms
- led_on(LED_4); //点亮指示灯D4
- sw_delay_ms(200); //延时200ms
- led_off(LED_4); //熄灭指示灯D4
- sw_delay_ms(200); //延时200ms
- EXTI_ClearITPendingBit(EXTI_Line5); //清除EXTI中断线路挂起位
- }
然后主函数中会对各外部中断进行初始化,在主循环中是控制用户指示灯D1闪烁1次,后进入睡眠模式。
代码清单:主函数
- int main(void)
- {
- //初始化用于驱动指示灯D1、D2、D3、D4的引脚
- leds_init();
- //初始化PE2为外部中断2
- EXTI_PE2_Init();
- //初始化PE3为外部中断3
- EXTI_PE3_Init();
- //初始化PE4为外部中断4
- EXTI_PE4_Init();
- //初始化PE5为外部中断5
- EXTI_PE5_Init();
- //配置嵌套向量中断控制器
- NVIC_Configuration();
- //主循环
- while(1)
- {
- led_on(LED_1); //点亮用户指示灯D1
- sw_delay_ms(200) ; //延时200ms
- led_off(LED_1); //熄灭用户指示灯D1
- sw_delay_ms(200) ; //延时200ms
- __WFI(); //进入睡眠模式,等待中断唤醒
- }
- }
实验步骤
- 解压“…\\第3部分:标准库教程和实验源码\\ 1 - 基础实验程序\\”目录下的压缩文件“实验2-10-3:SLEEP睡眠模式”,将解压后得到的文件夹拷贝到合适的目录,如“D\\STM32F103ZET6”。
- 启动MDK5.23。
- 在MDK5中执行“Project→Open Project”打开“…\\SLEEP\\projec”目录下的工程“SLEEP.uvproj”。
- 点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“SLEEP.hex”位于工程目录下的“Objects”文件夹中。
- 点击下载按钮下载程序。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。
- 程序运行后,可观察到指示灯D1闪烁一次后熄灭,指示灯D2、D3、D4均是熄灭状态。
- 按下开发板按键S1,可观察到指示灯D1会再闪烁一次之后熄灭。
- 按下开发板按键S2,可观察到指示灯D2会闪烁两次,之后指示灯D1再闪烁一次。
- 按下开发板按键S3,可观察到指示灯D3会闪烁两次,之后指示灯D1再闪烁一次。
- 按下开发板按键S4,可观察到指示灯D4会闪烁两次,之后指示灯D1再闪烁一次。
- 按下开发板按键S6,可观察到指示灯D1不会闪烁。
- 按下开发板按键S5,可观察到指示灯D1会再闪烁一次。
- 实验现象分析: 正常没有按键按下时,程序执行while循环中的控制指示灯D1闪烁一次的程序后执行进入睡眠模式的语句,使单片机进入睡眠状态,D1不再闪烁。按下按键S1,外部中断2会唤醒睡眠模式下的单片机,所以程序执行while循环中的控制指示灯D1闪烁一次的程序,之后单片机再次进入睡眠状态。按下按键S2、S3、S4均能唤醒处于睡眠模式的单片机,程序会首先执行外部中断3、外部中断4和外部中断5中的中断服务函数的程序,即控制对应用户指示灯闪烁,然后才会执行while循环中的控制指示灯D1闪烁一次的程序,之后单片机再次进入睡眠状态。按下按键S6,WKUP唤醒引脚上升沿可以唤醒待机模式下的单片机,但不能唤醒睡眠模式下的单片机,所以指示灯D1不会闪烁。按键S5是复位按键,连接的是单片机复位引脚,按下按键S5,单片机复位程序重头开始执行,所以会重新执行while循环中的语句,指示灯D1闪烁一次,之后单片机再次进入睡眠状态。
本文来自网络投稿,来自作者酷小二。不代表酷牛教程立场,如若转载,请注明出处:https://www.xukn.com/1342330.html