17:低功耗篇(PWR)---HAL库

 一:PWR

1:简历

        PWR(Power Control)电源控制

        PWR负责管理STM32内部的电源供电部分,可以实现可编程电压监测器和低功耗模式的功能

        可编程电压监测器(PVD)可以监控VDD电源电压,当VDD下降到PVD阀值以下或上升到PVD阀值之上时,PVD会触发中断,用于执行紧急关闭任务

        低功耗模式包括睡眠模式(Sleep)、停机模式(Stop)和待机模式(Standby),可在系统空闲时,降低STM32的功耗,延长设备使用时间

2:电源框图

VDD :  右边部分是VDD通过电压调节器,降压到1.8V ;   电压调节器,它的作用是给1.8V区域供电

3:低功耗模式

HSL和HSE : HSI内部高速时钟和HSE外部高速时钟

关闭电路通常有两个做法 :  一个是关闭时钟,另一个是关闭电源

关闭时钟-------所有的运算和涉及时序的操作都会暂停,  但是寄存器和存储器里面保存的数据还可以维持,不会消失

关闭电源--------就是电路直接断电 ,  电路的操作和数据都会直接丢失 .   所以关闭电源,比关闭时钟更省电

电压调节器:  电压调节器是把VDD的电压降低到了1.8V,  然后电压调节器给1.8V区域的供电   ;   电压调节器相当于1.8V供电区域的电池;  关闭电压调节器 , 1.8V供电区域的都不能使用;

睡眠 :       WFI--------任何外设发生任何中断时,芯片都会立刻醒来  ,  因为中断发生了,所以醒来之后的第一件事一般就是处理中断函数,处理完中断, 直接从睡的地方继续运行

        WFE------等待事件 ,  对应的唤醒条件是: 唤醒事件  ,  这个事件可以是外部中断配置为事件模式 ;  也可以是使能到中断,但是没有配置NVIC ,  调用WFE进入的睡眠模式 ,产生唤醒事件时,会立刻醒来 , 醒来之后,一般不需要进中断函数  ,  直接从睡的地方继续运行

        睡眠模式只是把1.8V区域的CPU时钟关闭

        睡眠模块:  WFI模式进入的只能使用中断唤醒,

                         WFE进入的可以使用中断唤醒,也可以使用事件唤醒。

                         中断的优先级> 事件的优先级

待机模式指定唤醒方式:

事件和中断:

简单理解

4:模式选择

5:低功耗模式注意事项

A:睡眠模式

        执行完WFI/WFE指令后,STM32进入睡眠模式,程序暂停运行,唤醒后程序从暂停的地方继续运行

        SLEEPONEXIT位决定STM32执行完WFI或WFE后,是立刻进入睡眠,还是等STM32从最低优先级的中断处理程序中退出时进入睡眠

        在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态

        WFI指令进入睡眠模式,可被任意一个NVIC响应的中断唤醒(外部和内部的中断都ok)

        WFE指令进入睡眠模式,可被唤醒事件唤醒

B:停止模式

        执行完WFI/WFE指令后,STM32进入停止模式,程序暂停运行,唤醒后程序从暂停的地方继续运行

           HSL和HSE : HSI内部高速时钟和HSE外部高速时钟

        1.8V供电区域的所有时钟都被停止,PLL、HSI和HSE被禁止,SRAM和寄存器内容被保留下来

        在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态

        当一个中断或唤醒事件导致退出停止模式时,HSI被选为系统时钟  -------- 你程序刚上电,是72MHz的主频 , 但是进入停止模式,再唤醒之后  ,  就变成8MHz的主频了;  所以,我们一般在停止模式唤醒后 , 第一时间就是重新启动HSE,配置主频为72MHz ,  我们只需要再调用一下Systemlnit就行

        当电压调节器处于低功耗模式下,系统从停止模式退出时,会有一段额外的启动延时

        WFI指令进入停止模式,可被任意一个EXTI外部中断唤醒(内部中断不能)

        WFE指令进入停止模式,可被任意一个EXTI外部事件唤醒 或者外部中断唤醒  (内部事件不能,内部中断也不可以) 中断的优先级> 事件的优先级

C:待机模式

        执行完WFI/WFE指令后,STM32进入待机模式,唤醒后程序从头开始运行

        整个1.8V供电区域被断电,PLL、HSI和HSE也被断电,SRAM和寄存器内容丢失,只有备份的寄存器和待机电路维持供电

        在待机模式下,所有的I/O引脚变为高阻态(浮空输入)

        WKUP引脚的上升沿、RTC闹钟事件的上升沿、NRST引脚上外部复位、IWDG复位退出待机模式

        它并不会主动关闭LSI和LSE两个低速时钟 , 因为这两个时钟还要维持RTC和独立看门狗的运行

