完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
第42章 电源管理—实现低功耗
42.1 STM32的电源管理简介 电源对电子设备的重要性不言而喻,它是保证系统稳定运行的基础,而保证系统能稳定运行后,又有低功耗的要求。在很多应用场合中都对电子设备的功耗要求非常苛刻,如某些传感器信息采集设备,仅靠小型的电池提供电源,要求工作长达数年之久,且期间不需要任何维护;由于智慧穿戴设备的小型化要求,电池体积不能太大导致容量也比较小,所以也很有必要从控制功耗入手,提高设备的续行时间。因此,STM32有专门的电源管理外设监控电源并管理设备的运行模式,确保系统正常运行,并尽量降低器件的功耗。 42.1.1 电源监控器 STM32芯片主要通过引脚VDD从外部获取电源,在它的内部具有电源监控器用于检测VDD的电压,以实现复位功能及掉电紧急处理功能,保证系统可靠地运行。 1. 上电复位与掉电复位(POR与PDR) 当检测到VDD的电压低于阈值VPOR及VPDR时,无需外部电路辅助,STM32芯片会自动保持在复位状态,防止因电压不足强行工作而带来严重的后果。见图 421,在刚开始电压低于VPOR时(约1.72V),STM32保持在上电复位状态(POR,Power On Reset),当VDD电压持续上升至大于VPOR时,芯片开始正常运行,而在芯片正常运行的时候,当检测到VDD电压下降至低于VPDR阈值(约1.68V),会进入掉电复位状态(PDR,Power Down Reset)。 图 421 POR与PDR 2. 欠压复位(BOR) POR与PDR的复位电压阈值是固定的,如果用户想要自行设定复位阈值,可以使用STM32的BOR功能(Brownout Reset)。它可以编程控制电压检测工作在表 421中的阈值级别,通过修改“选项字节”(某些特殊寄存器)中的BOR_LEV位即可控制阈值级别。其复位控制示意图见图 422。 图 422 BOR复位控制 3. 可编程电压检测器PVD 上述POR、PDR以及BOR功能都是使用其电压阈值与外部供电电压VDD比较,当低于工作阈值时,会直接进入复位状态,这可防止电压不足导致的误操作。除此之外,STM32还提供了可编程电压检测器PVD,它也是实时检测VDD的电压,当检测到电压低于VPVD阈值时,会向内核产生一个PVD中断(EXTI16线中断)以使内核在复位前进行紧急处理。该电压阈值可通过电源控制寄存器PWR_CSR设置。 使用PVD可配置8个等级,见表 422。其中的上升沿和下降沿分别表示类似图 422中VDD电压上升过程及下降过程的阈值。 42.1.2 STM32的电源系统 为了方便进行电源管理,STM32把它的外设、内核等模块跟据功能划分了供电区域,其内部电源区域划分见图 423。 图 423 STM32的电源系统 从框图了解到,STM32的电源系统主要分为备份域电路、内核电路以及ADC电路三部分,介绍如下: 备份域电路 STM32的LSE振荡器、RTC、备份寄存器及备份SRAM这些器件被包含进备份域电路中,这部分的电路可以通过STM32的VBAT引脚获取供电电源,在实际应用中一般会使用3V的钮扣电池对该引脚供电。 在图中备份域电路的左侧有一个电源开关结构,它的功能类似图 424中的双二极管,在它的上方连接了VBAT电源,下方连接了VDD主电源(一般为3.3V),右侧引出到备份域电路中。当VDD主电源存在时,由于VDD电压较高,备份域电路通过VDD供电,当VDD掉电时,备份域电路由钮扣电池通过VBAT供电,保证电路能持续运行,从而可利用它保留关键数据。 图 424 双二极管结构 调压器供电电路 在STM32的电源系统中调压器供电的电路是最主要的部分,调压器为备份域及待机电路以外的所有数字电路供电,其中包括内核、数字外设以及RAM,调压器的输出电压约为1.2V,因而使用调压器供电的这些电路区域被称为1.2V域。 调压器可以运行在“运行模式”、“停止模式”以及“待机模式”。在运行模式下,1.2V域全功率运行;在停止模式下1.2V域运行在低功耗状态,1.2V区域的所有时钟都被关闭,相应的外设都停止了工作,但它会保留内核寄存器以及SRAM的内容;在待机模式下,整个1.2V域都断电,该区域的内核寄存器及SRAM内容都会丢失(备份区域的寄存器及SRAM不受影响)。 ADC电源及参考电压 为了提高转换精度,STM32的ADC配有独立的电源接口,方便进行单独的滤波。ADC的工作电源使用VDDA引脚输入,使用VSSA作为独立的地连接,VREF引脚则为ADC提供测量使用的参考电压。 42.1.3 STM32的功耗模式 按功耗由高到低排列,STM32具有运行、睡眠、停止和待机四种工作模式。上电复位后STM32处于运行状态时,当内核不需要继续运行,就可以选择进入后面的三种低功耗模式降低功耗,这三种模式中,电源消耗不同、唤醒时间不同、唤醒源不同,用户需要根据应用需求,选择最佳的低功耗模式。三种低功耗的模式说明见表 423。 1. 睡眠模式 在睡眠模式中,仅关闭了内核时钟,内核停止运行,但其片上外设,CM4核心的外设全都还照常运行。有两种方式进入睡眠模式,它的进入方式决定了从睡眠唤醒的方式,分别是WFI(wait for interrupt)和WFE(wait for event),即由等待“中断”唤醒和由“事件”唤醒。睡眠模式的各种特性见表 424。 表 424 睡眠模式的各种特性 特性 说明 立即睡眠 在执行WFI 或WFE 指令时立即进入睡眠模式。 退出时睡眠 在退出优先级最低的中断服务程序后才进入睡眠模式。 进入方式 内核寄存器的SLEEPDEEP = 0 ,然后调用WFI或WFE指令即可进入睡眠模式; 另外若内核寄存器的SLEEPONEXIT=0时,进入“立即睡眠”模式,SLEEPONEXIT=1时,进入“退出时睡眠”模式。 唤醒方式 如果是使用WFI指令睡眠的,则可使用任意中断唤醒; 如果是使用WFE指令睡眠的,则由事件唤醒。 睡眠时 关闭内核时钟,内核停止,而外设正常运行,在软件上表现为不再执行新的代码。这个状态会保留睡眠前的内核寄存器、内存的数据。 唤醒延迟 无延迟。 唤醒后 若由中断唤醒,先进入中断,退出中断服务程序后,接着执行WFI指令后的程序;若由事件唤醒,直接接着执行WFE后的程序。 2. 停止模式 在停止模式中,进一步关闭了其它所有的时钟,于是所有的外设都停止了工作,但由于其1.2V区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以从停止模式唤醒,并重新开启时钟后,还可以从上次停止处继续执行代码。停止模式可以由任意一个外部中断(EXTI)唤醒。在停止模式中可以选择电压调节器为开模式或低功耗模式,可选择内部FLASH工作在正常模式或掉电模式。停止模式的各种特性见表 425。 调压器低功耗模式 在停止模式下调压器可工作在正常模式或低功耗模式,可进一步降低功耗 FLASH掉电模式 在停止模式下FLASH可工作在正常模式或掉电模式,可进一步降低功耗 进入方式 内核寄存器的SLEEPDEEP =1,PWR_CR寄存器中的PDDS=0,然后调用WFI或WFE指令即可进入停止模式; PWR_CR 寄存器的LPDS=0时,调压器工作在正常模式,LPDS=1时工作在低功耗模式; PWR_CR 寄存器的FPDS=0时,FLASH工作在正常模式,FPDS=1时进入掉电模式。 唤醒方式 如果是使用WFI指令睡眠的,可使用任意EXTI线的中断唤醒; 如果是使用WFE指令睡眠的,可使用任意配置为事件模式的EXTI线事件唤醒。 停止时 内核停止,片上外设也停止。这个状态会保留停止前的内核寄存器、内存的数据。 唤醒延迟 基础延迟为HSI振荡器的启动时间,若调压器工作在低功耗模式,还需要加上调压器从低功耗切换至正常模式下的时间,若FLASH工作在掉电模式,还需要加上FLASH从掉电模式唤醒的时间。 唤醒后 若由中断唤醒,先进入中断,退出中断服务程序后,接着执行WFI指令后的程序;若由事件唤醒,直接接着执行WFE后的程序。唤醒后,STM32会使用HIS作为系统时钟。 3. 待机模式 待机模式,它除了关闭所有的时钟,还把1.2V区域的电源也完全关闭了,也就是说,从待机模式唤醒后,由于没有之前代码的运行记录,只能对芯片复位,重新检测boot条件,从头开始执行程序。它有四种唤醒方式,分别是WKUP(PA0)引脚的上升沿,RTC闹钟事件,NRST引脚的复位和IWDG(独立看门狗)复位。 在以上讲解的睡眠模式、停止模式及待机模式中,若备份域电源正常供电,备份域内的RTC都可以正常运行、备份域内的寄存器及备份域内的SRAM数据会被保存,不受功耗模式影响。 42.2 电源管理相关的库函数及命令 STM32标准库对电源管理提供了完善的函数及命令,使用它们可以方便地进行控制,本小节对这些内容进行讲解。 42.2.1 配置PVD监控功能 PVD可监控VDD的电压,当它低于阈值时可产生PVD中断以让系统进行紧急处理,这个阈值可以直接使用库函数PWR_PVDLevelConfig配置成前面表 422中说明的阈值等级。 42.2.2 WFI与WFE命令 我们了解到进入各种低功耗模式时都需要调用WFI或WFE命令,它们实质上都是内核指令,在库文件core_cmInstr.h中把这些指令封装成了函数,见代码清单 241。 代码清单 421 WFI与WFE的指令定义(core_cmInstr.h文件) 1 2 /** brief Wait For Interrupt 3 4 Wait For Interrupt is a hint instruction that suspends execution 5 until one of a number of events occurs. 6 */ 7 #define __WFI __wfi 8 9 10 /** brief Wait For Event 11 12 Wait For Event is a hint instruction that permits the processor to enter 13 a low-power state until one of a number of events occurs. 14 */ 15 #define __WFE __wfe 对于这两个指令,我们应用时一般只需要知道,调用它们都能进入低功耗模式,需要使用函数的格式“__WFI();”和“__WFE();”来调用(因为__wfi及__wfe是编译器内置的函数,函数内部使用调用了相应的汇编指令)。其中WFI指令决定了它需要用中断唤醒,而WFE则决定了它可用事件来唤醒,关于它们更详细的区别可查阅《cortex-CM3/CM4权威指南》了解。 42.2.3 进入停止模式 直接调用WFI和WFE指令可以进入睡眠模式,而进入停止模式则还需要在调用指令前设置一些寄存器位,STM32标准库把这部分的操作封装到PWR_EnterSTOPMode函数中了,它的定义见代码清单 402。 代码清单 422 进入停止模式 1 /** 2 * @brief 进入停止模式 3 * 4 * @note 在停止模式下所有I/O的会保持在停止前的状态 5 * @note 从停止模式唤醒后,会使用HSI作为时钟源 6 * @note 调压器若工作在低功耗模式,可减少功耗,但唤醒时会增加延迟 7 * @param PWR_Regulator: 设置停止模式时调压器的工作模式 8 * @arg PWR_MainRegulator_ON: 调压器正常运行 9 * @arg PWR_LowPowerRegulator_ON: 调压器低功耗运行 10 * @param PWR_STOPEntry: 设置使用WFI还是WFE进入停止模式 11 * @arg PWR_STOPEntry_WFI: WFI进入停止模式 12 * @arg PWR_STOPEntry_WFE: WFE进入停止模式 13 * @retval None 14 */ 15 void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry) 16 { 17 uint32_t tmpreg = 0; 18 19 /* 设置调压器的模式 ------------*/ 20 tmpreg = PWR-》CR; 21 /* 清除 PDDS 及 LPDS 位 */ 22 tmpreg &= CR_DS_MASK; 23 24 /* 根据PWR_Regulator 的值(调压器工作模式)配置LPDS,MRLVDS及LPLVDS位 */ 25 tmpreg |= PWR_Regulator; 26 27 /* 写入参数值到寄存器 */ 28 PWR-》CR = tmpreg; 29 30 /* 设置内核寄存器的SLEEPDEEP位 */ 31 SCB-》SCR |= SCB_SCR_SLEEPDEEP_Msk; 32 33 /* 设置进入停止模式的方式-----------------*/ 34 if (PWR_STOPEntry == PWR_STOPEntry_WFI) { 35 /* 需要中断唤醒*/ 36 __WFI(); 37 } else { 38 /* 需要事件唤醒 */ 39 __WFE(); 40 } 41 /* 以下的程序是当重新唤醒时才执行的,清除SLEEPDEEP位的状态*/ 42 SCB-》SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); 43 } 这个函数有两个输入参数,分别用于控制调压器的模式及选择使用WFI或WFE停止,代码中先是根据调压器的模式配置PWR_CR寄存器,再把内核寄存器的SLEEPDEEP位置1,这样再调用WFI或WFE命令时,STM32就不是睡眠,而是进入停止模式了。函数结尾处的语句用于复位SLEEPDEEP位的状态,由于它是在WFI及WFE指令之后的,所以这部分代码是在STM32被唤醒的时候才会执行。 要注意的是进入停止模式后,STM32的所有I/O都保持在停止前的状态,而当它被唤醒时,STM32使用HSI作为系统时钟(16MHz)运行,由于系统时钟会影响很多外设的工作状态,所以一般我们在唤醒后会重新开启HSE,把系统时钟设置会原来的状态。 前面提到在停止模式中还可以控制内部FLASH的供电,控制FLASH是进入掉电状态还是正常供电状态,这可以使用库函数PWR_FlashPowerDownCmd配置,它其实只是封装了一个对FPDS寄存器位操作的语句,见代码清单 423。这个函数需要在进入停止模式前被调用,即应用时需要把它放在上面的PWR_EnterSTOPMode之前。 代码清单 423 控制FLASH的供电状态 1 /** 2 * @brief 设置内部FLASH在停止模式时是否工作在掉电状态 3 * 掉电状态可使功耗更低,但唤醒时会增加延迟 4 * @param NewState: 5 ENABLE:FLASH掉电 6 DISABLE:FLASH正常运行 7 * @retval None 8 */ 9 void PWR_FlashPowerDownCmd(FunctionalState NewState) 10 { 11 /*配置FPDS寄存器位*/ 12 *(__IO uint32_t *) CR_FPDS_BB = (uint32_t)NewState; 13 } 42.2.4 进入待机模式 类似地,STM32标准库也提供了控制进入待机模式的函数,其定义见代码清单 403。 代码清单 424 进入待机模式 1 /** 2 * @brief 进入待机模式 3 * @note 待机模式时,除以下引脚,其余引脚都在高阻态: 4 * -复位引脚 5 * - RTC_AF1 引脚 (PC13) (需要使能侵入检测、时间戳事件或RTC闹钟事件) 6 * - RTC_AF2 引脚 (PI8) (需要使能侵入检测或时间戳事件) 7 * - WKUP 引脚 (PA0) (需要使能WKUP唤醒功能) 8 * @note 在调用本函数前还需要清除WUF寄存器位 9 * @param None 10 * @retval None 11 */ 12 void PWR_EnterSTANDBYMode(void) 13 { 14 /* 选择待机模式 */ 15 PWR-》CR |= PWR_CR_PDDS; 16 17 /* 设置内核寄存器的SLEEPDEEP位 */ 18 SCB-》SCR |= SCB_SCR_SLEEPDEEP_Msk; 19 20 /* 存储操作完毕时才能进入待机模式,使用以下语句确保存储操作执行完毕 */ 21 22 __force_stores(); 23 24 /* 等待中断唤醒 */ 25 __WFI(); 26 } 该函数中先配置了PDDS寄存器位及SLEEPDEEP寄存器位,接着调用__force_stores函数确保存储操作完毕后再调用WFI指令,从而进入待机模式。这里值得注意的是,待机模式也可以使用WFE指令进入的,如果您有需要可以自行修改;另外,由于这个函数没有操作WUF寄存器位,所以在实际应用中,调用本函数前,还需要清空WUF寄存器位才能进入待机模式。 在进入待机模式后,除了被使能了的用于唤醒的I/O,其余I/O都进入高阻态,而从待机模式唤醒后,相当于复位STM32芯片,程序重新从头开始执行。 42.3 PWR—睡眠模式实验 在本小节中,我们以实验的形式讲解如何控制STM32进入低功耗睡眠模式。 42.3.1 硬件设计 实验中的硬件主要使用到了按键、LED彩灯以及使用串口输出调试信息,这些硬件都与前面相应实验中的一致,涉及到硬件设计的可参考原理图或前面章节中的内容。 42.3.2 软件设计 本小节讲解的是“PWR—睡眠模式”实验,请打开配套的代码工程阅读理解。 1. 程序设计要点 (1) 初始化用于唤醒的中断按键; (2) 进入睡眠状态; (3) 使用按键中断唤醒芯片; 2. 代码分析 main函数 睡眠模式的程序比较简单,我们直接阅读它的main函数了解执行流程,见代码清单 242。 代码清单 425 睡眠模式的main函数(main.c文件) 1 2 /** 3 * @brief 主函数 4 * @param 无 5 * @retval 无 6 */ 7 int main(void) 8 { 9 10 LED_GPIO_Config(); 11 12 /*初始化USART1*/ 13 Debug_USART_Config(); 14 15 /* 初始化按键为中断模式,按下中断后会进入中断服务函数 */ 16 EXTI_Key_Config(); 17 18 printf(“rn欢迎使用秉火 STM32 F429 开发板。rn”); 19 printf(“rn秉火F429 睡眠模式例程rn”); 20 21 printf(“rn实验说明:rn”); 22 23 printf(“rn 1.本程序中,绿灯表示STM32正常运行,红灯表示睡眠状态,蓝灯表示刚从睡眠状态被唤醒rn”); 24 printf(“rn 2.程序运行一段时间后自动进入睡眠状态,在睡眠状态下,可使用KEY1或KEY2唤醒rn”); 25 printf(“rn 3.本实验执行这样一个循环:rn”); 26printf(“rn --》亮绿灯(正常运行)-》亮红灯(睡眠模式)-》按KEY1或KEY2唤醒-》亮蓝灯(刚被唤醒)--》rn”); 27 printf(“rn 4.在睡眠状态下,DAP下载器无法给STM32下载程序,rn”); 28 printf(“rn可按KEY1、KEY2唤醒后下载,rn”); 29 printf(“rn或按复位键使芯片处于复位状态,然后在电脑上点击下载按钮,再释放复位按键,即可下载rn”); 30 31 while (1) { 32 /*********执行任务***************************/ 33 printf(“rn STM32正常运行,亮绿灯rn”); 34 35 LED_GREEN; 36 Delay(0x3FFFFFF); 37 38 /*****任务执行完毕,进入睡眠降低功耗***********/ 39 40 41 printf(“rn进入睡眠模式,按KEY1或KEY2按键可唤醒rn”); 42 43 //使用红灯指示,进入睡眠状态 44 LED_RED; 45 //进入睡眠模式 46 __WFI(); //WFI指令进入睡眠 47 48 //等待中断唤醒 K1或K2按键中断 49 50 /***被唤醒,亮蓝灯指示***/ 51 LED_BLUE; 52 Delay(0x1FFFFFF); 53 54 printf(“rn已退出睡眠模式rn”); 55 //继续执行while循环 56 } 57 } 这个main函数的执行流程见图 425。 图 425 睡眠模式实验流程图 (1) 程序中首先初始化了LED灯及串口以便用于指示芯片的运行状态,并且把实验板上的两个按键都初始化成了中断模式,以便当系统进入睡眠模式的时候可以通过按键来唤醒。这些硬件的初始化过程都跟前面章节中的一模一样。 (2) 初始化完成后使用LED及串口表示运行状态,在本实验中,LED彩灯为绿色时表示正常运行,红灯时表示睡眠状态,蓝灯时表示刚从睡眠状态中被唤醒。 (3) 程序执行一段时间后,直接使用WFI指令进入睡眠模式,由于WFI睡眠模式可以使用任意中断唤醒,所以我们可以使用按键中断唤醒。 (4) 当系统进入停止状态后,我们按下实验板上的KEY1或KEY2按键,即可使系统回到正常运行的状态,当执行完中断服务函数后,会继续执行WFI指令后的代码。 中断服务函数 系统刚被唤醒时会进入中断服务函数,见代码清单 243。 代码清单 426 按键中断的服务函数(stm32f4xx_it.c文件) 1 2 void KEY1_IRQHandler(void) 3 { 4 //确保是否产生了EXTI Line中断 5 if (EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) { 6 LED_BLUE; 7 printf(“rn KEY1 按键中断唤醒 rn”); 8 EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); 9 } 10 } 11 12 void KEY2_IRQHandler(void) 13 { 14 //确保是否产生了EXTI Line中断 15 if (EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) { 16 LED_BLUE; 17 printf(“rn KEY2 按键中断唤醒 rn”); 18 //清除中断标志位 19 EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE); 20 } 21 } 用于唤醒睡眠模式的中断,其中断服务函数也没有特殊要求,跟普通的应用一样。 42.3.3 下载验证 下载这个实验测试时,可连接上串口,在电脑端的串口调试助手获知调试信息。当系统进入睡眠状态的时候,可以按KEY1或KEY2按键唤醒系统。 注意: 当系统处于睡眠模式低功耗状态时(包括后面讲解的停止模式及待机模式),使用DAP下载器是无法给芯片下载程序的,所以下载程序时要先把系统唤醒。或者使用如下方法:按着板子的复位按键,使系统处于复位状态,然后点击电脑端的下载按钮下载程序,这时再释放复位按键,就能正常给板子下载程序了。 42.4 PWR—停止模式实验 在睡眠模式实验的基础上,我们进一步讲解如何进入停止模式及唤醒后的状态恢复。 42.4.1 硬件设计 本实验中的硬件与睡眠模式中的一致,主要使用到了按键、LED彩灯以及使用串口输出调试信息。 42.4.2 软件设计 本小节讲解的是“PWR—停止模式”实验,请打开配套的代码工程阅读理解。 1. 程序设计要点 (1) 初始化用于唤醒的中断按键; (2) 设置停止状态时的FLASH供电或掉电; (3) 选择电压调节器的工作模式并进入停止状态; (4) 使用按键中断唤醒芯片; (5) 重启HSE时钟,使系统完全恢复停止前的状态。 2. 代码分析 重启HSE时钟 与睡眠模式不一样,系统从停止模式被唤醒时,是使用HSI作为系统时钟的,在STM32F429中,HSI时钟一般为16MHz,与我们常用的180MHz相关太远,它会影响各种外设的工作频率。所以在系统从停止模式唤醒后,若希望各种外设恢复正常的工作状态,就要恢复停止模式前使用的系统时钟,本实验中定义了一个SYSCLKConfig_STOP函数,用于恢复系统时钟,它的定义见代码清单 243。 代码清单 427 恢复系统时钟(main.c文件) 1 /** 2 * @brief 停机唤醒后配置系统时钟: 使能 HSE, PLL 3 * 并且选择PLL作为系统时钟。 4 * @param None 5 * @retval None 6 */ 7 static void SYSCLKConfig_STOP(void) 8 { 9 /* After wake-up from STOP reconfigure the system clock */ 10 /* 使能 HSE */ 11 RCC_HSEConfig(RCC_HSE_ON); 12 13 /* 等待 HSE 准备就绪 */ 14 while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); 15 16 /* 使能 PLL */ 17 RCC_PLLCmd(ENABLE); 18 19 /* 等待 PLL 准备就绪 */ 20 while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); 21 22 /* 选择PLL作为系统时钟源 */ 23 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); 24 25 /* 等待PLL被选择为系统时钟源 */ 26 while (RCC_GetSYSCLKSource() != 0x08); 27 } 这个函数主要是调用了各种RCC相关的库函数,开启了HSE时钟、使能PLL并且选择PLL作为时钟源,从而恢复停止前的时钟状态。 main函数 停止模式实验的main函数流程与睡眠模式的类似,主要是调用指令方式的不同及唤醒后增加了恢复时钟的操作,见代码清单 242。 代码清单 428 停止模式的main函数(main.c文件) 1 2 /** 3 * @brief 主函数 4 * @param 无 5 * @retval 无 6 */ 7 int main(void) 8 { 9 LED_GPIO_Config(); 10 11 /*初始化USART1*/ 12 Debug_USART_Config(); 13 14 /* 初始化按键为中断模式,按下中断后会进入中断服务函数 */ 15 EXTI_Key_Config(); 16 17 printf(“rn欢迎使用秉火 STM32 F429 开发板。rn”); 18 printf(“rn秉火F429 停止模式例程rn”); 19 20 printf(“rn实验说明:rn”); 21 22 printf(“rn 1.本程序中,绿灯表示STM32正常运行,红灯表示停止状态,蓝灯表示刚从停止状态被唤醒rn”); 23 printf(“rn 2.程序运行一段时间后自动进入停止状态,在停止状态下,可使用KEY1或KEY2唤醒rn”); 24 printf(“rn 3.本实验执行这样一个循环:rn”); 25printf(“rn --》亮绿灯(正常运行)-》亮红灯(停止模式)-》按KEY1或KEY2唤醒-》亮蓝灯(刚被唤醒)---》rn”); 26 printf(“rn 4.在停止状态下,DAP下载器无法给STM32下载程序,rn”); 27 printf(“rn可按KEY1、KEY2唤醒后下载,rn”); 28 printf(“rn或按复位键使芯片处于复位状态,然后在电脑上点击下载按钮,再释放复位按键,即可下载rn”); 29 30 while (1) { 31 /*********执行任务***************************/ 32 printf(“rn STM32正常运行,亮绿灯rn”); 33 34 LED_GREEN; 35 Delay(0x3FFFFFF); 36 37 /*****任务执行完毕,进入停止降低功耗***********/ 38 39 printf(“rn进入停止模式,按KEY1或KEY2按键可唤醒rn”); 40 41 //使用红灯指示,进入停止状态 42 LED_RED; 43 44 /*设置停止模式时,FLASH进入掉电状态*/ 45 PWR_FlashPowerDownCmd (ENABLE); 46 /* 进入停止模式,设置电压调节器为低功耗模式,等待中断唤醒 */ 47 PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI); 48 49 //等待中断唤醒 K1或K2按键中断 50 /*********************被唤醒***********************/ 51 //获取刚被唤醒时的时钟状态 52 //时钟源 53 clock_source_wakeup = RCC_GetSYSCLKSource (); 54 //时钟频率 55 RCC_GetClocksFreq(&clock_status_wakeup); 56 57 //从停止模式下被唤醒后使用的是HSI时钟,此处重启HSE时钟,使用PLLCLK 58 SYSCLKConfig_STOP(); 59 60 //获取重新配置后的时钟状态 61 //时钟源 62 clock_source_config = RCC_GetSYSCLKSource (); 63 //时钟频率 64 RCC_GetClocksFreq(&clock_status_config); 65 66 //因为刚唤醒的时候使用的是HSI时钟,会影响串口波特率,输出不对,所以在重新配置时钟源后才使用串口输出。 67 printf(“rn重新配置后的时钟状态:rn”); 68 printf(“ SYSCLK频率:%d,rn HCLK频率:%d,rn PCLK1频率:%d,rn PCLK2频率:%d,rn时钟源:%d (0表示HSI,8表示PLLCLK)n”, 69 clock_status_config.SYSCLK_Frequency, 70 clock_status_config.HCLK_Frequency, 71 clock_status_config.PCLK1_Frequency, 72 clock_status_config.PCLK2_Frequency, 73 clock_source_config); 74 75 printf(“rn刚唤醒的时钟状态:rn”); 76 printf(“ SYSCLK频率:%d,rn HCLK频率:%d,rn PCLK1频率:%d,rn PCLK2频率:%d,rn时钟源:%d (0表示HSI,8表示PLLCLK)n”, 77 clock_status_wakeup.SYSCLK_Frequency, 78 clock_status_wakeup.HCLK_Frequency, 79 clock_status_wakeup.PCLK1_Frequency, 80 clock_status_wakeup.PCLK2_Frequency, 81 clock_source_wakeup); 82 83 /*指示灯*/ 84 LED_BLUE; 85 Delay(0x1FFFFFF); 86 87 printf(“rn已退出停止模式rn”); 88 //继续执行while循环 89 } 90 } 这个main函数的执行流程见图 425。 图 426 停止模式实验流程图 (1) 程序中首先初始化了LED灯及串口以便用于指示芯片的运行状态,并且把实验板上的两个按键都初始化成了中断模式,以便当系统进入停止模式的时候可以通过按键来唤醒。这些硬件的初始化过程都跟前面章节中的一模一样。 (2) 初始化完成后使用LED及串口表示运行状态,在本实验中,LED彩灯为绿色时表示正常运行,红灯时表示停止状态,蓝灯时表示刚从停止状态中被唤醒。在停止模式下,I/O口会保持停止前的状态,所以LED彩灯在停止模式时也会保持亮红灯。 (3) 程序执行一段时间后,我们先用库函数PWR_FlashPowerDownCmd设置FLASH的在停止状态时使用掉电模式,接着调用库函数PWR_EnterSTOPMode把调压器设置在低功耗模式,并使用WFI指令进入停止状态。由于WFI停止模式可以使用任意EXTI的中断唤醒,所以我们可以使用按键中断唤醒。 (4) 当系统进入睡眠状态后,我们按下实验板上的KEY1或KEY2按键,即可唤醒系统,当执行完中断服务函数后,会继续执行WFI指令(即PWR_EnterSTOPMode函数)后的代码。 (5) 为了更清晰地展示停止模式的影响,在刚唤醒后,我们调用了库函数RCC_GetSYSCLKSource以及RCC_GetClocksFreq获取刚唤醒后的系统的时钟源以及时钟频率,在使用SYSCLKConfig_STOP恢复时钟后,我们再次获取这些时状态,最后再通过串口打印出来。 (6) 通过串口调试信息我们会知道刚唤醒时系统时钟使用的是HIS时钟,频率为16MHz,恢复后的系统时钟采用HSE倍频后的PLL时钟,时钟频率为180MHz。 42.4.3 下载验证 下载这个实验测试时,可连接上串口,在电脑端的串口调试助手获知调试信息。当系统进入停止状态的时候,可以按KEY1或KEY2按键唤醒系统。 注意: 当系统处于停止模式低功耗状态时(包括睡眠模式及待机模式),使用DAP下载器是无法给芯片下载程序的,所以下载程序时要先把系统唤醒。或者使用如下方法:按着板子的复位按键,使系统处于复位状态,然后点击电脑端的下载按钮下载程序,这时再释放复位按键,就能正常给板子下载程序了。 42.5 PWR—待机模式实验 最后我们来学习最低功耗的待机模式。 42.5.1 硬件设计 本实验中的硬件与睡眠模式、停止模式中的一致,主要使用到了按键、LED彩灯以及使用串口输出调试信息。要强调的是,由于WKUP引脚(PA0)必须使用上升沿才能唤醒待机状态的系统,所以我们硬件设计的PA0引脚连接到按键KEY1,且按下按键的时候会在PA0引脚产生上升沿,从而可实现唤醒的功能,按键的具体电路请查看配套的原理图。 42.5.2 软件设计 本小节讲解的是“PWR—待机模式”实验,请打开配套的代码工程阅读理解。 1. 程序设计要点 (1) 清除WUF标志位; (2) 使能WKUP唤醒功能; (3) 进入待机状态。 2. 代码分析 main函数 待机模式实验的执行流程比较简单,见代码清单 242。 代码清单 429 停止模式的main函数(main.c文件) 1 2 /** 3 * @brief 主函数 4 * @param 无 5 * @retval 无 6 */ 7 int main(void) 8 { 9 LED_GPIO_Config(); 10 11 /*初始化USART1*/ 12 Debug_USART_Config(); 13 14 /*初始化按键,不需要中断,仅初始化KEY2即可,只用于唤醒的PA0引脚不需要这样初始化*/ 15 Key_GPIO_Config(); 16 17 printf(“rn欢迎使用秉火 STM32 F429 开发板。rn”); 18 printf(“rn秉火F429 待机模式例程rn”); 19 20 printf(“rn实验说明:rn”); 21 22 printf(“1.绿灯表示本次复位是上电或引脚复位,红灯表示即将进入待机状态,蓝灯表示本次是待机唤醒的复位rn”); 23 printf(“rn 2.长按KEY2按键后,会进入待机模式rn”); 24 printf(“rn 3.在待机模式下,按KEY1按键可唤醒,唤醒后系统会进行复位,程序从头开始执行rn”); 25 printf(“rn 4.可通过检测WU标志位确定复位来源rn”); 26 27 printf(“rn 5.在待机状态下,DAP下载器无法给STM32下载程序,需要唤醒后才能下载”); 28 29 //检测复位来源 30 if (PWR_GetFlagStatus(PWR_FLAG_WU) == SET) { 31 LED_BLUE; 32 printf(“rn待机唤醒复位 rn”); 33 } else { 34 LED_GREEN; 35 printf(“rn非待机唤醒复位 rn”); 36 } 37 while (1) { 38 // K2 按键长按进入待机模式 39 if (KEY2_LongPress()) { 40 41 printf(“rn即将进入待机模式,进入待机模式后可按KEY1唤醒,唤醒后会进行复位,程序从头开始执行rn”); 42 LED_RED; 43 Delay(0xFFFFFF); 44 /*清除WU状态位*/ 45 PWR_ClearFlag (PWR_FLAG_WU); 46 47 /* 使能WKUP引脚的唤醒功能,使能PA0*/ 48 PWR_WakeUpPinCmd (ENABLE); 49 50 /* 进入待机模式 */ 51 PWR_EnterSTANDBYMode(); 52 } 53 } 54 } 这个main函数的执行流程见图 425。 图 427 待机模式实验流程图 (1) 程序中首先初始化了LED灯及串口以便用于指示芯片的运行状态,由于待机模式唤醒使用WKUP引脚并不需要特别的引脚初始化,所以我们调用的按键初始化函数Key_GPIO_Config它的内部只初始化了KEY2按键,而且是普通的输入模式,对唤醒用的PA0引脚可以不初始化。当然,如果不初始化PA0的话,在正常运行模式中KEY1按键是不能正常运行的,我们这里只是强调待机模式的WKUP唤醒不需要中断,也不需要像按键那样初始化。本工程中使用的Key_GPIO_Config函数定义如代码清单 4210所示。 代码清单 4210 Key_GPIO_Config函数(bsp_key.c文件) 1 2 /** 3 * @brief 配置按键用到的I/O口 4 * @param 无 5 * @retval 无 6 */ 7 void Key_GPIO_Config(void) 8 { 9 GPIO_InitTypeDef GPIO_InitStructure; 10 11 /*开启按键GPIO口的时钟*/ 12 RCC_AHB1PeriphClockCmd(KEY2_GPIO_CLK,ENABLE); 13 14 /*设置引脚为输入模式*/ 15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; 16 17 /*设置引脚不上拉也不下拉*/ 18 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 19 20 /*选择按键的引脚*/ 21 GPIO_InitStructure.GPIO_Pin = KEY2_PIN; 22 23 /*使用上面的结构体初始化按键*/ 24 GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure); 25 } (2) 使用库函数PWR_GetFlagStatus检测PWR_FLAG_WU标志位,当这个标志位为SET状态的时候,表示本次系统是从待机模式唤醒的复位,否则可能是上电复位。我们利用这个区分两种复位形式,分别使用蓝色LED灯或绿色LED灯来指示。 (3) 在while循环中,使用自定义的函数KEY2_LongPress来检测KEY2按键是否被长时间按下,若长时间按下则进入待机模式,否则继续while循环。KEY2_LongPress函数不是本章分析的重点,感兴趣的读者请自行查阅工程中的代码。 (4) 检测到KEY2按键被长时间按下,要进入待机模式。在使用库函数PWR_EnterSTANDBYMode发送待机命令前,要先使用库函数PWR_ClearFlag清除PWR_FLAG_WU标志位,并且使用库函数PWR_WakeUpPinCmd使能WKUP唤醒功能,这样进入待机模式后才能使用WKUP唤醒。 (5) 在进入待机模式前我们控制了LED彩灯为红色,但在待机状态时,由于I/O口会处于高阻态,所以LED灯会熄灭。 (6) 按下KEY1按键,会使PA0引脚产生一个上升沿,从而唤醒系统。 (7) 系统唤醒后会进行复位,从头开始执行上述过程,与第一次上电时不同的是,这样的复位会使PWR_FLAG_WU标志位改为SET状态,所以这个时候LED彩灯会亮蓝色。 42.5.3 下载验证 下载这个实验测试时,可连接上串口,在电脑端的串口调试助手获知调试信息。长按实验板上的KEY2按键,系统会进入待机模式,按KEY1按键可唤醒系统。 注意: 当系统处于待机模式低功耗状态时(包括睡眠模式及停止模式),使用DAP下载器是无法给芯片下载程序的,所以下载程序时要先把系统唤醒。或者使用如下方法:按着板子的复位按键,使系统处于复位状态,然后点击电脑端的下载按钮下载程序,这时再释放复位按键,就能正常给板子下载程序了。 42.6 PWR—PVD电源监控实验 这一小节我们学习如何使用PVD监控供电电源,增强系统的鲁棒性。 42.6.1 硬件设计 本实验中使用PVD监控STM32芯片的VDD引脚,当监测到供电电压低于阈值时会产生PVD中断,系统进入中断服务函数进入紧急处理过程。所以进行这个实验时需要使用一个可调的电压源给实验板供电,改变给STM32芯片的供电电压,为此我们需要先了解实验板的电源供电系统,见图 428。 图 428 实验板的电源供电系统 整个电源供电系统主要分为以下五部分: (1) 6-12V的DC电源供电系统,这部分使用DC电源接口引入6-12V的电源,经过RT7272进行电压转换成5V电源,再与第二部分的“5V_USB”电源线连接在一起。 (2) 第二部分使用USB接口,使用USB线从外部引入5V电源,引入的电源经过电源开关及保险丝连接到“5V”电源线。 (3) 第三部分的是电源开关及保险丝,即当我们的实验板使用DC电源或“5V_USB”线供电时,可用电源开关控制通断,保险丝也会起保护作用。 (4) “5V”电源线遍布整个板子,板子上各个位置引出的标有“5V”丝印的排针都与这个电源线直接相连。5V电源线给板子上的某些工作电压为5V的芯片供电。5V电源还经过LDO稳压芯片,输出3.3V电源连接到“3.3V”电源线。 (5) 同样地,“3.3V”电源线也遍布整个板子,各个引出的标有“3.3V”丝印的排针都与它直接相连,3.3V电源给工作电压为3.3V的各种芯片供电。STM32芯片的VDD引脚就是直接与这个3.3V电源相连的,所以通过STM32的PVD监控的就是这个“3.3V”电源线的电压。 当我们进行这个PVD实验时,为方便改变“3.3V”电源线的电压,我们可以把可调电源通过实验板上引出的“5V”及“GND”排针给实验板供电,当可调电源电压降低时,LDO在“3.3V”电源线的供电电压会随之降低,即STM32的PVD监控的VDD引脚电压会降低,这样我们就可以模拟VDD电压下降的实验条件,对PVD进行测试了。不过,由于这样供电不经过保险丝,所以在调节电压的时候要小心,不要给它供电远高于5V,否则可能会烧坏实验板上的芯片。 42.6.2 软件设计 本小节讲解的是“PWR—睡眠模式”实验,请打开配套的代码工程阅读理解。为了方便把这个工程的PVD监控功能移植到其它应用,我们把PVD电压监控相关的主要代码编都写到“bsp_pvd.c”及“bsp_pvd.h”文件中,这些文件是我们自己编写的,不属于标准库的内容,可根据您的喜好命名文件。 1. 程序设计要点 (1) 初始化PVD中断; (2) 设置PVD电压监控等级并使能PVD; (3) 编写PVD中断服务函数,处理紧急任务。 2. 代码分析 初始化PVD 使用PVD功能前需要先初始化,我们把这部分代码封装到PVD_Config函数中,见代码清单 4211。 代码清单 4211 初始化PVD(bsp_pvd.c文件) 1 2 /** 3 * @brief 配置PVD. 4 * @param None 5 * @retval None 6 */ 7 void PVD_Config(void) 8 { 9 NVIC_InitTypeDef NVIC_InitStructure; 10 EXTI_InitTypeDef EXTI_InitStructure; 11 12 /*使能 PWR 时钟 */ 13 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); 14 15 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 16 17 /* 使能 PVD 中断 */ 18 NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn; 19 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 20 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 21 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 22 NVIC_Init(&NVIC_InitStructure); 23 24 /* 配置 EXTI16线(PVD 输出) 来产生上升下降沿中断*/ 25 EXTI_ClearITPendingBit(EXTI_Line16); 26 EXTI_InitStructure.EXTI_Line = EXTI_Line16; 27 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 28 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; 29 EXTI_InitStructure.EXTI_LineCmd = ENABLE; 30 EXTI_Init(&EXTI_InitStructure); 31 32 //配置PVD级别5 33 // (PVD检测电压的阈值为2.8V,VDD电压低于2.8V时产生PVD中断, 34 //具体数据可查询数据手册获知) 35 /*具体级别根据自己的实际应用要求配置*/ 36 PWR_PVDLevelConfig(PWR_PVDLevel_5); 37 38 /* 使能PVD输出 */ 39 PWR_PVDCmd(ENABLE); 40 } 在这段代码中,执行的流程如下: (1) 配置PVD的中断优先级。由于电压下降是非常危急的状态,所以请尽量把它配置成最高优先级。 (2) 配置了EXTI16线的中断源,设置EXTI16是因为PVD中断是通过EXTI16产生中断的(GPIO的中断是EXTI0-EXTI15)。 (3) 使用库函数PWR_PVDLevelConfig设置PVD监控的电压阈值等级,各个阈值等级表示的电压值请查阅表 422或STM32的数据手册。 (4) 最后使用库函数PWR_PVDCmd使能PVD功能。 PVD中断服务函数 配置完成PVD后,还需要编写中断服务函数,在其中处理紧急任务,本工程的PVD中断服务函数见代码清单 4212。 代码清单 4212 PVD中断服务函数(stm32f4xx_it.c文件) 1 2 /** 3 * @brief PVD中断请求 4 * @param None 5 * @retval None 6 */ 7 void PVD_IRQHandler(void) 8 { 9 /*检测是否产生了PVD警告信号*/ 10 if (PWR_GetFlagStatus (PWR_FLAG_PVDO)==SET) { 11 /* 亮红灯,实际应用中应进入紧急状态处理 */ 12 LED_RED; 13 14 } 15 /* 清除中断信号*/ 16 EXTI_ClearITPendingBit(EXTI_Line16); 17 18 } 19 注意这个中断服务函数的名是PVD_IRQHandler而不是EXTI16_IRQHandler(STM32没有这样的中断函数名),示例中我们仅点亮了LED红灯,不同的应用中要根据需求进行相应的紧急处理。 main函数 本电源监控实验的main函数执行流程比较简单,仅调用了PVD_Config配置监控功能,当VDD供电电压正常时,板子亮绿灯,当电压低于阈值时,会跳转到中断服务函数中,板子亮红灯,见代码清单 242。 代码清单 4213 停止模式的main函数(main.c文件) 1 /** 2 * @brief 主函数 3 * @param 无 4 * @retval 无 5 */ 6 int main(void) 7 { 8 LED_GPIO_Config(); 9 10 //亮绿灯,表示正常运行 11 LED_GREEN; 12 13 //配置PVD,当电压过低时,会进入中断服务函数,亮红灯 14 PVD_Config(); 15 16 while (1) { 17 18 /*正常运行的程序*/ 19 20 } 21 22 } 23 24 42.6.3 下载验证 本工程的验证步骤如下: (1) 通过电脑把本工程编译并下载到实验板; (2) 把下载器、USB及DC电源等外部供电设备都拔掉; (3) 按“硬件设计”小节中的说明,使用可调电源通过“5V”及“GND”排针给实验板供5V电源;(注意要先调好可调电源的电压再连接,防止烧坏实验板) (4) 复位实验板,确认板子亮绿灯,表示正常状态; (5) 持续降低可调电源的输出电压,直到实验板亮红灯,这时表示PVD检测到电压低于阈值。 本工程中,我们实测PVD阈值等级为“PWR_PVDLevel_5”时,当可调电源电压降至4.4V时,板子亮红灯,此时的“3.3V”电源引脚的实测电压为2.75V;而PVD阈值等级为“PWR_PVDLevel_3”时,当可调电源电压降至4.2V时,板子亮红灯,此时的“3.3V”电源引脚的实测电压为2.55V; 注意: 由于这样使用可调电源供电不经过保险丝,所以在调节电压的时候要小心,不要给它供电远高于5V,否则可能会烧坏实验板上的芯片。 42.7 每课一问 10. 在睡眠模式实验的基础上编写程序,添加SYSTICK定时器,使用它控制LED灯1秒翻转状态1次,控制完毕后立即重新进入睡眠状态。 11. 在停止模式实验的基础上改写程序,尝试在系统唤醒后(紧接着PWR_EnterSTOPMode函数之后)立即使用串口打印调试信息到电脑端,观察实验现象并解释。 答:由于系统时钟没有恢复,导致串口波特率与原配置不符,导致通讯错误。 12. 在PVD电源监控实验的基础上,修改PVD监控的电压阈值等级,进入PVD中断时“3.3V”电源线的临界电压。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1617 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1543 浏览 1 评论
977 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
683 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1595 浏览 2 评论
1863浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
644浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
531浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
504浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 02:29 , Processed in 0.808705 second(s), Total 77, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号