[DAY 28] _看门狗简介_视窗看门狗(2)

昨天主要介绍了视窗看门狗和独立看门狗的差别,今天来看这如何计算,这计算方式再参考手册里面有举例说明,如下图:
https://ithelp.ithome.com.tw/upload/images/20211011/20141979i3lHJcz5kw.png
从图的下方可以看到,他已Tpclk=48MHz来举例,最下有个式子48000k,这手册没标示出来我也不知道位什麽?或许这是常识?...哈哈刚开始怀疑了一下子为甚麽是48000,经过按计算机才确定那是指48M分之1。

WWDG如何用:

WWDG一般用来监测外部干扰或不可预见的逻辑条件,造成的应用程序背离正常的运行序列而产生的软件故障。
假设一个程序段正常运行的时间是50ms,在运行完这个段程序之後紧接着进行喂狗,如果在规定的时间视窗内还没有喂狗,那就说明我们监控的程序出故障了,那麽就会产生系统重置,让程序重新运行。

WWDG实验:

硬体需两个LED来观看喂狗状态。

bsp_wwdg.h

#ifndef __WWDG_H
#define	__WWDG_H

#include "stm32f0xx.h"

void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv);
void WWDG_Feed(void);

#endif 

宣告两个函式,初始化WWDG,喂狗

再来看中断的部分

stm32f4xx_it.c

void WWDG_IRQHandler(void)
{
	// 清除中断标志位元
	WWDG_ClearFlag();
	
	//黄灯亮,点亮LED只是示意性的操作,
	//真正使用的时候,这里应该是做最重要的事情
	LED1_ON; 
}

bsp_wwdg.c

#include "./wwdg/bsp_wwdg.h"   

static uint8_t wwdg_cnt;             //用於记录看门狗 递减计数器的值,方便喂狗函数直接使用

static void WWDG_NVIC_Config(void)   // WWDG 中断优先顺序初始化
{
  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);
}

在递减计数器减到0X40的时候,我们开启了提前唤醒中断,这个中断我们称它为死前中断或者叫遗嘱中断,在中断函数里面我们应该出来,是很重要的事情而且必须得快,因为递减计数器再减一次,就会产生系统重置。

void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
{	
	wwdg_cnt = tr;   //保存CNT配置,用在喂狗函数
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // 开启 WWDG 时钟

	WWDG_SetPrescaler(prv);              // 设置预分频器的值
	WWDG_SetWindowValue(wr);             // 设置上视窗值              
	WWDG_Enable(tr);	                 // 设置计数器的值,使能WWDG
	WWDG_ClearFlag();	                 // 清除提前唤醒中断标志位元
	WWDG_NVIC_Config();	 	             // 配置WWDG中断优先顺序
	WWDG_EnableIT();                     // 开WWDG 中断
}
void WWDG_Feed(void)   // 喂狗
{
	WWDG_SetCounter( wwdg_cnt ); // 喂狗,刷新递减计数器的值,设置成最大WDG_CNT=0X7F
}

void WWDG_Config,来解释这函式里的三个数值要填怎样的数值
WWDG 配置函数
tr :递减计时器的值, 取值范围为:0x7f~0x40,超出范围会直接复位
wr :视窗值,取值范围为:0x7f~0x40
prv:预分频器值,取值可以是
WWDG_Prescaler_1: WWDG counter clock = (PCLK1(45MHz)/4096)/1 约10968Hz 91us
WWDG_Prescaler_2: WWDG counter clock = (PCLK1(45MHz)/4096)/2 约5484Hz 182us
WWDG_Prescaler_4: WWDG counter clock = (PCLK1(45MHz)/4096)/4 约2742Hz 364us
WWDG_Prescaler_8: WWDG counter clock = (PCLK1(45MHz)/4096)/8 约1371Hz 728us
例:tr = 127(0x7f,tr的最大值) wr = 80(0x50, 0x40为最小wr最小值) prv = WWDG_Prescaler_8~728 * (127-80) = 34.2ms < 刷新窗口 < ~728 * 64 = 46.6ms也就是说调用WWDG_Config进行这样的配置,若在之後的34.2ms前喂狗,系统会重定,在46.6ms後没有喂狗,系统也会重定。需要在刷新视窗的时间内喂狗,系统才不会重定。再来看main.c

main.c

#include "stm32f0xx.h"
#include "bsp_led.h" 
#include "bsp_wwdg.h"

int main(void)
{
    uint8_t wwdg_tr, wwdg_wr;
	LED_GPIO_Config();  // LED_GPIO初始化
	
	LED2_ON();   //LED2量
	delay_ms(20); 

	WWDG_Config(127,80,WWDG_Prescaler_8); // 初始化WWDG
    wwdg_wr = WWDG->CFR & 0X7F;   //视窗值我们在初始化的时候设置成0x5F,这个值不会改变
	while(1)
	{
	  LED2(OFF);
      
	  wwdg_tr = WWDG->CR & 0X7F;
	  if( wwdg_tr < wwdg_wr )
	  {
	   WWDG_Feed(); // 喂狗,重新设置计数器的值为最大0X7F
	  }
	}
}

烧入後的动作:
把编译好的程序下载到开发板,LED2 被点亮一段时间之後熄灭,之後LED2 一直就没有被点亮过,说明系统没有产生重定,如果产生重置的话LED2会再被点亮一次。中断服务程序中的LED1也没被点亮过,说明喂狗正常。

看门狗的介绍就到这了,目前我在练习韧体还没实际用到这个功能。


<<:  开始建立专案

>>:  Day 29:开始来学资料系结:使用目前所学,来个简单实作吧!(三)

Day 17 - Error Handling 错误处理

前言 错误处理往往是最容易被忽略的一块,因为 程序运行顺利,那当然不用考虑 error case 程...

第48天-学习 crontab 工作排程

今天进度 鸟哥私房菜 - 第十五章、例行性工作排程(crontab) 我在 Crontab.guru...

英雄列表范例:载入资料

接下来我要用一个小应用来介绍基本的 CRUD 实作:复仇者英雄列表。它的功能如下: 新增英雄到列表中...

【Day 08】基本程序介绍

我们回到第三天建立专案那天写的echo程序码。 结果如下: 主程序 Text Message 我们再...

[影片]第29天:物件导向程序设计-可以为null 的数值型态(实例112、113)

4.8 可以为null 的数值型态 实例112 存取可以为null的数值型态 实例113 为Nul...