STM32单片机-PWR电源控制和WDG看门狗

STM32单片机-PWR电源控制和WDG看门狗

一、PWR简介

  • PWR负责管理STM32内部的电源供电部分,可以实现可编程电压监测器低功耗模式的功能
  • 可编程电压监测器(PVD)可以监测VDD电源电压 ,当VDD下降到PVD阈值以下 或上升到PVD阈值以上 时,PVD会触发中断,用于执行紧急关闭任务
  • 低功耗模式包括睡眠模式 (Sleep)、停机模式 (Stop)和待机模式 (Standby),可在系统空闲时,降低STM32的功耗,延长设备的使用时间

下图为STM32的电源框图

从图中需要知道每个区域的供电引脚以及供电的电路

二、低功耗模式

下图为低功耗模式表

从上到下 ,关闭的电路越来越多,越来越省电,越来越难唤醒

睡眠模式 :调用WFIWFE 进入睡眠模式。WFI:任何外设发生中断 时,芯片都会立刻醒来。WFE:事件唤醒 ,不需要进入中断。只关闭CPU时钟,对他电路无任何操作

关闭电路通常有关闭时钟和关闭电源两个做法,关闭时钟 :所有运算和涉及时序的操作都会暂停,寄存器和存储器的数据可以维持 ,不会消失。关闭电源 :电路直接断电,电路操作和数据会直接丢失

停机模式待机模式 :首先SLEEPDEEP= 1 ,之后PDDS=0-停机模式PDDS=1-待机模式LPDS=0-电压调节器开启LPDS=1-电压调节器进入低功耗 ,最终调用WFI 或者WFE 进入低功耗 模式。任一外部中断(不需要时钟)外部事件 唤醒停机模式WKUP上升沿RTC闹钟 等唤醒待机模式 。停机和待机同时关闭CPU和外设时钟内外部高速时钟停机模式不关闭电源 ,所以CPU和外设寄存器数据维持原状待机模式全部关闭

下图为模式选择配置

执行WFI和WFE指令后,STM32进入低功耗模式

三、修改主频&睡眠模式&停机模式&待机模式

3.1 修改主频

在system.stm32f1ox.c文件中修改系统主频,默认72Mhz,文件是只读的,所以需要修改权限

c 复制代码
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000
#endif

3.2 睡眠模式

对于中断触发的代码,加入低功耗模式,不进入中断的时候,可以节省资源,有中断进来再进入中断函数

利用串口收发函数模拟,调用__WFI();函数 ,程序进入睡眠模式,Running!不再闪烁,当STM接收到数据触发中断时,Runnging!闪烁一次,接着进入睡眠模式,降低功耗

c 复制代码
uint8_t RxData;
int main(void)
{
	OLED_Init();
	Serial_Init();
	OLED_ShowString(1,1,"RxData:");
	while(1)
	{
		if(Serial_GetRxFlag() == 1)
		{
			RxData = Serial_GetRxData();
			OLED_ShowHexNum(1,8,RxData,2);
		}
		
		OLED_ShowString(2,1,"Running!");
		Delay_ms(100);
		OLED_ShowString(2,1,"        ");
		Delay_ms(100);
		
		__WFI();//开启睡眠模式(中断唤醒)
	}
}

3.3 停机模式

停机模式使用外部中断唤醒 ,利用对射红外传感器模拟

当外部中断不触发时,CountSensor_Get()会一直被扫描,浪费资源,可以使STM32进入低功耗模式,节省资源

进入停机模式,需要使用PWR外设,所以需要开启APB1PWR时钟 ,然后调用PWR_EnterSTOPMode()函数 ,开启停机模式,外部中断发生 时,芯片唤醒

复位后第一次Running!闪烁很快,后面的Running!闪烁很慢,是由于第一次在是72Mhz主频,后面进入停止模式,默认时钟是8MHz

注意按下复位按钮下载

c 复制代码
int main(void)
{
	OLED_Init();
	CountSensor_Init();
	OLED_ShowString(1,1,"Count:");
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//开启PWR时钟
	
	while(1)
	{
		OLED_ShowNum(1,7,CountSensor_Get(),5);
		
		OLED_ShowString(2,1,"Running:");
		Delay_ms(100);
		OLED_ShowString(2,1,"        ");
		Delay_ms(100);
		
		PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI);//开启停止模式
		SystemInit();//恢复主频
	}
}

3.4 待机模式

待机模式唤醒需要特定的信号,使用RTC唤醒待机模式

