初学正点原子Ministm32看门狗实验

 这一章,我们将向大家介绍如何使用 STM32 的另外一个看门狗,窗口看门狗。在本章中,我们将使用窗口看门狗的中断功能来喂狗,通过 DS0 和 DS1 提示程序的 运行状态。本章分为如下几个部分:

1 STM32 窗口看门狗简介

2 硬件设计

3 软件设计

一、STM32 窗口看门狗简介

窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6位(WWDG->CR的第六位)变成0前被刷新,看门狗电路在达到预置的时间周期时,会产生一个MCU复位。在递减计数器达到窗口配置寄存器(WWDG->CFR)数值之前,如果7位的递减计数器数值(在控制寄存器中)被刷新, 那么也将产生一个MCU复位。这表明递减计数器需要在一个有限的时间窗口中被刷新。他们的关系可以用下图来说明:

6a4e0b56d08c4cc8b493be6993b718c8.png

上图中,T[6:0]就是WWDG_CR的低七位,W[6:0]即是WWDG->CFR的低七位。T[6:0]就是窗口看门狗的计数器,而W[6:0]则是窗口看门狗的上窗口,下窗口值是固定的(0X40)。当窗口看门狗的计数器在上窗口值之外被刷新,或者低于下窗口值都会产生复位。上窗口值(W[6:0])是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保窗口值大于0X40,否则窗口就不存在了。窗口看门狗的超时公式如下:Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1;其中:Twwdg:WWDG超时时间(单位为ms)Fpclk1:APB1的时钟频率(单位为Khz)WDGTB:WWDG的预分频系数T[5:0]:窗口看门狗的计数器低6位根据上面的公式,假设Fpclk1=36Mhz,那么可以得到最小-最大超时时间表如下所示:

98b16ba89aaa45e3b9c4e5ecf5212a77.png

接下来,我们介绍窗口看门狗的3个寄存器。首先介绍控制寄存器(WWDG_CR),该寄存器的各位描述如图所示:

6686c85bd7cd4daeb0f0a4d1eaded975.png

可以看出,这里我们的WWDG_CR只有低八位有效,T[6:0]用来存储看门狗的计数器值,随时更新的,每个窗口看门狗计数周期(4096×2^ WDGTB)减1。当该计数器的值从0X40变为0X3F的时候,将产生看门狗复位。

WDGA位则是看门狗的激活位,该位由软件置1,以启动看门狗,并且一定要注意的是该位一旦设置,就只能在硬件复位后才能清零了。

窗口看门狗的第二个寄存器是配置寄存器(WWDG_CFR),该寄存器的各位及其描述如图所示:

 2481368c19384ab69f3d8c3e9ed23924.png

该位中的EWI是提前唤醒中断,也就是在快要产生复位的前一段时间(T[6:0]=0X40)来提醒我们,需要进行喂狗了,否则将复位!因此,我们一般用该位来设置中断,当窗口看门狗的计数器值减到0X40的时候,如果该位设置,并开启了中断,则会产生中断,我们可以在中断里面向WWDG_CR重新写入计数器的值,来达到喂狗的目的。注意这里在进入中断后,必须在不大于1个窗口看门狗计数周期的时间(在PCLK1频率为36M且WDGTB为0的条件下,该时间为113us)内重新写WWDG_CR,否则,看门狗将产生复位!

最后我们要介绍的是状态寄存器(WWDG_SR),该寄存器用来记录当前是否有提前唤醒的标志。该寄存器仅有位0有效,其他都是保留位。当计数器值达到40h时,此位由硬件置1。它必须通过软件写0来清除。对此位写1无效。即使中断未被使能,在计数器的值达到0X40的时候,此位也会被置1。

在介绍完了窗口看门狗的寄存器之后,我们介绍要如何启用STM32的窗口看门狗。这里我们介绍库函数中用中断的方式来喂狗的方法,窗口看门狗库函数相关源码和定义分布在文件stm32f10x_wwdg.c文件和头文件stm32f10x_wwdg.h中。步骤如下:

1)使能WWDG时钟

WWDG不同于IWDG,IWDG有自己独立的40Khz时钟,不存在使能问题。而WWDG使用的是PCLK1的时钟,需要先使能时钟。方法是:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  // WWDG时钟使能 

2)设置窗口值和分频数

设置窗口值的函数是:

void WWDG_SetWindowValue(uint8_t WindowValue); 

这个函数就一个入口参数为窗口值,很容易理解。

设置分频数的函数是:

void WWDG_SetPrescaler(uint32_t WWDG_Prescaler); 

这个函数同样只有一个入口参数就是分频值。

3)开启WWDG中断并分组

开启WWDG中断的函数为:

WWDG_EnableIT(); //开启窗口看门狗中断 

接下来是进行中断优先级配置,这里就不重复了,使用NVIC_Init()函数即可。

4)设置计数器初始值并使能看门狗

这一步在库函数里面是通过一个函数实现的:

void WWDG_Enable(uint8_t Counter);

该函数既设置了计数器初始值,同时使能了窗口看门狗。

二、硬件设计

本实验用到的硬件资源有:

1) 指示灯DS0和DS1

2) 窗口看门狗

其中指示灯前面介绍过了,窗口看门狗属于STM32的内部资源,只需要软件设置好即可正常工作。我们通过DS0和DS1来指示STM32的复位情况和窗口看门狗的喂狗情况。

三、软件设计

打开我们的窗口看门狗实验可以看到,相对于独立看门狗,我们只增加了窗口看门狗相关的库函数支持文件stm32f10x_wwdg.c/stm32f10x_wwdg.h,同时新加了wwdg.c源文件和引入了对应的头文件wwdg.h。wwdg.c源文件内容如下:

#include "wwdg.h"
#include "led.h" 
void WWDG_Init(u8 tr,u8 wr,u32 fprer) 
{   RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  
    WWDG_SetPrescaler(fprer);设置 WWDG预分频值 
    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_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.c文件里面三个函数都比较简单,第一个函数void WWDG_Init(u8 tr,u8 wr,u8 fprer)

用来设置WWDG的初始化值。包括看门狗计数器的值和看门狗比较值等。该函数就是按照我们上面的4个思路设计出来的代码。注意到这里有个全局变量WWDG_CNT,该变量用来保存最初设置WWDG_CR计数器的值。在后续的中断服务函数里面,就又把该数值放回到WWDG_CR上。

WWDG_Set_Counter函数比较简单,就是用来重设窗口看门狗的计数器值的。该函数很简单,我们就不多说了。

最后在中断服务函数里面,先重设窗口看门狗的计数器值,然后清除提前唤醒中断标志。最后对LED1(DS1)取反,来监测中断服务函数的执行了状况。我们再把这几个函数名加入到头文件里面去,以方便其他文件调用。

在完成了以上部分之后,我们就回到主函数,代码如下:

#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);  
    uart_init(9600);   
    LED_Init();   
    LED0=0;  
    delay_ms(300);     
    WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);      
    while(1) 
    { 
        LED0=1;
    }
}

该函数通过LED0(DS0)来指示是否正在初始化。而LED1(DS1)用来指示是否发生了中断。我们先让LED0亮300ms,然后关闭以用于判断是否有复位发生了。在初始化WWDG之后,

我们回到死循环,关闭LED1,并等待看门狗中断的触发/复位。

在编译完成之后,我们就可以下载这个程序到MiniSTM32开发板上,看看结果是不是和我们设计的一样。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值