二 : 案例

A:睡眠模式--WFI

睡眠模式 SLEEP-NOW 以 WF进入,外部中断唤醒

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "RTC.h"
#include <time.h>
#include <stdarg.h>
#include "stdio.h"
#include "key.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */Uart_Init(115200);RTC_Init();KEY_Init();while(1){printf("5\r\n");HAL_Delay(1000);printf("4\r\n");HAL_Delay(1000);printf("3\r\n");HAL_Delay(1000);/*睡眠模式有2个:SLEEP-NOW  SLEEP-ON-EXIT 关闭了SLEEP-ON-EXIT那就是打开了SLEEP-NOW  */HAL_PWR_DisableSleepOnExit();SysTick->CTRL  &=~ SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;                         HAL_PWR_EnterSLEEPMode(0,PWR_SLEEPENTRY_WFI);  /*以WFI进入的睡眠模式*/printf("2\r\n");HAL_Delay(1000);printf("1\r\n");HAL_Delay(1000);}  
}#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "delay.h"
#include <stdarg.h>
#include "stdio.h"
#include "UART.h"
void KEY_Init(void)
{__HAL_RCC_GPIOB_CLK_ENABLE() ;GPIO_InitType.Mode=GPIO_MODE_IT_FALLING;GPIO_InitType.Pin=GPIO_PIN_0;GPIO_InitType.Pull=GPIO_PULLUP; //上拉GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB,&GPIO_InitType); 	HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);HAL_NVIC_SetPriority(EXTI0_IRQn,2,0);HAL_NVIC_EnableIRQ(EXTI0_IRQn);}	void EXTI0_IRQHandler()
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin==GPIO_PIN_0){printf("唤醒\r\n");SysTick->CTRL  |=SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; }}

睡眠模式SLEEP-NOW 以WFI 进入  只能使用中断唤醒;不能使用事件唤醒。

在HAL_Init(); 函数中

   Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) HAL_InitTick(TICK_INT_PRIORITY);

systick配置位1MS的中断,做为HAL库的时基参数。每1m产生1个HAL_IncTick的中断,会唤醒我们的睡眠模式。

/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  HAL_IncTick();	
}

我们需要:

在唤醒之前吧HAL_IncTick中断关闭
关闭:将相应的二进制位变为0
&=~  :原来为1变为0  ;  原来是0还是0
SysTick->CTRL  &=~ SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; 醒来只后在打开
|=置1
SysTick->CTRL  |=SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; 

B:睡眠模式--WFI

睡眠模式 SLEEP-NOW 以WFI  进入。内部中断: 定时器2中断唤醒

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "RTC.h"
#include <time.h>
#include <stdarg.h>
#include "stdio.h"
#include "key.h"
#include "IC_encoder.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */Uart_Init(115200);RTC_Init();KEY_Init();while(1){printf("5\r\n");HAL_Delay(1000);printf("4\r\n");HAL_Delay(1000);printf("3\r\n");HAL_Delay(1000);//内部中断:定时器唤醒IC_encoder_Init(20000-1,7200-1);/*睡眠模式有2个:SLEEP-NOW  SLEEP-ON-EXIT 关闭了SLEEP-ON-EXIT那就是打开了SLEEP-NOW  */HAL_PWR_DisableSleepOnExit();SysTick->CTRL  &=~ SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;                         HAL_PWR_EnterSLEEPMode(0,PWR_SLEEPENTRY_WFI);  /*以WFI进入的睡眠模式*/printf("2\r\n");HAL_Delay(1000);printf("1\r\n");HAL_Delay(1000);}  
}#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
TIM_HandleTypeDef PA0TIM2CH1Handleinit;void IC_encoder_Init(uint16_t arr,uint16_t psc)
{PA0TIM2CH1Handleinit.Instance=TIM2;PA0TIM2CH1Handleinit.Init.Period=arr;   //ARR自动重装载值PA0TIM2CH1Handleinit.Init.Prescaler=psc;    //预分频系数PA0TIM2CH1Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	HAL_TIM_Base_Init(&PA0TIM2CH1Handleinit);__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE);//以中断的方式打开定时器HAL_TIM_Base_Start_IT(&PA0TIM2CH1Handleinit);}void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM2){__HAL_RCC_TIM2_CLK_ENABLE();HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);HAL_NVIC_SetPriority(TIM2_IRQn ,2,0);HAL_NVIC_EnableIRQ(TIM2_IRQn);}
}void TIM2_IRQHandler()
{HAL_TIM_IRQHandler(&PA0TIM2CH1Handleinit);	
}//更新中断的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{	if(htim->Instance==TIM2){		//在唤醒睡眠模式后,关闭定时器;否则时间一到,会调用这个回调HAL_TIM_Base_Stop_IT(htim);SysTick->CTRL  |=SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; printf("定时器唤醒睡眠模式\r\n");}
}

