stm32窗口看门狗中断服务函数为啥不能用延时函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了stm32窗口看门狗中断服务函数为啥不能用延时函数相关的知识,希望对你有一定的参考价值。

参考技术A 你用一下这个代码看一下:
void EXTI0_IRQHandler(void) //key1


Delay_us(10000); //消除抖动
if(KEY1==0)

LED1=!LED1;

EXTI_ClearITPendingBit(EXTI_Line0);



void Delay_us(__IO uint32_t nTime)

TimingDelay=nTime;
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //使能滴答时钟,开始计数

while(TimingDelay!=0);

if(!TimingDelay) //假如计数结束,则关闭滴答时钟
SysTick->CTRL&=(~SysTick_CTRL_ENABLE_Msk);


void SysTick_Handler(void)

if(TimingDelay!=0x00)
TimingDelay--;

19 . 窗口看门狗(WWDG)实验

窗口看门狗(WWDG)实验

上一篇我们介绍了独立看门狗IWDG,这一篇我们来学习下窗口看门狗(以下简称WWDG)。要实现的功能是:使用窗口看门狗的中断来喂狗,通过D1、D2 指示灯提示程序运行状态。学习本章可以参考《STM32F10x 中文参考手册》-18窗口看门狗(WWDG)章节。分为如下几部分内容:

1 WWDG 介绍
2 WWDG 配置步骤
3 硬件设计
4 软件设计

WWDG 介绍

WWDG 简介
上一章我们已经介绍了IWDG,知道它的工作原理就是一个12 位递减计数器不断递减计数,当减到0 之前还未进行喂狗的话,产生一个MCU 复位。窗口看门狗WWDG 其实和独立看门狗类似,它是一个7 位递减计数器不断的往下递减计数,当减到一个固定值0X40 时还不喂狗的话,产生一个MCU 复位,这个值叫窗口的下限,是固定的值,不能改变。这个和独立看门狗是类似的,不同的是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间才可以刷新(喂狗),这也是窗口看门狗中“窗口”两个字的含义。窗口看门狗时序图如图24.1.1 所示:

窗口看门狗时序图
从图24.1.1 可以看到,T[6:0]是窗口控制寄存器(WWDG_CR)的低7 位,W[6:0]是窗口配置寄存器(WWDG_CFR)低7 位。T[6:0]就是窗口看门狗的计数器值,而W[6:0]是窗口看门狗的上窗口,下窗口是固定值0X40。当窗口看门狗的计数器在上窗口值之外或者低于下窗口值被刷新都会产生复位。上窗口值(W[6:0])是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保窗口值大于0X40,否则窗口就不存在了。窗口看门狗WWDG 通常被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。

WWDG 结构框图
要更好的理解窗口看门狗,就需要了解它内部的结构,如图所示:

WWDG 结构框图
我们把WWDG 结构框图分成5 个子模块,按照顺序依次进行简单介绍。
(1)标号1:WWDG 时钟
窗口看门狗(WWDG)的时钟来自PCLK1,即挂接在APB1 总线上,由RCC 时钟控制器开启。APB1 时钟最大为36M。
(2)标号2:WDG 预分频器器
PCLK1 时钟并不是直接提供给窗口看门狗计数器时钟,而是通过一个WDG 预分频器分频后输入给计数器时钟。我们可以操作配置寄存器WWDG_CFR 的位8:7WDGTB[1:0]来设置分频因子,分频因子可以为0、1、2、3。分频后的计数器时钟为:CK_CNT= PCLK1/4096/(2^WDGTB),除以4096 是中文参考手册内公式规定,没有为什么。PCLK1 等于APB1 时钟,WDGTB 为分频因子
(0-3),2^WDGTB 大小就是1、2、4、8,与库函数中的分频参数对应。每经过一个计数器时钟,计数器就减1。
(3)标号3:计数器
窗口看门狗的计数器是一个7 位的递减计数器,计数最大值为0X7F,其值存放在控制寄存器WWDG_CR 中的6:0 位,即T[6:0]。当递减到T6 位变成0 时,即从0X40 变为0X3F 时候,会产生看门狗复位。这个值0X40 是窗口看门狗能够递减到的最小值,所以计数器的值只能在0X40~0X7F 之间,实际上用来计数的是T[5:0]。当递减计数器递减到0X40 的时候,还不会马上产生复位,如果使能了提前唤醒中断,窗口配置寄存器(WWDG_CFR)位9 EWI 置1,则产生提前唤醒中断,也就是在快产生复位的前一段时间提醒我们,需要进行喂狗了,否则将复位。我们通常都是在提前唤醒中断内向WWDG_CR 重新写入计数器的值,来达到喂狗的目的。需要注意的是:在进入中断后,必须在不大于1 个窗口看门狗计数周期的时间(在PCLK1 频率为36M 且WDGTB 为0 的条件下,该时间为113us)内重新写WWDG_CR,否则,看门狗将产生复位!如果不使用提前唤醒中断来喂狗,我们要会计算窗口看门狗的超时时间,计算公式如下:
Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /PCLK1;
其中:
Twwdg 为窗口看门狗的超时时间,单位为ms。
PCLK1 为APB1 的时钟频率,最大36MHz。
WDGTB 为窗口看门狗的预分频系数。
T[5:0]为窗口看门狗的计数器低6 位。
根据上面的公式,假设PCLK1=36Mhz,那么可以得到最小-最大超时时间表,如下:

(4)标号4:看门狗配置寄存器
我们知道窗口看门狗必须在窗口范围内进行喂狗才不会产生复位,窗口中的下窗口是一个固定值0X40,上窗口值可以改变,具体的由配置寄存器WWDG_CFR的位W[6:0]设置。其值必须大于0X40,如果小于或者等于0X40 就是失去了窗口的意义,而且也不能大于计数器的最大值0X7F。窗口值具体要设置成多大,这个得根据我们需要监控的程序的运行时间来决定。假如我们要监控的程序段A运行的时间为Ta,当执行完这段程序之后就要进行喂狗,如果在窗口时间内没有喂狗的话,那程序就肯定是出问题了。一般计数器的值TR 设置成最大0X7F,窗口值为WW,计数器减一个数的时间为T,那么时间:(TR-WW)*T 应该稍微大于Ta 即可,这样就能做到刚执行完程序段A 之后喂狗,起到监控的作用,这样也就可以算出WW 的值是多少。
(5)标号5:系统复位信号
当计数器值超过配置寄存器内的上窗口设置值或者低于下窗口值,并且WDGA 位置1,即开启窗口看门狗,将产生一个系统复位信号,促使系统复位。由于篇幅限制, 本章并没有对相关寄存器进行介绍,大家可以参考《STM32F10x 中文参考手册》-18 窗口看门狗(WWDG)章节,里面有详细的讲解。如果看不懂的可以暂时放下,因为我们使用的是库函数开发。

WWDG 配置步骤

接下来我们介绍下如何使用库函数对WWDG 进行配置。这个也是在编写程序中必须要了解的。具体步骤如下:(WWDG 相关库函数在stm32f10x_wwdg.c 和stm32f10x_wwdg.h 文件中)
(1)使能WWDG 时钟
WWDG 不同于IWDG,IWDG 有自己独立的LSI 时钟,所以不存在使能问题,而WWDG 使用的是APB1 时钟,需要先使能时钟。在库函数中实现函数如下:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);

(2)设置WWDG 窗口值和分频数设置WWDG 窗口值函数为:

void WWDG_SetWindowValue(uint8_t WindowValue);

窗口值最大值为0X7F,最小不能低于0X40,否则就失去了窗口的意义。设置WWDG 分频数函数为:

void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);

分频系数可以为WWDG_Prescaler_1 、WWDG_Prescaler_2 、WWDG_Prescaler_4、WWDG_Prescaler_8。
(3)开启WWDG 中断并分组
通常对窗口看门狗进行喂狗是在提前唤醒中断内操作,所以需要打开WWDG的中断功能,并且配置对应的中断通道及分组。
中断分组及通道选择是在NVIC_Init 初始化内完成,这个在前面章节中都介绍过,这里我们看下使能WWDG 中断,库函数如下:

WWDG_EnableIT();

(4)设置计数器初始值并使能WWDG库函数中提供了一个同时设置计数器初始值和使能WWDG 的函数,如下:

void WWDG_Enable(uint8_t Counter);

注意计数器最大值不能大于OX7F。库函数还提供了一个独立设置计数器值的函数,如下:

void WWDG_SetCounter(uint8_t Counter);

(5)编写WWDG 中断服务函数
最后我们还需要编写一个WWDG 中断服务函数,通过中断函数进行喂狗。WWDG中断服务函数名在STM32F1 启动文件内就有,WWDG 中断函数名如下:

WWDG_IRQHandler

在中断内要进行喂狗,可以直接调用WWDG_SetCounter()函数,给它传递一个窗口值即可,特别注意,在中断内喂狗一定要快,否则当看门狗计数器值减到0X3F 时将产生复位。然后清除WWDG 中断状态标志位EWIF,函数如下:

WWDG_ClearFlag(); //清除窗口看门狗状态标志

通过以上几步配置后,我们就可以正常使用窗口看门狗了,我们需要在中断内快速喂狗,否则系统即会重新启动。

硬件设计

由于WWDG 是STM32F1 内部资源,因此本硬件电路非常简单,只有D1、D2指示灯连接,对应的电路图在前面章节中都有介绍,这里就不多说。D1 指示灯用来提示系统是否被复位,D2 指示灯用来作为喂狗提示,每进入中断喂狗D2 指示灯状态翻转一次。

软件设计

本章所要实现的功能是:系统开启时D1 指示灯点亮500ms 时间,然后熄灭。D2 指示灯不断闪烁表示正在喂狗。如果喂狗超时将重启系统,D1 指示灯点亮500ms,然后熄灭,继续喂狗。程序框架如下:
(1)初始化WWDG(使能WWDG 时钟,设置窗口及分频值,使能中断等)
(2)编写窗口看门狗中断函数
(3)编写主函数
在前面介绍WWDG 配置步骤时,就已经讲解如何开启WWDG、设置窗口及分频值等。下面我们打开“\\4–实验程序\\库函数版\\17. 窗口看门狗实验”工程,在APP 工程组中可以看到添加了wwdg.c 文件,在StdPeriph_Driver 工程组中添加了stm32f10x_wwdg.c 库文件。窗口看门狗操作的库函数都放在stm32f10x_wwdg.c 和stm32f10x_wwdg.h 文件中,所以使用到窗口看门狗就必须加入stm32f10x_wwdg.c 文件,同时还要包含对应的头文件路径。

WWDG 初始化函数
要使用WWDG,我们必须先对它进行配置。WWDG 初始化代码如下:

/****************************************************************
***************
* 函数名: WWDG_Init
* 函数功能: WWDG 初始化窗口值是:0x5f
定时器计数值是:0x7f
预分频值是:8
窗口看门狗进入中断的频率计算公式是:PCLK1/(4096*2^pre)
* 输入: 无
* 输出: 无
*****************************************************************
**************/
void WWDG_Init(void)

NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); //开启窗口看门狗的时钟
WWDG_SetWindowValue(0x5f);//设置窗口值
WWDG_SetPrescaler(WWDG_Prescaler_8);//设置分频值
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;//窗口中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化NVIC 寄存器
WWDG_Enable(0x7f); //使能窗口看门狗并初始化计数器值
WWDG_ClearFlag(); //清除窗口看门狗状态标志(这一句必须加上,否则进入不了中断)
WWDG_EnableIT(); //开启中断

在WWDG_Init()函数中,首先使能WWDG 时钟,设置WWDG 窗口值为0X5F,分频值为WWDG_Prescaler_8,然后设置中断分组并开启中断,最后设置计数器值为0X7F 并使能WWDG。这一过程在前面步骤介绍中已经提了。
窗口看门狗中断函数
初始化WWDG 后,中断就已经开启了,当窗口看门狗计数器递减到0X40 时,就会产生一次提前唤醒中断,具体代码如下:
/****************************************************************


  • 函数名: WWDG_IRQHandler
  • 函数功能: WWDG 中断函数
  • 输入: 无
  • 输出: 无

/
void WWDG_IRQHandler(void)

WWDG_SetCounter(0x7f); //重新赋值
WWDG_ClearFlag(); //清除窗口看门狗状态标志
led2=!led2;

在中断内必须快速进行喂狗,也就是重新对窗口看门狗计数器赋值。然后清
除中断状态标志,这里我们使用一个D2 指示灯来提示喂狗,如果喂狗D2 指示灯
状态翻转一次。
24.4.3 主函数
编写好窗口看门狗初始化和中断函数后,接下来就可以编写主函数了,代码
如下:
/
**************************************************


  • 函数名: main
  • 函数功能: 主函数
  • 输入: 无
  • 输出: 无

**************/
int main()

SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组分2 组
LED_Init();
USART1_Init(9600);
led1=0;
delay_ms(500);
WWDG_Init();
while(1)

led1=1;


主函数实现的功能很简单,首先调用之前编写好的硬件初始化函数,包括SysTick 系统时钟,中断分组,LED 初始化等。然后让D1 指示灯点亮500ms,再调用我们前面编写的WWDG 初始化函数,最后进入while 循环,关闭D1 指示灯。在主函数内并没有看到喂狗操作,这是因为我们使用窗口看门狗中断进行喂狗,当计数器递减到0X40 时,进入中断喂狗,D2 指示灯状态翻转一次,如果喂狗失败,将使系统复位,那么D1 指示灯又会点亮500ms 后熄灭。

以上是关于stm32窗口看门狗中断服务函数为啥不能用延时函数的主要内容,如果未能解决你的问题,请参考以下文章

STM32:模拟看门狗只触发一次中断HAL_ADC_LevelOutOfWindowCallback

06 STM32F4的窗口看门狗(WWDG)

STM32窗口看门狗

STM32学习小记之独立看门狗(IWDG)

STM32学习小记之独立看门狗(IWDG)

STM32学习小记之窗口看门狗(WWDG)