STM32-自学笔记(15.窗口看门狗)

发布者:Tianran2021最新更新时间:2022-04-18 来源: eefocus关键字:STM32  窗口看门狗  死循环 手机看文章 扫描二维码
随时随地手机看文章

概述:

再由单片机为核心构成的微型计算机系统中,单片机常常会受到来自外界电磁场的干扰,造成程序跑飞,致使程序的正常运行状态被打断而陷入死循环,使得由单片机控制的系统无法继续正常工作,造成整个系统的停滞,发生不可预料的后果。


所以,出于对单片机运行状态进行实时检测的考虑,便产生了一种专门用于检测单片机程序运行状态的硬件结构,俗称“看门狗”。STM32微控制配备了2只看门狗,分别是窗口看门狗和独立看门狗。


窗口看门狗简称WWDG,是Window Watch Dog的缩写。WWDG的核心是一个6位定时计数器,其特性如下:

  • 内置一个可编程的、自由运行的递减计数器。

  • 复位条件:当递减计数器的值小于0x40,(若看门狗已被启用)则产生复位;当递减计数器在窗口外被重新装载,(若看门狗被启动)则产生复位。

  • 如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),此中断服务可以被用于重装载计数器以避免发生WWDG复位。

WWDG结构简图

看门狗控制寄存器中的T[6:0]存放的是WWDG当前计数值,其会在PCLK1经过分频器之后所产生的时钟驱动下进行递减计数。当即数值递减至0x40,则会请求一次看门狗早期唤醒中断(可以在该中断服务中进行喂狗操作)。而当计数值继续递减至0x3F时,就会产生一次WWDG复位。而W[6:0]存放的是WWDG计数比较值,当T[6:0]中存放的值大于W[6:0]中存放的值时进行喂狗操作,同样会产生一次看门狗中断。这就是“窗口”的含义:喂狗操作必须是当前计数值在W[6:0]与0x3F之间进行才不会发生看门狗复位。从程序的角度来说,即无论是过早还是过晚的进行喂狗操作,都将引发一次看门狗复位。这正是STM32的WWDG最大的特点。


WWDG的驱动时钟来自PCLK1。这就是WWDG正常运行的必要条件——当PCLK1发生故障,则看门狗就停止了工作。因此WWDG一般用于整个程序中某个局部的检测。


实验设计

验证STM32微控制器窗口看门狗的复用功能。初始化各个设备之后,在看门狗早期唤醒中断服务中进行喂狗操作。同时配置一个外部中断EXTI0,并赋予其比窗口看门狗早期唤醒中断更为高级的先占优先级。当EXTI0触发即可停止喂狗操作,则理应很快发生一次窗口看门狗复位事件。以上信息使用串口向上位机打印。

硬件电路

软件设计(程序设计)

注意要点:

  • 配置RCC寄存器组,设置PCLK1频率为36MHz(即PLL输出72MHz后进行2分频)。

  • 打开WWDG时钟,注意WWDG属于APB1总线设备(最大速度36MHz)。

  • 配置WWDG,预分频值为8,并写入初始计数值(本次实验写入0x7F)。

  • 配置GPIO、EXTI、USART等外设。

  • 给WWDG的早期唤醒中断赋予较低先占优先级,同时给予EXTI中断赋予较高先占优先级。

对于WWDG的配置来说,最重要的无疑是其溢出时间和初始计数值之间的关系。现基于以上提出的几点要点来进行一次计算的示例。

  1. 上述要点提及WWDG属于APB1总线设备,即表示其时钟来自于PCLK1,最大为36MHz,因此PCLK1为36MHz。

  2. 在PCLK1驱动看门狗计时之前,首先要经过既定的4096分频,在经过Prescaler=8分频(上述第3点),由此不难得到看门狗的计数频率为:          f = PCLK / 4096 / Prescaler = 36MHz / 4096 / 8 = 244Hz

  3. 则可以得到进行一次计数的时间约为:T = 1 / f = 4ms

  4. 上述第三点还提及将初始计数值设为0x7F,则由前面所知,当看门狗计数值从0x40跳变至0x3F时发生看门狗复位,则计算出了看门狗从启动计数到发生溢出复位的时间为:T1=4ms*(0x7F-0x3F)=264ms

  5. T1便是本次软件设计所设定的看门狗溢出复位时间,所以用户程序的喂狗周期不能大于264ms,否则将发生看门狗复位。


主函数  main.c


#include "stm32f10x_lib.h"

 

#include "stdio.h"

 

void RCC_Configuration (void);

 

void NVIC_Configuration (void);

 

