STM32 独立看门狗和窗口看门狗

独立看门狗(IWDG)实验

STM32 内部自带了 2 个看门狗:独立看门狗(IWDG)和窗口看门狗(WWDG)。先介绍独立看门狗

STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然
有效。这里需要注意独立看门狗的时钟是一个内部 RC 时钟,所以并不是准确的 40Khz,而是在 30~60Khz 之间的一个可变化的时钟

键寄存器(IWDG_KR)
预分频寄存器(IWDG_PR)
重装载寄存器(IWDG_RLR)
状态寄存器(IWDG_SR)

在这里插入图片描述

在这里插入图片描述
IWDG_PR 和 IWDG_RLR 寄存器具有写保护功能。要修改这两个寄存器的值,必须先向IWDG_KR 寄存器中写入 0x5555。
重装载操作(即写入 0xAAAA)也会启动写保护功能。

在这里插入图片描述
在键寄存器(IWDG_KR)中写入 0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值 0xFFF 递减计数。当计数器计数到末尾 0x000 时,会产生一个复位信号(IWDG_RESET)。
无论何时,只要键寄存器 IWDG_KR 中被写入 0xAAAA, IWDG_RLR 中的值就会被重新加载到计数器中从而避免产生看门狗复位

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

溢出时间计算:
Tout=((4×2^prer) ×rlr) /40 (M3)

其中 Tout 为看门狗溢出时间(单位为 ms);
prer 为看门狗时钟预分频值(IWDG_PR 值),范围为
0~7;
rlr 为看门狗的重装载值(IWDG_RLR 的值);

时钟频率LSI=40K, 一个看门狗时钟周期就是最短超时时间。
最长超时时间= (IWDG_RLR寄存器最大值)X看门狗时钟周期

独立看门狗相关的库函数和定义分布在文件 stm32f10x_iwdg.h 和stm32f10x_iwdg.c 中。

void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);//取消写保护:0x5555使能
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);//设置预分频系数:写PR
void IWDG_SetReload(uint16_t Reload);//设置重装载值:写RLR
void IWDG_ReloadCounter(void);//喂狗:写0xAAAA到KR
void IWDG_Enable(void);//使能看门狗:写0xCCCC到KR
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);//状态:重装载/预分频 更新
    步骤:

在这里插入图片描述
项目:在配置看门狗后,DS0 将常亮,如果 WK_UP 按键按下,就喂狗,只要 WK_UP 不停的按,看门狗就一直不会产生复位,保持 DS0 的常亮,一旦超过看门狗定溢出时间(Tout)还没按,那么将会导致程序重启,这将导致 DS0 熄灭一次。
(只要不停的按就一直亮)

注:我们要加入固件库看门狗支持文件 stm32f10x_iwdg.h 和
stm32f10x_iwdg.c 文件。

wdg.c 里面的代码如下:
#include "wdg.h"
//初始化独立看门狗
//prer:分频数:0~7(只有低 3 位有效!)
//分频因子=4*2^prer.但最大值只能是 256!
//rlr:重装载寄存器值:低 11 位有效.
//时间计算(大概):Tout=((4*2^prer)*rlr)/40 (ms).
void IWDG_Init(u8 prer,u16 rlr) 
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); 
//使能对寄存器 IWDG_PR 和 IWDG_RLR 的写操作
IWDG_SetPrescaler(prer); //设置 IWDG 预分频值:设置 IWDG 预分频值为 64
IWDG_SetReload(rlr); //设置 IWDG 重装载值
IWDG_ReloadCounter(); //按照 IWDG 重装载寄存器的值重装载 IWDG 计数器
IWDG_Enable(); //使能 IWDG}
//喂独立看门狗
void IWDG_Feed(void)
{
IWDG->KR=0XAAAA;//reload
}
主函数 main 的代码
int main(void)
{
delay_init(); //延时函数初始化
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组 2 
uart_init(9600); //串口初始化为 9600
LED_Init(); //初始化与 LED 连接的硬件接口
 KEY_Init(); //按键初始化
delay_ms(300); //让人看得到灭
IWDG_Init(4,625); //与分频数为 64,重载值为 625,溢出时间为 1s 
LED0=0; //点亮 LED0
while(1)
{
if(KEY_Scan(0)==WKUP_PRES)IWDG_Feed();//如果 WK_UP 按下,则喂狗
delay_ms(10);
};
}

窗口门狗(WWDG)实验

之所以称为窗口就是因为其喂狗时间是一个有上下限的范围内(窗口),你可以通过设定相关寄存器,设定其上限时间(下限固定)。喂狗的时间不能过早也不能过晚。

而独立看门狗限制喂狗时间在0-x内,x由相关寄存器决定。喂狗的时间不能过晚。

在这里插入图片描述

T[6:0]就是 WWDG_CR 的低七位,W[6:0]即是 WWDG->CFR 的低七位。T[6:0] 就是窗口看门狗的计数器,而
W[6:0]则是窗口看门狗的上窗口,下窗口值是固定的(0X40)。 当窗口看门狗的计数器在上窗口值之外被刷新,或者低于下窗口值都会产生复位。
上窗口值(W[6:0])是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保 窗口值大于 0X40,否则窗口就不存在了

STM32F的窗口看门狗中有一个7位的递减计数器T[6:0],它会在出现下述2种情况之一时产生看门狗复位:
当喂狗的时候如果计数器的值大于某一设定数值W[6:0]时,此设定数值在WWDG_CFR寄存器定义。
当计数器的数值从0x40减到0x3F时【T6位跳变到0】 。
如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以用于喂狗以避免WWDG复位。

窗口看门狗的超时公式如下:
Twwdg=(4096×2^WDGTB×(T[5:0]+1))/Fpclk1;
其中: Twwdg:WWDG 超时时间(单位为 ms)
Fpclk1:APB1 的时钟频率(单位为 Khz)
WDGTB:WWDG 的预分频系数
T[5:0]:窗口看门狗的计数器低 6 位

3个寄存器:
控制寄存器(WWDG_CR)
配置寄存器(WWDG_CFR)
状态寄存器(WWDG_SR)

控制寄存器(WWDG_CR)
在这里插入图片描述

WWDG_CR 只有低八位有效,
T[6:0]用来存储看门狗的计数器值,随时更新的,每个窗口看门狗计数周期(4096×2^ WDGTB)减 1。
当该计数器的值从 0X40 变为 0X3F 的时候,将产生看门狗复位。
WDGA 位则是看门狗的激活位,该位由软件置 1,以启动看门狗,并且一定要注意的是该位一旦设置,就只能在硬件复位后才能清零了。

配置寄存器(WWDG_CFR)

在这里插入图片描述

  • EWI 是提前唤醒中断,也就是在快要产生复位的前一段时间
    (T[6:0]=0X40)来提醒我们,需要进行喂狗了,否则将复位!

  • 因此,我们一般用该位来设置中断,当窗口看门狗的计数器值减到 0X40 的时候,如果该位设置,并开启了中断,则会产生中断,我们可以在中断里面向 WWDG_CR 重新写入计数器的值,来达到喂狗的目的。

  • 注意这里在进入中断后,必须在不大于 1 个窗口看门狗计数周期的时间(在 PCLK1 频率为 36M 且 WDGTB 为 0 的条下, 该时间为 113us)内重新写 WWDG_CR,否则,看门狗将产生复位!

状态寄存器(WWDG_SR)

在这里插入图片描述

  • 状态寄存器(WWDG_SR),该寄存器用来记录当前是否有提前唤醒 的标志。该寄存器仅有位 0 有效,其他都是保留位。当计数器值达到 40h 时,此位由硬件置 1。

  • 它必须通过软件写 0 来清除。对此位写 1 无效。即使中断未被使能,在计数器的值达到 0X40的时候,此位也会被置 1。

步骤;