首先开启PWR时钟 ,然后调用PWR_EnterSTANDBYMode()开启待机模式 。当RTC闹钟事件来临时,唤醒待机模式,唤醒一次后,程序从头开始,闹钟值会重新设置

c 复制代码
int main(void)
{
	MyRTC_Init();
	OLED_Init();
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//开启PWR时钟
	
	OLED_ShowString(1,1,"CNT:");
	OLED_ShowString(2,1,"ALR:");
	OLED_ShowString(3,1,"ALRF:");
	uint32_t Alarm = RTC_GetCounter()+10;
	RTC_SetAlarm(Alarm);//设定闹钟值
	
	OLED_ShowNum(2,6,Alarm,10);
	while(1)
	{
		OLED_ShowNum(1,6,RTC_GetCounter(),10);
		OLED_ShowNum(3,6,RTC_GetFlagStatus(RTC_FLAG_ALR),1);
		
		OLED_ShowString(4,1,"Running!");
		Delay_ms(100);
		OLED_ShowString(4,1,"        ");
		Delay_ms(100);
		
		PWR_EnterSTANDBYMode();//开启待机模式
	}
}

四、WDG简介

  • 看门狗可以监控程序的运行状态 ,当程序因为设计漏洞硬件故障电磁干扰 等原因,出现卡死或跑飞现象 时,看门狗能及时复位程序避免程序陷入长时间的罢工状态,保证系统的可靠性和安全性
  • 看门狗本质上是一个定时器 ,当指定时间范围内 ,程序没有执行喂狗 (重置计数器 )操作时,看门狗硬件电路 就会自动产生复位信号
  • STM32内置两个看门狗
  • 独立看门狗 (IWDG):独立工作,对时间精度要求较低
  • 窗口看门狗 (WWDG):要求看门狗在精确计时窗口起作用

4.1 独立看门狗原理

下图为独立看门狗框图

与定时器类似,看门狗使用的是自减运行 ,自减到0后,定时器产生更新事件或者中断,看门狗是直接产生复位 ,定时器是产生事件后自动重装值 ,看门狗需要在自减到0之前手动重装 ,不然就会进行复位,手动重装就是喂狗

看门狗输入时钟是低速时钟LSI40KHz ,之后时钟进入8位预分频器进行预分频,最大256分频,预分频寄存器可以配置分频系数 ,之后每来一个时钟,12位递减计数器自减一个数 ,最大值是4095,自减到0后产生IWDG复位 ,在重装载数值写一个值,在键寄存器里写一个特定数据,控制电路进行喂狗,这时重装值就会复制到当前的计数器中,计数器就会回到重装值,重新自减运行了

下面给出IWDG键寄存器

  • 键寄存器本质上是控制寄存器,用于控制硬件电路的工作
  • 在可能存在干扰的情况下,一般通过在整个键寄存器写入特定值代替 控制寄存器写入一位的功能,以降低硬件电路收到干扰的概率
  • 超时时间TIWDG = TLSI x PR预分频系数 x (RL(重装值)+1)
  • 其中:TLSI = 1/FLSI = 1/40K = 0.025ms

下图为PR寄存器和分频系数的对应关系以及RL和时间关系

4.2 窗口看门狗原理

下图为窗口看门狗框图

PCLK1时钟源36MHz 进入预分频器WDGTB,然后到6位递减计数器 (T6是溢出标志位,溢出产生复位信号)CNT ,窗口看门狗没有重装寄存器,喂狗 只需要在计数器里写入数据 即可

复位信号输出部分,WDGA是窗口看门狗激活位 ,给1 启动窗口看门狗。T6=0时表示计数器溢出 ,产生复位 信号,计算一个最早界限的计数值 写入到W6-W0中,固定不变,执行写入CR操作时,即喂狗时的CNT计数值 > 窗口值 ,比较结果为1 ,也可以申请复位

喂狗太晚 ,6位计数器减到0后,复位;喂狗太早,计数器的值超过窗口值,复位

当计数器减到0x40(1000 0000)时,可以产生早期唤醒中断(EWI),下一时刻才复位

  • 超时时间 (喂狗的最晚时间 ):TWWDG = TPCLK1 x 4096 x WDGTB预分频系数 x (T[5:0] + 1)
  • 窗口时间 (喂狗的最早时间 ):TWIN = TPCLK1 x 4096 x WDGTB预分频系数 x (T[5:0] - W[5:0])
  • TPCLK1 = 1 / FPCLK1(36MHz)

下图为最小/最大超时值与分配系数关系

WDGTB = 0,1,2,3对应1,2,4,8分频

4.3 IWDG和WWDG对比

下图为IWDG和WWDG对比图

五、独立看门狗&窗口看门狗

5.1 独立看门狗

步骤:打开LSI时钟(默认打开 ) --- 键寄存器 (解除写保护 ) --- 写入预分频值和重装值 --- 键寄存器 (启动独立看门狗 ) --- 键寄存器 (写重装值-喂狗)

当程序卡死超过设定时间时,看门狗就会进行复位

c 复制代码
int main(void)
{
	OLED_Init();
	Key_Init();
	OLED_ShowString(1,1,"IWDG TEST");
	
	if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET)//本次复位由IWDG产生
	{
		OLED_ShowString(2,1,"IWDGRST");
		Delay_ms(500);
		OLED_ShowString(2,1,"       ");
		Delay_ms(500);
		RCC_ClearFlag();//清除标志位
	}
	else//普通复位
	{
		OLED_ShowString(3,1,"RST");
		Delay_ms(500);
		OLED_ShowString(3,1,"   ");
		Delay_ms(500);
	}
	//时钟自动配置
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//接触写保护
	//1000ms超时时间
	IWDG_SetPrescaler(IWDG_Prescaler_16);//配置预分频值
	IWDG_SetReload(2499);//配置重装值/喂狗
	IWDG_ReloadCounter();//先喂狗,CNT初始值就是2499
	//启动看门狗
	IWDG_Enable();
	while(1)
	{
		Key_GetNum();//按键一直按下,程序卡死,看门狗复位
		IWDG_ReloadCounter();//喂狗
		//Delay_ms(950);//看门狗不复位
		//Delay_ms(1010);//程序卡死超过1000ms,看门狗会一直复位
	}
}

5.2 窗口看门狗

步骤:打开PCLK1 时钟(APB1时钟 ) --- 配置预分频和窗口寄存器值 --- 写入控制寄存器CR (看门狗使能计数器溢出标志位计数器有效位 ) --- 计数器写值 (喂狗)

窗口看门狗需要设定窗口值和超时值,过早或超时喂狗都会使得看门狗复位

c 复制代码
int main(void)
{
	OLED_Init();
	Key_Init();
	OLED_ShowString(1,1,"WWDG TEST");
	
	if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET)//本次复位由WWDG产生
	{
		OLED_ShowString(2,1,"WWDGRST");
		Delay_ms(500);
		OLED_ShowString(2,1,"       ");
		Delay_ms(500);
		RCC_ClearFlag();//清除标志位
	}
	else//普通复位
	{
		OLED_ShowString(3,1,"RST");
		Delay_ms(500);
		OLED_ShowString(3,1,"   ");
		Delay_ms(500);
	}
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);//开启PCLK1时钟
	//超时50ms 窗口30ms
	WWDG_SetPrescaler(WWDG_Prescaler_8);//分频系数
	WWDG_SetWindowValue(0x40 | 21);//窗口值是W5-W0,W6为1
	WWDG_Enable(0x40 | 54);//计数器值是T5-T0,T6为1
	
	
	while(1)
	{
		//Key_GetNum();
		//Delay_ms(32);//过早喂狗:避免第一次喂狗和第二次间隔小于窗口30ms
		Delay_ms(55);//超时喂狗
		WWDG_SetCounter(0x40 | 54);
	}
}
相关推荐
LateBloomer7771 小时前
FreeRTOS——信号量
笔记·stm32·学习·freertos
wenchm2 小时前
细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的另一种方法
stm32·单片机·嵌入式硬件
嵌新程6 小时前
day03(单片机高级)RTOS
stm32·单片机·嵌入式硬件·freertos·rtos·u575
Lin2012306 小时前
STM32 Keil5 attribute 关键字的用法
stm32·单片机·嵌入式硬件
电工小王(全国可飞)7 小时前
STM32 RAM在Memory Map中被分为3个区域
stm32·单片机·嵌入式硬件
maxiumII7 小时前
Diving into the STM32 HAL-----DAC笔记
笔记·stm32·嵌入式硬件
时光の尘10 小时前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
日晨难再13 小时前
嵌入式:STM32的启动(Startup)文件解析
stm32·单片机·嵌入式硬件
PegasusYu1 天前
STM32CUBEIDE FreeRTOS操作教程(九):eventgroup事件标志组
stm32·教程·rtos·stm32cubeide·free-rtos·eventgroup·时间标志组
文弱书生6561 天前
输出比较简介
stm32