void GPIO_Configuration (void);

 

void EXTI_Configuration (void);

 

void USART_Configuration (void);

 

void WWDG_Configuration (void);

 

int main (void)

 

{

 

RCC_Configuration ();         //设置系统时钟

 

NVIC_Configuration ();        //设置GPIO端口

 

GPIO_Configuration ();        //设置NVIC

 

EXTI_Configuration ();        //设置EXTI

 

USART_Configuration ();       //设置USART

 

//检查是否发生过窗口看门狗复位,是则进入if()内部,否则进入else内部

 

if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST)!=RESET)

 

{

 

printf("rn The STM32 has been reset by WWDG  rn");

 

RCC_ClearFlag();     //清除看门狗复位标志

 

}

 

else

 

{

 

WWDG_Configuration ();      //设置WWDG

 

printf("rn The STM32 has been reset by WWDG before /r/n");

 

}

 

while(1);

 

}

 

 

 

设置系统各部分时钟   RCC_Configuration


void RCC_Configuration(void)

 

{

 

ErrorStatus HSEStartUpStatus;      //定义枚举类型变量 HSEStartUpStatus

 

RCC_DeInit();                     //复位系统时钟设置

 

RCC_HSEConfig(RCC_HSE_ON);         //开启HSE

 

HSEStatrtUpStatus=RCC_WaitForHSEStartUp();   //等待HSE起振并稳定

 

if(HSEStatrtUpStatus==SUCCESS)     //判断HSE是否起振成功,是则进入if()内部

 

{

 

RCC_HCLKConfig(RCC_SYSCLK_Div1);   //选择HCLK(AHB)时钟源为SYSCLK分频

 

RCC_PCLK2Config(RCC_HCLK_Div1);    //选择PCLK2时钟源为HCLK(AHB)1分频

 

RCC_PCLK1Config(RCC_HCLK_Div2);    //选择PCLK1时钟源为HCLK(AHB)2分频

 

FLASH_SetLatency(FLASH_Latency_2);  //设置Flash延时周期数为2

 

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);   //使能Flash预取缓存

 

//选择PLL时钟源为 HSE 1 分频,倍频数为9,则PLL=8MHz *9=72MHz

 

RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);

 

RCC_PLLCmd(ENABLE);                  //使能PLL

 

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);  //等待PLL输出稳定

 

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);    //选择SYSCLK时钟源为PLL

 

while(RCC_GetSYSCLKSource()!=0x08);      //等待PLL成为SYSCLK时钟源

 

}

 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);     //打开APB1总线上的窗口看门狗时钟

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);    //打开APB2总线上的GPIOA和USART1时钟

 

}

设置各GPIO端口功能    GPIO_Configuration (void)


void GPIO_Configuration(void)

 

{

 

GPIO_InitTypeDef GPIO_InitStructure;

 

//设置PA.0为上拉输入(EXTI Line0)

 

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;

 

GPIO_InitStructure.GPIO_Mode=GPIO_Mode__IPU;

 

GPIO_Init(GPIOA,&GPIO_InitStructure);

 

//定义PA.0为外部中断0输入通道(EXTI0)

 

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

 

//设置USART1的Tx脚(PA.9)为第2功能推挽输出功能

 

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;

 

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

 

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

 

GPIO_Init(GPIOA,&GPIO_InitStructure);

 

//设置USART1的Rx脚(PA.10)为浮空输入脚

 

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_10;

 

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

 

GPIO_Init(GPIOA,&GPIO_InitStructure);

 

}

设置EXTI参数    EXTI_Configuration


void EXTI_Configuration(void)

 

{

 

//定义EXTI初始化结构体EXTI_InitStructure

 

EXTI_InitTypeDef EXTI_InitStructure;

 

//设置外部中断0通道(EXTI_Line0)在下降沿时触发中断

 

EXTI_InitStructure.EXTI_Line=EXTI_Line0;

 

EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;

 

EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;

 

EXTI_InitStructure.EXTI_LineCmd=ENABLE;

 

EXTI_Init(&EXTI_InitStructure);

 

//定义PA.0为外部中断0输入通道(EXIT0)

 

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

 

}

设置WWDG参数   WWDG_Configuration


void WWDG_Configuration(void)

 

{

 

设置WWDG预分频值为8,WWDG时钟频率=(PCLK1/4096)/8=244Hz(约4ms)

 

WWDG_SetPrescaler(WWDG_Prescaler_8);

 

//设置WWDG初始计数值为0x7F并启动WWDG,此时WWDG超时时间为4ms*(0x7F-0x3F)=264ms

 

WWDG_Enable(0x7F);

 

WWDG_ClearFlag();    //清除WWDG早期唤醒中断(EWI)标志

 

WWDG_EnableIT();     //使能WWDG早期唤醒中断(EWI)

 

}

