600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > stm32-看门狗(独立看门狗 窗口看门狗)

stm32-看门狗(独立看门狗 窗口看门狗)

时间:2018-12-07 08:26:50

相关推荐

stm32-看门狗(独立看门狗 窗口看门狗)

基于野火教程的看门狗。

实验器材:stm32c8t6,LED灯,按键一个。

实验一:独立看门狗

1. 实验原理。

2.实验代码讲解。

3.实验现象。

实验二:窗口看门狗

1. 实验原理。

2.实验代码讲解。

3.实验现象。

在进入正题之前,我们先了解一下什么是看门狗。看门狗用于检测和解决由软件错误引起的故障,当计数器达到给定的超时值时,触发一个中断(仅适用于窗口看门狗)或系统复位。通俗的来讲,就是当程序跑飞,在规定的时间内系统复位,或产生中断。看门狗分为独立看门狗和窗口看门狗。独立看门狗用通俗一点的话来解释就是一个 12 位的递减计数器,当计数器的值从某个值一直减到 0 的时候,系统就会产生一个复位信号,即 IWDG_RESET。如果在计数没减到 0 之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。 看门狗功能由 VDD 电压域供电,在停止模式和待机模式下仍能工作 。窗口看门狗跟独立看门狗一样,也是一个递减计数器不断的往下递减计数,当减到一个固定值 0X40时还不喂狗的话,产生复位,这个值叫窗口的下限, 是固定的值,不能改变。 这个是跟独立看门狗类似的地方,不同的地方是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗,这就是窗口看门狗中窗口两个字的含义 。这是野火教程给的解释。

记下来我们进入正题:

实验一:独立看门狗

实验原理:

功能框图如下:

①:独立看门狗的时钟由独立的RC振荡器提供LSI提供。主时钟发生故障时依然有效。另外就是LSI的频率在不同的温度和工作场合有漂移,因此看门狗适用于时间精确度低的场合。

②:递减寄存器的时钟由LSI经过寄存器IWDG_PR 分频得到。计数器时钟CK_CNT= 40/ 42^PRV,一个计数器时钟计数器就减一。

③:

④:重装载寄存器里面装着要刷新到计数器的值。这个值决定着独立看门狗的溢出时间。超时时间 Tout = (42^prv) / 40 * rlv (s) , prv 是预分频器寄存器的值, rlv 是重装载寄存器的值。

⑤:键寄存器作为看门狗的控制寄存器有三种模式:

要说明的是:写0XCCCC时是软件启动,一旦启动看门狗,只有复位才能关闭。

⑥:略。

看门狗的使用:一个程序运行的时间是50ms,我们设置的溢出时间是60ms,如果超过60ms还没有喂狗,就意味着程序跑飞了,系统就会自动复位。而后重新进行。

2.实验代码讲解:

.c中的代码如下

#include "bsp_iwdg.h"// 超时时间计算:Tout = prv / 40 * rlv// prv 可以取下列值:4,8,16,32,64,128,256,256// IWDG_Prescaler_4: IWDG prescaler set to 4// IWDG_Prescaler_8: IWDG prescaler set to 8// IWDG_Prescaler_16: IWDG prescaler set to 16// IWDG_Prescaler_32: IWDG prescaler set to 32// IWDG_Prescaler_64: IWDG prescaler set to 64// IWDG_Prescaler_128: IWDG prescaler set to 128// IWDG_Prescaler_256: IWDG prescaler set to 256// 形参 rlv用来设置重装载寄存器 IWDG_RLR的 值 , 取 值 范 围 为0~0XFFF 。//初始化函数void IWDG_Config(uint8_t prv, uint16_t rlv){// 使能 预分频器PR 和 重装载寄存器RLR 可写。IWDG_WriteAccessCmd( IWDG_WriteAccess_Enable );// 设置 预分频器值IWDG_SetPrescaler( prv );// 设置 重装载寄存器的值IWDG_SetReload( rlv );// 把重装载寄存器的值放到计数器中IWDG_ReloadCounter();// 使能 IWDGIWDG_Enable();} // 喂狗函数void IWDG_Feed(void){//把重装载寄存器的值放到计数器中,防止IWDG复位//当计数器的值减到零时,系统会复位IWDG_ReloadCounter();}

.h中的代码如下:

#ifndef __BSP_IWDG_H#define __BSP_IWDG_H#include "stm32f10x.h"void IWDG_Feed(void);void IWDG_Config(uint8_t prv,uint16_t rlv);#endif /* __BSP_IWDG_H */

main.c中的文件如下:

//来到这里的时候,系统的时钟已经配置成72M。LED1_GPIO_Config();LED2_GPIO_Config();GPIO_SetBits(LED2_G_GPIO_PORT, LED2_G_GPIO_PIN); //开始时,关闭绿灯SysTick_Delay_ms(1500); // 延时 1.5 毫秒// 检查看门狗是否复位if( RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET ){// 看门狗复位时亮绿灯LED2_OFF;// 清除标志RCC_ClearFlag();// 如果一直不喂狗,会一直复位,加上前面的延时,会看到红灯闪烁}else {// 不是独立看门狗复位时(可能为上电复位或手动复位),LED2_ON;SysTick_Delay_ms(500);LED2_OFF;SysTick_Delay_ms(500);}KEY1_GPIO_Config();IWDG_Config( IWDG_Prescaler_64 , 625 ); // prv = IWDG_Prescaler_64 ,rlv = 625 1秒的溢出时间while( 1 ){// 以上代码为被监控的代码if(Key1_Scan(KEY1_GPIO_PORT ,KEY1_GPIO_PIN) == KEY1_ON ){//喂狗操作,如果不喂狗,系统会复位,LED1则会灭一次,如果在一秒的时间内准时喂狗,绿灯会常亮IWDG_Feed();// 绿灯会常亮LED2_OFF;}}

3.实验现象:

我们设置的溢出时间是1秒,如果在1秒的时间内没有按下按键,那么程序就会在main.c中执行while(1)之前的程序,一直循环,我们就会看到绿灯闪烁的情况。如果在1秒内不停按下了按键,(阻止了递减计数器减到零,程序就不会复位。)那么绿灯就会一直亮着。(限于材料有限,if和else中的程序均由绿灯完成,请多包含!)

实验二:窗口看门:

开始之前,先来了解一下什么是窗口看门狗:

TR是窗口看门狗的计数器的值, WR 是窗口看门狗的上窗口值,均由用户独立设置。

功能框图:

①窗口看门狗的时钟:窗口看门狗的时钟PCLK1,PCLK1最大是36M。

②计数器的时钟:计数器的时钟由CK计时器经过预分频得到,分频系数由配置寄存器CFR-WDGTB配置,CK计时器的时钟=PCLK1/4096。计数器时钟CNT_CK=PCLK1/4096/(2*WDGTB),那么计数器递减一个数的时间T=1/CNT_CK。

③计数器:计数器手册上讲解的比我想说的更清楚:

④窗口值:下限我们无法改变,能改变的只有上限。而这个值必须介于0X7F到0X40之间。我们要监控的程序段 A 运行的时间为 Ta,当执行完这段程序之

后就要进行喂狗,如果在窗口时间内没有喂狗的话,那程序就肯定是出问题了。一般计数器的值TR设置成最大 0X7F,窗口值为 WR,计数器减一个数的时间为 T,那么时间: (TRWR)*T 应该稍微大于 Ta 即可。

⑤计算看门狗超时时间:

窗口看门狗适用于外部不可抗干扰或者程序逻辑错误造成的程序跑飞情况。

2.实验代码讲解:

.c 文件代码如下:

#include "bsp_wwdg.h"// 中断优先级初始化static void WWDG_NVIC_Config(void){NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}// WWDG 配置函数// tr 递减计数器的值,取值范围是0X7F-0X40// wr 窗口值,取值范围为0X7F-0X40// prv 预分频器值,有四种选择:// WWDG_Prescaler_1// WWDG_Prescaler_2// WWDG_Prescaler_4// WWDG_Prescaler_8void WWDG_Config( uint8_t tr,uint8_t wr,uint32_t prv){// 开启WWDG时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);// 设置递减计数器的值WWDG_SetCounter(tr);// 设置预分频器的值WWDG_SetPrescaler(prv);// 设置上窗口的值WWDG_SetWindowValue(wr); // 设置计数器的值,使能WWDGWWDG_Enable(WWDG_CNT); // 清除提前唤醒中断标志位WWDG_ClearFlag(); // 配置WWDG中断优先级WWDG_NVIC_Config(); // 开 WWDG中断WWDG_EnableIT();}void WWDG_Feed(void){// 喂狗,刷新递减计数器的值,设置成最大WDG_CNT = 0X7FWWDG_SetCounter(WWDG_CNT);}

stm32f10x.it.c文件如下:

// WWDG 中断服务函数程序,如果发生了此中断,表示程序已经出现了故障,

// 这是一个死前中断,在此中断服务函数中应该干最重要的事,

// 这个时间具体有多长,看WDGTB的值决定:

// WDGTB:0 113us

// WDGTB:1 227us

// WDGTB:2 445us

// WDGTB:3 910us

void WWDG_IRQHandler(void)

{

//清除中断标志位

WWDG_ClearFlag();

// LED2亮,点亮LED只是示意性操作

// 真正使用的时候,应该是做最重要的事情

LED2_ON; // 这里以绿灯LED2常亮为最重要的事

}

// WWDG 中断服务函数程序,如果发生了此中断,表示程序已经出现了故障,// 这是一个死前中断,在此中断服务函数中应该干最重要的事,// 这个时间具体有多长,看WDGTB的值决定:// WDGTB:0 113us// WDGTB:1 227us// WDGTB:2 445us// WDGTB:3 910usvoid WWDG_IRQHandler(void){//清除中断标志位WWDG_ClearFlag();// LED2亮,点亮LED只是示意性操作// 真正使用的时候,应该是做最重要的事情LED2_ON; // 这里以绿灯LED2常亮为最重要的事}

main.c文件如下:

uint8_t wwdg_tr, wwdg_wr;//来到这里的时候,系统的时钟已经配置成72M。LED1_GPIO_Config();LED2_GPIO_Config();// 开始之前先关闭LED1LED1_ON; // 红灯关// 延时1秒 SysTick_Delay_ms(1000); // 初始化 WWDG ,配置计数器的初始值,配置上窗口值,启动WWDG,使能提前唤醒中断WWDG_Config( 0X7F,0X5F,WWDG_Prescaler_8 ); // 窗口值我们在初始化的时候设置为0X5F,这个值不会改变wwdg_wr = WWDG->CFR & 0X7F; while( 1 ){LED1_OFF; wwdg_tr = WWDG->CR & 0X7F;if( wwdg_tr < wwdg_wr ){// 喂狗,重新设置计数器的值为最大0X7FWWDG_Feed();} }

3.实验现象:

程序执行后LED1亮一段时间后会熄灭,之后就不会亮,而中断函数中的LED2不会灭(LED2指的是板子上的绿灯)。

刚入门,如果有错误,请及时指出,大佬勿喷!

欢迎交流学习,共同进步!

下方是我微信:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。