本次中断唤醒,我们使用内部的中断:定时器

C:睡眠模式-----WFE

睡眠模式 SLEEP-NOW  以 WFE进入, 外部事件唤醒

WFE的事件唤醒,中断也可以唤醒。 中断的优先级>事件的优先级。

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "RTC.h"
#include <time.h>
#include <stdarg.h>
#include "stdio.h"
#include "key.h"
#include "IC_encoder.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */Uart_Init(115200);RTC_Init();KEY_Init();while(1){printf("5\r\n");HAL_Delay(1000);printf("4\r\n");HAL_Delay(1000);printf("3\r\n");HAL_Delay(1000);/*睡眠模式有2个:SLEEP-NOW  SLEEP-ON-EXIT 关闭了SLEEP-ON-EXIT那就是打开了SLEEP-NOW  */HAL_PWR_DisableSleepOnExit();SysTick->CTRL  &=~ SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;                         HAL_PWR_EnterSLEEPMode(0,PWR_SLEEPENTRY_WFE);  /*以WFI进入的睡眠模式*/SysTick->CTRL  |=SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; printf("2\r\n");HAL_Delay(1000);printf("1\r\n");HAL_Delay(1000);		}  
}#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "delay.h"
#include <stdarg.h>
#include "stdio.h"
#include "UART.h"
void KEY_Init(void)
{__HAL_RCC_GPIOB_CLK_ENABLE() ;GPIO_InitTypeDef GPIO_InitType;GPIO_InitType.Mode=GPIO_MODE_EVT_FALLING;GPIO_InitType.Pin=GPIO_PIN_0;GPIO_InitType.Pull=GPIO_PULLUP; //上拉GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB,&GPIO_InitType); 		
}	

D:睡眠模式-----WFE

睡眠模式 SLEEP-NOW  以 WFE进入, 内部事件唤醒

WFE的事件唤醒,中断也可以唤醒。 中断的优先级>事件的优先级。

内部事件 比 外部事件比较麻烦。

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "RTC.h"
#include <time.h>
#include <stdarg.h>
#include "stdio.h"
#include "key.h"
#include "IC_encoder.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */Uart_Init(115200);RTC_Init();KEY_Init();while(1){printf("5\r\n");HAL_Delay(1000);printf("4\r\n");HAL_Delay(1000);printf("3\r\n");HAL_Delay(1000);IC_encoder_Init(20000-1,7200);HAL_PWR_EnableSEVOnPend();   //使能SEV/*睡眠模式有2个:SLEEP-NOW  SLEEP-ON-EXIT 关闭了SLEEP-ON-EXIT那就是打开了SLEEP-NOW  */HAL_PWR_DisableSleepOnExit();SysTick->CTRL  &=~ SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;                         HAL_PWR_EnterSLEEPMode(0,PWR_SLEEPENTRY_WFE);  /*以WFI进入的睡眠模式*/SysTick->CTRL  |=SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; __HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE); //清除中断标志位NVIC_ClearPendingIRQ(TIM2_IRQn);   //清除NVIC中相应的优先级HAL_TIM_Base_Stop_IT(&PA0TIM2CH1Handleinit);printf("2\r\n");HAL_Delay(1000);printf("1\r\n");HAL_Delay(1000);		}  
}#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
TIM_HandleTypeDef PA0TIM2CH1Handleinit;void IC_encoder_Init(uint16_t arr,uint16_t psc)
{PA0TIM2CH1Handleinit.Instance=TIM2;PA0TIM2CH1Handleinit.Init.Period=arr;   //ARR自动重装载值PA0TIM2CH1Handleinit.Init.Prescaler=psc;    //预分频系数PA0TIM2CH1Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	HAL_TIM_Base_Init(&PA0TIM2CH1Handleinit);__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE);//以中断的方式打开定时器HAL_TIM_Base_Start_IT(&PA0TIM2CH1Handleinit);}void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM2){__HAL_RCC_TIM2_CLK_ENABLE();
//	
//		HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
//		HAL_NVIC_SetPriority(TIM2_IRQn ,2,0);
//		HAL_NVIC_EnableIRQ(TIM2_IRQn);}
}

内部事件的配置:

首先在外设的控制寄存器使能一个中断,但不在NVIC中使能

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
TIM_HandleTypeDef PA0TIM2CH1Handleinit;void IC_encoder_Init(uint16_t arr,uint16_t psc)
{PA0TIM2CH1Handleinit.Instance=TIM2;PA0TIM2CH1Handleinit.Init.Period=arr;   //ARR自动重装载值PA0TIM2CH1Handleinit.Init.Prescaler=psc;    //预分频系数PA0TIM2CH1Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	HAL_TIM_Base_Init(&PA0TIM2CH1Handleinit);__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE);//以中断的方式打开定时器HAL_TIM_Base_Start_IT(&PA0TIM2CH1Handleinit);}void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM2){__HAL_RCC_TIM2_CLK_ENABLE();}
}

同时在Cortex-M3的系统控制寄存器中使能SEVONPEND位

		HAL_PWR_EnableSEVOnPend();   使能SEV

当CPU从WFE恢复后,需要清除相应外设的中断挂起位和外设NVIC中断通道挂起位(在NVIC中断清除挂起寄存器中)。

	__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE); //清除中断标志位NVIC_ClearPendingIRQ(TIM2_IRQn);   //清除NVIC中相应的优先级

我们使用的是定时器2的更新中断做为他的内部事件,清除相应的标志位

E:睡眠模式 

睡眠模式 SLEEP-ON-EXIT    全中断模式唤醒

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "RTC.h"
#include <time.h>
#include <stdarg.h>
#include "stdio.h"
#include "key.h"
#include "IC_encoder.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */Uart_Init(115200);RTC_Init();KEY_Init();HAL_PWR_EnableSleepOnExit();IC_encoder_Init(20000-1,7200);while(1){}  
}#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
TIM_HandleTypeDef PA0TIM2CH1Handleinit;void IC_encoder_Init(uint16_t arr,uint16_t psc)
{PA0TIM2CH1Handleinit.Instance=TIM2;PA0TIM2CH1Handleinit.Init.Period=arr;   //ARR自动重装载值PA0TIM2CH1Handleinit.Init.Prescaler=psc;    //预分频系数PA0TIM2CH1Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	HAL_TIM_Base_Init(&PA0TIM2CH1Handleinit);__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE);//以中断的方式打开定时器HAL_TIM_Base_Start_IT(&PA0TIM2CH1Handleinit);}void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM2){__HAL_RCC_TIM2_CLK_ENABLE();HAL_NVIC_SetPriority(TIM2_IRQn ,2,0);HAL_NVIC_EnableIRQ(TIM2_IRQn);}
}void TIM2_IRQHandler()
{HAL_TIM_IRQHandler(&PA0TIM2CH1Handleinit);	
}//更新中断的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{	if(htim->Instance==TIM2){		//在唤醒睡眠模式后,关闭定时器;否则时间一到,会调用这个回调SysTick->CTRL  |=SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; printf("在这个中断中做事情,这个是定时器产生的\r\n");}
}/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  HAL_IncTick();	printf("睡眠\r\n");SysTick->CTRL  &=~ SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;    
}

使用我们的SLEEP-ON-EXIT ,主While()不能有任务, 所有的任务全部是靠中断处理的。

关于HAL_Init():

在我们的 HAL_Init(),中把我们的分组分为:4

也就是说我们的NVIC抢占式优先级位:4位,也就是是 0-15

 不明白的参考:CSDNicon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/136486395

系统滴答定时器的优先级最低位0x0f=15;    在统从最低优先级的中断处理程序中退出时,微控制器就立即进入睡眠模式。

系统滴答定时器

 在我们的 HAL_Init(),中把我们的分组分为:4

也就是说我们的NVIC抢占式优先级位:4位,也就是是 0-15

        如果使用的正点原子的Delay.c,那么可以不要下面代码的操作。因为他们在delay_init中把

系统滴答定时器的中断关闭了,没有中断信号,也就不会唤醒我们的睡眠模式。        

        不使用正点原子的Delay.c,必须坐下面的操作,系统滴答定时器中断信号会唤醒我们的睡眠模式

在唤醒之前吧HAL_IncTick中断关闭
关闭:将相应的二进制位变为0
&=~  :原来为1变为0  ;  原来是0还是0
SysTick->CTRL  &=~ SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; 醒来只后在打开
|=置1
SysTick->CTRL  |=SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; 

下面为:void delay_init(uint16_t sysclk) 

/*** @brief       初始化延迟函数* @param       sysclk: 系统时钟频率, 即CPU频率(HCLK)* @retval      无*/
void delay_init(uint16_t sysclk)
{
#if SYS_SUPPORT_OS /* 如果需要支持OS. */uint32_t reload;
#endifSysTick->CTRL = 0;       清Systick状态,以便下一步重设,如果这里开了中断会关闭其中断 HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);   /* SYSTICK使用内核时钟源8分频,因systick的计数器最大值只有2^24 */g_fac_us = sysclk / 8;                                      /* 不论是否使用OS,g_fac_us都需要使用,作为1us的基础时基 */
#if SYS_SUPPORT_OS                                              /* 如果需要支持OS. */reload = sysclk / 8;                                        /* 每秒钟的计数次数 单位为M */reload *= 1000000 / delay_ostickspersec;                    /* 根据delay_ostickspersec设定溢出时间* reload为24位寄存器,最大值:16777216,在9M下,约合1.86s左右*/g_fac_ms = 1000 / delay_ostickspersec;                      /* 代表OS可以延时的最少单位 */SysTick->CTRL |= 1 << 1;                                    /* 开启SYSTICK中断 */SysTick->LOAD = reload;                                     /* 每1/delay_ostickspersec秒中断一次 */SysTick->CTRL |= 1 << 0;                                    /* 开启SYSTICK */
#endif
}

F:停机模式 

停机模式 以WFI进入

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"#include "OLED.h"
#include "wwdg.h"
#include "RTC.h"
#include <time.h>
#include <stdarg.h>
#include "stdio.h"
#include "key.h"
#include "IC_encoder.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */       Uart_Init(115200);KEY_Init();while(1){printf("5\r\n");HAL_Delay(1000);printf("4\r\n");HAL_Delay(1000);printf("3\r\n");HAL_Delay(1000);SysTick->CTRL  &=~ SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;                         HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON,PWR_STOPENTRY_WFI);  /*以WFI进入的睡眠模式*/printf("2\r\n");HAL_Delay(1000);printf("1\r\n");HAL_Delay(1000);		}  
}#include "stm32f1xx_hal.h"
#include "rcc.h"#include <stdarg.h>
#include "stdio.h"
#include "UART.h"
void KEY_Init(void)
{__HAL_RCC_GPIOB_CLK_ENABLE() ;GPIO_InitTypeDef GPIO_InitType;GPIO_InitType.Mode=GPIO_MODE_IT_FALLING;GPIO_InitType.Pin=GPIO_PIN_0;GPIO_InitType.Pull=GPIO_PULLUP; //上拉GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB,&GPIO_InitType); 	HAL_NVIC_SetPriority(EXTI0_IRQn,2,0);HAL_NVIC_EnableIRQ(EXTI0_IRQn);}	void EXTI0_IRQHandler()
{sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin==GPIO_PIN_0){printf("唤醒\r\n");SysTick->CTRL  |=SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; }}

 停机模式以WFI进入的,只有外部中断才可以唤醒  (其他任何方式都不可以)

停机模式会关闭我们的时钟,我们需要在外部中断中在打开一次。

G:停机模式

停机模式 以WFE进入

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"#include "OLED.h"
#include "wwdg.h"
#include "RTC.h"
#include <time.h>
#include <stdarg.h>
#include "stdio.h"
#include "key.h"
#include "IC_encoder.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */       Uart_Init(115200);KEY_Init();while(1){printf("5\r\n");HAL_Delay(1000);printf("4\r\n");HAL_Delay(1000);printf("3\r\n");HAL_Delay(1000);SysTick->CTRL  &=~ SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;                         HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON,PWR_STOPENTRY_WFE);  /*以WFI进入的睡眠模式*/SysTick->CTRL  |=SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk; sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */       printf("2\r\n");HAL_Delay(1000);printf("1\r\n");HAL_Delay(1000);		}  
}
#include "stm32f1xx_hal.h"
#include "rcc.h"#include <stdarg.h>
#include "stdio.h"
#include "UART.h"
void KEY_Init(void)
{__HAL_RCC_GPIOB_CLK_ENABLE() ;GPIO_InitTypeDef GPIO_InitType;GPIO_InitType.Mode=GPIO_MODE_EVT_FALLING;GPIO_InitType.Pin=GPIO_PIN_0;GPIO_InitType.Pull=GPIO_PULLUP; //上拉GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB,&GPIO_InitType); 	}	

停机模式 以WFE进入 的 只能被外部中断唤醒 或者 外部事件 唤醒。

H:待机模式

WKUP引脚唤醒

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"#include "OLED.h"
#include "wwdg.h"
#include "RTC.h"
#include <time.h>
#include <stdarg.h>
#include "stdio.h"
#include "key.h"
#include "IC_encoder.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */       Uart_Init(115200);KEY_Init();__HAL_RCC_PWR_CLK_ENABLE() ;  //待机模式需要使能PWR时钟if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB)){//TRUEprintf("系统进入待机模式\r\n");__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);}else{printf("系统不在待机模式\r\n");}while(1){printf("5\r\n");HAL_Delay(1000);printf("4\r\n");HAL_Delay(1000);printf("3\r\n");HAL_Delay(1000);/*需要使能WKUP引脚,我们的STM32F1C8T6只有PA0一个不需要单独配置PA0的IO口初始化*/HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);/*除了电源控制/状态寄存器(PWR_CSR),所有寄存器被复位。WUF:唤醒标志 打开待机模式的时候首先把标志位清除了*/__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);HAL_PWR_EnterSTANDBYMode();printf("2\r\n");HAL_Delay(1000);printf("1\r\n");HAL_Delay(1000);		}  
}

 

H:待机模式

使用RTC闹钟唤醒

RTC:

CSDNicon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/140343928

 

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "UART.h"#include "OLED.h"
#include "wwdg.h"
#include "RTC.h"
#include <time.h>
#include <stdarg.h>
#include "stdio.h"
#include "key.h"
#include "IC_encoder.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */       Uart_Init(115200);KEY_Init();RTC_Init();__HAL_RCC_PWR_CLK_ENABLE() ;  //待机模式需要使能PWR时钟if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB)){//TRUEprintf("系统进入待机模式\r\n");__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);}else{printf("系统不在待机模式\r\n");}while(1){printf("5\r\n");HAL_Delay(1000);printf("4\r\n");HAL_Delay(1000);printf("3\r\n");HAL_Delay(1000);/*需要使能WKUP引脚,我们的STM32F1C8T6只有PA0一个不需要单独配置PA0的IO口初始化*///HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);/*除了电源控制/状态寄存器(PWR_CSR),所有寄存器被复位。WUF:唤醒标志 打开待机模式的时候首先把标志位清除了*/__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);HAL_PWR_EnterSTANDBYMode();printf("2\r\n");HAL_Delay(1000);printf("1\r\n");HAL_Delay(1000);		}  
}#include "stm32f1xx_hal.h"
#include <time.h>
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"RTC_HandleTypeDef RTC_Handle;
struct tm timedata;    /*设置时间的结构体*/
struct tm alarm_clock;   /*设置闹钟的结构体*/
time_t temp;     /*mktime的反回值为time_t类型的,所以这个也定义为这个类型的*/void RTC_Init(void)
{RTC_Handle.Instance=RTC;RTC_Handle.Init.AsynchPrediv=RTC_AUTO_1_SECOND;  /*这个参数自动1S给CNT加1*/RTC_Handle.Init.OutPut=RTC_OUTPUTSOURCE_NONE;  /*RTC输出引脚*/HAL_RTC_Init(&RTC_Handle);timedata.tm_year=2024-1900;timedata.tm_mon=7;timedata.tm_mday=11;timedata.tm_hour=14;timedata.tm_min=29;timedata.tm_sec=30;/*设置闹钟结构体  6s后面触发闹钟*/alarm_clock.tm_year=2024-1900;alarm_clock.tm_mon=7;alarm_clock.tm_mday=11;alarm_clock.tm_hour=14;alarm_clock.tm_min=29;alarm_clock.tm_sec=36;temp = mktime(&timedata);   /*把时间变为秒的c库*/__HAL_RTC_WRITEPROTECTION_DISABLE(&RTC_Handle);   /*关闭写保护*//*写时钟计数器寄存器*/WRITE_REG(RTC_Handle.Instance->CNTH,temp>>16);WRITE_REG(RTC_Handle.Instance->CNTL,temp&0x0000FFFF);temp = mktime(&alarm_clock);   /*把时间变为秒的c库*//*写闹钟寄存器*/WRITE_REG(RTC_Handle.Instance->ALRH,temp>>16);WRITE_REG(RTC_Handle.Instance->ALRL,temp&0x0000FFFF);__HAL_RTC_WRITEPROTECTION_ENABLE(&RTC_Handle);   /*开启写保护*/HAL_Delay(20);    /*必须写延迟*//*在HAL_RTC_SetAlarm_IT函数下复制的。我们没有使用HAL的,使用的为c库使用需要自己干*/__HAL_RTC_ALARM_CLEAR_FLAG(&RTC_Handle, RTC_FLAG_ALRAF); /*清除RTC的闹钟标志位*/__HAL_RTC_ALARM_ENABLE_IT(&RTC_Handle, RTC_IT_ALRA);  /*使能闹钟打开中断*/__HAL_RTC_ALARM_EXTI_ENABLE_IT();  /*打开EXTI时钟线;EXTI线17连接到RTC闹钟事件*/__HAL_RTC_ALARM_EXTI_ENABLE_RISING_EDGE();  /*上升沿触发*/}void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{__HAL_RCC_RTC_ENABLE();         //打开RTC的时钟__HAL_RCC_BKP_CLK_ENABLE();     //打开备份区时钟/*闹钟的NVIC*///	HAL_NVIC_SetPriority(RTC_Alarm_IRQn,2,0);
//	HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/871755.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

51单片机9(使用左移实现流水灯编程)

一、序言&#xff1a;下面我们来给大家介绍一下这个流水灯&#xff0c;流水灯如何来实现&#xff1f;我们依然使用这个工程来完成它。 1、那要使用实现这个流水灯&#xff0c;那我们只需要让D1到D8逐个的点亮&#xff0c;那同样要实现它足够的点亮&#xff0c;也会涉及到延时&…

使用requirements.txt文件安装cuda(GPU)版本的pytorch

使用requirements.txt文件安装cuda&#xff08;GPU&#xff09;版本的pytorch 问题描述解决方法 问题描述 使用requirements.txt可以轻松地帮助我们配置新环境&#xff0c;然而&#xff0c;当使用requirements.txt安装pytorch时有时会出现仅能安装cpu版本pytorch的情况。 举例…

从汇编层看64位程序运行——函数的调用和栈平衡

函数调用 不知道有没有人想过一个问题&#xff1a;A函数调用B函数&#xff0c;B函数是如何知道在调用结束后回到A函数中的&#xff1f; 比如下面的代码&#xff0c;main函数调用foo。当foo执行完毕&#xff0c;需要执行main函数的return 0语句。但是main和foo是割裂的&#x…

Vulnhub靶场DC-3-2练习

目录 0x00 准备0x01 主机信息收集0x02 站点信息收集0x03 漏洞查找与利用1. joomla漏洞查找2. SQL注入漏洞3. 破解hash4. 上传一句话木马5. 蚁剑连接shell6. 反弹shell7. 提权 0x04 总结 0x00 准备 下载链接&#xff1a;https://download.vulnhub.com/dc/DC-3-2.zip 介绍&#…

一文清晰了解CSS——简单实例

首先一个小技巧&#xff1a; 一定要学会的vsCode格式化整理代码的快捷键&#xff0c;再也不用手动调格式了-腾讯云开发者社区-腾讯云 (tencent.com) CSS选择器用于选择要应用样式的HTML元素。常见的选择器包括&#xff1a; 类选择器&#xff1a;以.开头&#xff0c;用于选择具…

React Element介绍

React Element是React中的核心概念之一&#xff0c;它代表了React应用中的UI元素。React Element并不是真实的DOM节点&#xff0c;而是一个轻量级的、不可变的、描述性的对象&#xff0c;它包含了创建UI所需的类型&#xff08;type&#xff09;、属性&#xff08;props&#xf…

前端框架前置知识之Node.js:模块化、导入导出语法、包的概念、npm介绍

什么是模块化&#xff1f; 在Node.js中&#xff0c;每一个文件都被视为一个单独的模块 概念&#xff1a;项目是由很多个模块文件组成的 好处&#xff1a;提高代码复用性&#xff0c;按需加载&#xff0c;独立作用域 使用&#xff1a;需要标准语法导出和导入进行使用 导入导…

在pycharm 2023.2.1中运行由R语言编写的ipynb文件

在pycharm 2023.2.1中运行由R语言编写的ipynb文件 背景与目标&#xff1a; 项目中包含由R语言编写的ipynb文件&#xff0c;希望能在pycharm中运行该ipynb文件。 最终实现情况&#xff1a; 未能直接在pycharm中运行该ipynb文件&#xff0c;但是替代的实现方法有&#xff1a;…

自然语言处理(NLP)——法国工程师IMT联盟 期末考试题

1. 问题1 &#xff08;法语&#xff09;En langue arabe lcrasante majorit des mots sont forms par des combinaisons de racines et de schmes. Dans ce mcanisme... &#xff08;英语&#xff09;In Arabic language the vast majority&#xff08;十之八九&#xff09; of…

ServiceNow UI Jelly模板注入漏洞复现(CVE-2024-4879)

0x01 产品简介 ServiceNow 是一个业务转型平台。通过平台上的各个模块,ServiceNow 可用于从人力资源和员工管理到自动化工作流程或作为知识库等各种用途。 0x02 漏洞概述 由于ServiceNow的Jelly模板输入验证不严格,导致未经身份验证的远程攻击者可通过构造恶意请求利用,在…

在线图书销售管理系统设计

在线图书销售管理系统的设计是一个涉及多个模块和功能的复杂项目&#xff0c;它旨在提高图书销售的效率&#xff0c;优化库存管理&#xff0c;提升用户体验&#xff0c;以及提供数据分析支持。以下是系统设计的一些关键组成部分&#xff1a; 1. 需求分析 用户需求&#xff1a…

[综述笔记]Functional neuroimaging as a catalyst for integrated neuroscience

论文网址&#xff1a;Functional neuroimaging as a catalyst for integrated neuroscience | Nature 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔…

Stable Diffusion 使用

目录 背景 最简单用法 进阶用法 高手用法 safetensor 一、概述 二、主要特点 背景 Stable Diffusion 开源后&#xff0c;确实比较火&#xff0c;上次介绍了下 Stable Diffusion 最简单的concept。今天继续介绍下&#xff0c;以Liblib 为例&#xff0c;介绍下如何使用参…

807.力扣每日一题7/14 Java(执行用时分布击败100%)

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;算法练习关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 目录 解题思路 解题过程 时间复杂度 空间复杂度 Code 解题思路 首先…

LLM上下文长度扩展方案:YaRN

文章目录 I. 前言II. NTK-by-partsIII. YaRNIV. Dynamic NTK 题目&#xff1a; YaRN: Efficient Context Window Extension of Large Language Models 论文地址&#xff1a; YaRN: Efficient Context Window Extension of Large Language Models I. 前言 在之前的两篇文章中分…

RuoYi-后端管理项目入门篇1

目录 前提准备 下载若依前后端 Gitee 地址 准备环境 后端数据库导入 1 克隆完成 若依后端管理后端 Gitte 地址 :若依/RuoYi-Vue 2.1 创建Data Source数据源 2.2 填写好对应的数据库User 和 Password 点击Apply 2.3 新建一个Schema 2.4 填写对应数据库名称 这边演示写的…

【工具使用】adb下载和配置

【工具使用】adb下载和配置 一&#xff0c;简介二&#xff0c;操作步骤2.1 Bing搜索adb2.2 下载adb工具2.3 添加路径到环境变量 三&#xff0c;效果验证 一&#xff0c;简介 本文主要介绍如何下载adb并安装使用&#xff0c;供参考。 此时打开cmd&#xff0c;输入adb 会提示&am…

计算机网络——网络层(概念及IP地址划分)

目录 网络层概念 网络层向上层提供的两种服务 虚电路 网络提供数据报服务 虚电路服务与数据报服务的对比 网络层的两个层面 分组传送到路由器的运作 对网络层进行分层 网际协议IP 虚拟互联网络 IP地址 IP地址及其表示方法 IP地址的计算方式 IP地址的结构 …

每日一练,java

目录 描述示例 总结 描述 题目来自牛客网 •输入一个字符串&#xff0c;请按长度为8拆分每个输入字符串并进行输出&#xff1b; •长度不是8整数倍的字符串请在后面补数字0&#xff0c;空字符串不处理。 输入描述&#xff1a; 连续输入字符串(每个字符串长度小于等于100) 输…

用Java连接MySQL数据库的总结

✨个人主页&#xff1a; 不漫游-CSDN博客 前言 在日常开发中&#xff0c;使用Java连接MySQL数据库是一个常见的任务&#xff0c;涉及多个步骤。接着我就带着大家细细看来~ 一.下载.jar 包文件 1.什么是.jar 文件 通俗点讲就是一个压缩包&#xff0c;不过里面存放的都是由Java代…