设置NVIC参数   NVIC_Configuration


void NVIC_Configuration(void)

 

{

 

//定义NVIC初始化结构体NVIC_InitStructure

 

NVIC_InitTypeDef NVIC_InitStructure;

 

//使用优先级分组2

 

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

 

//使能外部中断0通道(EXIT0),0级先占优先级,0级次占优先级

 

NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQChannel;

 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;

 

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

 

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

 

NVIC_Init(&NVIC_InitStructure);

 

//使能窗口看门狗(WWDG)中断,1级先占优先级

 

NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQChannel;

 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;

 

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

 

NVIC_Init(&NVIC_InitStructure);

 

}

设置USART1  USART_Configuration


void USART_Configuration(void)

 

{

 

USART_InitTypeDef USART_InitStructure;       //定义USART初始化结构体USART_InitStructure

 

USART_ClockInitTypeDef USART_ClockInitStructure;  //定义USART初始化结构体USART_ClockInitStructure

 

//波特率为9600bps;8位数据长度,1个停止位,无检验位;禁用硬件流控制;禁止USART时钟;时钟极性低;在第2个边沿捕获数据;最后一位数据的时钟脉冲不从SCLK输出

 

USART_InitStructure.USART_BaudRate=9600;

 

USART_InitStructure.USART_WordLength=USART_WordLength_8b;

 

USART_InitStructure.USART_StopBits=USART_StopBits_1;

 

USART_InitStructure.USART_Parity=USART_Parity_NO;

 

USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;

 

USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;

 

USART_Init(USART1,&USART_InitStructure);

 

USART_Cmd(USART1,ENABLE);         //使能USART1

 

}

将printf函数重定位到USART1     fputc


int fputc (int ch,FILE*f)

 

UASRT_SendData(USART1,(u8)ch);

 

while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);

 

return ch;

中断服务程序


头文件


#include "stm32f10x_it.h"

 

#include"stdio.h"

 

看门狗早期唤醒中断服务函数  WWDG_IRQHandler


void WWDG_IRQHandler (void)

 

{

 

WWDG_SetCounter(0x7F);      //更新WWDG计数器

 

WWDG_ClearFlag();           //清除WWDG早期唤醒中断(EWI)标志

 

printf("rn The Windows Watch Dog Has been flash rn");

 

}

外部中断0中断服务函数     EXTI0_IRQHandler


void EXTI0_IRQHandler (void)

 

{

 

while(1)

 

}



注意事项:

  1. 窗口看门狗是否产生复位操作,取决于定时计数器的值是否小于0x40,也就是窗口看门狗控制寄存器中的T6位是否为0,因此写入小于0x40的初始计数会马上发生一次复位操作。


  2. 窗口看门狗的复位相当于一次软复位,复位前WWDG各个寄存器的状态都将得到保留,因此在复位后,要首先将看门狗复位标志清除掉。


  3. 注意窗口看门狗启用之后在下一次复位事件产生之前不可以被禁用。


  4. 默认情况下,即使STM32进入调试状态窗口看门狗仍然会运行,这将导致调试出错。

  5. 在开启窗口看门狗的情况下进行程序跟踪调试的读者应该注意这点。


  6. 如果程序中需要处理比较多的中断服务,请合理安排窗口看门狗的中断优先级。推荐的做法是:设置比较长的喂狗周期,同时赋予看门狗比较高的中断优先级。


关键字:STM32  窗口看门狗  死循环 引用地址:STM32-自学笔记(15.窗口看门狗)

上一篇:STM32-自学笔记(12.通过串口与PC通信,发Hello,程序用到的库函数介绍)
下一篇:STM32-自学笔记(19.DMA——存储器直接存取,让数据传输更上一层楼)

推荐阅读最新更新时间:2024-11-06 00:24