**
1.使能看门狗时钟:
RCC_APB1PeriphClockCmd();
② 设置分频系数:
WWDG_SetPrescaler();
③ 设置上窗口值:
WWDG_SetWindowValue();
④ 开启提前唤醒中断并分组(可选):
WWDG_EnableIT();
NVIC_Init();
⑤ 使能看门狗:
WWDG_Enable();
⑥ 喂狗:
WWDG_SetCounter();
⑦编写中断服务函数
WWDG_IRQHandler();
**

增加了窗口看门狗相关的库函数支持stm32f10x_wwdg.c/stm32f10x_wwdg.h,同时新加了wwdg.c源文件和引入了对应的头文件 wwdg.h。

wwdg.c 源文件内容如下

wwdg.c 源文件内容如下
#include "wwdg.h"
#include "led.h"


//保存WWDG计数器的设置值,默认为最大.
u8 WWDG_CNT=0x7f;
//初始化窗口看门狗
//tr     : T[6:0],计数器值
//wr     : W[6:0],窗口值
//fprer:分频系数(WDGTB),仅最低2位有效

void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{ 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  //   WWDG时钟使能

	WWDG_SetPrescaler(fprer);设置IWDG预分频值

	WWDG_SetWindowValue(wr);//设置窗口值

	WWDG_Enable(tr);	 //使能看门狗 ,	设置 counter .                  

	WWDG_ClearFlag();

	WWDG_NVIC_Init();//初始化窗口看门狗 NVIC

	WWDG_EnableIT(); //开启窗口看门狗中断
} 
//重设置WWDG计数器的值
void WWDG_Set_Counter(u8 cnt)
{
    WWDG_Enable(cnt);	 
}
//窗口看门狗中断服务程序
void WWDG_NVIC_Init()
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;    //WWDG中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占2,子优先级3,组2	
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	 //抢占2,子优先级3,组2	
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; 
	NVIC_Init(&NVIC_InitStructure);//NVIC初始化
}


//中断服务函数
void WWDG_IRQHandler(void)
	{
	// Update WWDG counter
	WWDG_SetCounter(0x7F);	  //当禁掉此句后,窗口看门狗将产生复位
	// Clear EWI flag */
	WWDG_ClearFlag();	  //清除提前唤醒中断标志位
	// Toggle GPIO_Led pin 7 */
	LED1=!LED1;
	}
wwdg.h
#ifndef __WDG_H
#define __WDG_H
#include "sys.h"
	  

void WWDG_Init(u8 tr,u8 wr,u32 fprer);//初始化WWDG
void WWDG_Set_Counter(u8 cnt);       //设置WWDG的计数器
void WWDG_NVIC_Init(void);
#endif

main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "wwdg.h"

 int main(void)
 {
 
	delay_init();	    
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(9600);
 	LED_Init(); 
	LED0=0;    //点亮LED
	delay_ms(300);	  
	WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);   
 	while(1)
	{
		LED0=1;			  	   
	}	 
 }


led.c
#include "led.h"

	

//初始化PB5和PE5为输出口.并使能这两个口的时钟		    
//LED IO初始化
void LED_Init(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);	 //使能PA,PD端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				 //LED0-->PA.8 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOA, &GPIO_InitStructure);					 //根据设定参数初始化GPIOA.8
 GPIO_SetBits(GPIOA,GPIO_Pin_8);						 //PA.8 输出高

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	    		 //LED1-->PD.2 端口配置, 推挽输出
 GPIO_Init(GPIOD, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz
 GPIO_SetBits(GPIOD,GPIO_Pin_2); 						 //PD.2 输出高 
}
 
led.h
#ifndef __LED_H
#define __LED_H	 
#include "sys.h"

#define LED0 PAout(8)	// PA8
#define LED1 PDout(2)	// PD2	

void LED_Init(void);//初始化

		 				    
#endif

实验现象:可以看到 DS0 亮一下之后熄灭,紧接着 DS1 开始不停的闪
烁。每秒钟闪烁 9 次左右

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值