stm32定时器1的2路互补PWM
void TIM1_PWM_Ini(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; //开启时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //使能定时器3时钟 RCC_APB2PeriphClockC
[单片机]
征服stm32 can 标准帧 扩展帧 过滤器配置
如果过滤器配置不好,就会导致发送的数据接收不到,下面是过滤器配置的代码 //配置过滤器 CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位 /*******************************标准帧配置***********************************
[单片机]
stm32开发板开发笔记(4)-启动设置
stm32有个启动引脚Boot0和Boot1,用于设置代码的启动位置 如下图 Boot0位于94脚,是专门的Boot脚,Boot1位于37脚,和PB2复用, Boot1 Boot0 x 0: boot0为0,boot1为任意值,代码从内部程序存储区启动 0 1:代码从系统存储区启动(ISP代码区) 所以将Boot0对地短路,只需改变Boot1就能改变启动方式。 当前主板上MAX232,所以用USB转串口接上主板,配合Flymcu软件,可以读出和擦除当中的信息,但是烧写中间会出错。 FlyMcu(www.mcuisp.com) 可能是由于延长线的问题或USB转串口的问题,并且发现只有波特率为1
[单片机]
<font color='red'>stm32</font>开发板开发笔记(4)-启动设置
[HAL库]STM32之DMA方式串口发送
目的:使用cube软件实现DMA方式的数据发送和接收 1.在cube Pinout中打开USART1,方式为异步通讯(Asynchronous); 2.在cube Configuration中打开USART1 Configuration,添加DMA通道(接收改为循环方式)以及打开usart的全局中断,在NVIC中调整优先级 3.生成代码,在keil中进行以下修改: 1)在main文件中建立发送缓存区和接收缓存区(两个定常数组) 使用HAL_UART_Receive_DMA(&huart1,aRxBuffer,sizeof(aRxBuffer)) 进行DMA的接收(等待接收) 使用HAL_UART_Transmi
[单片机]
STM32型号参考
startup_stm32f10x_cl.s 互联型的器件,STM32F105xx,STM32F107xx startup_stm32f10x_hd.s 大容量的STM32F101xx,STM32F102xx,STM32F103xx startup_stm32f10x_hd_vl.s 大容量的STM32F100xx startup_stm32f10x_ld.s 小容量的STM32F101xx,STM32F102xx,STM32F103xx startup_stm32f10x_ld_vl.s 小容量的STM32F100xx startup_stm32f10x_md.s 中容量的STM32F101xx,STM32F102xx,STM3
[单片机]
<font color='red'>STM32</font>型号参考
STM32】并、串行通信的区别 串行通信的分类
通信接口背景知识 设备之间通信的方式 一般情况下,设备之间的通信方式可以分成并行通信和串行通信两种。它们的区别是: 并、串行通信的区别 串行通信的分类 1、按照数据传送方向,分为: 单工:数据传输只支持数据在一个方向上传输; 半双工:允许数据在两个方向上传输。但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;它不需要独立的接收端和发送端,两者可以合并一起使用一个端口。 全双工:允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端。 2、按照通信方式,分为: 同步通信:带时钟同步信号传输。比如:SPI,IIC通信接口。 异步通信:不带时钟同步信号。比如
[单片机]
【<font color='red'>STM32</font>】并、串行通信的区别 串行通信的分类
STM32低成本WiFi播放电路设计详解
以STM32F103($2.5718)作为微处理器,设计一个低成本的无线WiFi 音乐播放系统,结合接收WiFi 数据的WM-G-MR-08(wm631)模块和VS1003B 音频解码器实现MP3 音乐播放。基于Android 系统开发的客户端软件采用手机控制,完成手机端与控制端之间的数据传输,实现手机远程对音乐播放器的控制。结果表明,该系统设备简单方便、成本较低、系统可靠、易于扩展。本设计基于已经发展成熟的WiFi 无线网络,充分利用WiFi 覆盖范围广、传输速度快、抗干扰能力强等优点。Android 具有开源性、封装性、性价比高等优点,基于Android 系统开发的客户端软件移植性强,通用性高。采用手机作为控制终端,便于操作。
[单片机]
<font color='red'>STM32</font>低成本WiFi播放电路设计详解
stm32专题三十一:电源管理
stm32的电源管理 上电复位与掉电复位(POR PDR): 这个滞回电压,是为了让单片机容忍一定程度的电压波动,而不是只要电压稍微一变化,就立刻掉电复位。 可编程电压监测器PVD: PVD中断的上升沿或下降沿,表示的是VDD电压是超过阈值还是低于阈值,关于PVD中断的描述如下: stm32电源系统 为了方便进行电源管理,STM32 把它的外设、内核等模块跟据功能划分了供电区域,其内部电源区域划分如图: CPU内核为1.8V供电,以降低功耗,整个1.8V供电区域由电压调节器单独供电,有时CPU可以休眠,有时可以不休眠,这是由电压调节器来提供的。 关于时钟的具体描述: 这里,值得注意的是后备供电区
[单片机]
<font color='red'>stm32</font>专题三十一:电源管理
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved