STM32
直播中

王燕

7年用户 1697经验值
私信 关注
[问答]

STM32的看门狗系统是由哪些部分组成的

看门狗电路的基本原理是什么?
STM32的看门狗系统是由哪些部分组成的?

回帖(1)

李娜

2021-9-22 16:41:43
本文大部分内容只用到了键盘的3个按键…你懂的 。 简单总结,Markdown了解一下,推荐。
1.看门狗电路介绍
看门狗电路(watchdog timer),又称监控电路。百度百科解释的很详细:
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成各种寄存器和内存的数据混乱,会导致程序指针错误,不在程序区,取出错误的程序指令等,都会陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续正常工作,会造成整个系统的陷入停滞状态,发生不可预料的后果。
看门狗电路本质上来说就是一个定时器电路,一般有一个输入和一个输出,其中输入叫做喂狗(no service, die!),输出一般连接到另外一个部分的复位端,一般是连接到主控芯片。看门狗的功能是定期的查看芯片内部的情况,防止程序发生死循环或者程序跑飞,一旦发生错误就向芯片发出重启信号。
通俗理解就是你领养了一只小狗,你不在时可以帮你看好你的羊不乱跑,为了让它听话你必须按时地喂它。显然,如果是只‘小狗’,便看不住太多的‘羊’。
注意:看门狗命令在程序的中断中拥有最高的优先级!
2.基本原理
看门狗是一种监控系统运行状况的手段,通过软硬件结合的方式实现对系统运行状况的监控。稳定运行的软件会在执行完特定指令后进行喂狗,若在一定周期内看门狗没有收到来自软件或硬件的喂狗信号,则表示MCU已经挂了,会进入中断处理程序或强制系统复位(最高优先级)。看门狗主要由寄存器、计数器和狗叫模块构成,通过寄存器对看门狗进行基本设置,计数器计算狗叫时间,狗叫模块决定看门狗超时后发出的中断或复位方式。其工作原理是:看门狗芯片和单片机的一个I/O引脚相连,该I/O引脚通过程序控制它定时地往看门狗的这个引脚上送入高电平(或低电平),这一程序语句是分散地放在单片机其他控制语句中间的,一旦单片机由于干扰造成程序跑飞后而陷入某一程序段进入死循环状态时,写看门狗引脚的程序便不能被执行,这个时候,看门狗电路就会由于得不到单片机送来的信号,便在它和单片机复位引脚相连的引脚上送出一个复位信号,使单片机发生复位。即程序从程序存储器的起始位置开始执行,这样便实现了单片机的自动复位。
3.STM32中的看门狗系统
STM32F10xxx内置两个看门狗,一个是独立看门狗(IWDG),一个是窗口看门狗(WWDG),两个看门狗设备都可以用来检测和解决由软件或硬件错误引起的故障,提供了更高的安全性、时间的精确性和使用的灵活性。
3.1 IWDG 的使用方法
3.1.1 IWDG介绍
独立看门狗用通俗一点的话来解释就是一个12位的递减计数器,当计数器的值从某个值一直递减到0的时候,系统就会产生一个复位信号,即IWDG_RESET。如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号。看门狗功能由VDD电压域供电,在停止模式和待机模式下仍能工作。STM32的独立看门狗由内部专门的40Khz的低速时钟LSI驱动,即使主时钟发生故障,它也仍然有效。这里需要注意的是独立看门狗的时钟是一个内部RC时钟,在30~60Khz之间的一个可变化时钟,根据温度和工作场合会有一定的漂移,我们一般取40KHZ。在对看门狗时间要求不是很精确的场合,也就是精度较低的场合,时钟钟有些偏差可以接受。
3.1.2 IWDG 相关寄存器和功能框图
参考STM32英文参考手册(有些东西英文反而更容易理解),首先是键值寄存器IWDG_KR,该寄存器的各位描述如下:

在键值寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗,此时计数器从其复位值0xFFF递减计数。当计数器数到末尾0x000时,会产生一个复位信号(IWDG_RESET) 。无论何时,只要键值寄存器 IWDG_KR中被写入0xAAAA,IWDG_RLR 中的值就会被重新加载到计数器中从而避免产生看门狗复位 。
另一个寄存器是预分频寄存器IWDG_PR,该寄存器该寄存器用来设置看门狗时钟的分频系数,各位描述如下:

还有一个重装载寄存器IWDG_RLR,该寄存器用来保存重装载到计数器中的值,其各位描述如下:

注意:IWDG_PR和 IWDG_RLR寄存器具有写保护功能。要修改这两个寄存器的值,必须先向IWDG_KR寄存器中写入0x5555 。将其它值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护。重装载操作 (即写入0xAAAA)也会启动写保护功能。
注:这里还有一个状态寄存器IWDG_SR,无需配置,这里不做介绍。
下图是独立看门狗各个寄存器分布示意图:

3.1.3 IWDG 配置方法
对以上三个寄存器进行相应的配置,就可以启动STM32的独立看门狗(独立看门狗相关的库函数和定义分布在文件stm32f10x_iwdg.h和stm32f10x_iwdg.c中),具体步骤如下:
取消寄存器的写保护(向IWDG_KR写入0X5555)
通过这步,我们取消IWDG_PR和 IWDG_RLR的写保护,使后面可以操作这两个寄存器,设置IWDG_PR和 IWDG_RLR的值。实现函数是:
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable) //使能对寄存器IWDG_PR和IWDG_RLR的写操作
设置独立看门狗的与分频系数和重装载值
设置看门狗的分频系数的函数是:
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler) //设置IWDG预分频值
设置看门狗重装载值的函数是:
void IWDG_SetReload(uint16_t Reload) // 设置IWDG的重装载值
设置好看门狗的分频系数 prer和重装载值就可以知道看门狗的喂时间Tout(也就是看门狗溢出时间),该时间的计算方式为:
Tout=( ( 4 * 2 ^ prer ) * rlr ) / 40
其中Tout为看门狗溢出时间(单位为 ms)
prer为看门狗时钟预分频值( IWDG_PR的值),范围为0~7
rlr 为看门狗的重装载值(IWDG_RLR的值)
比如我们设定prer值为4,rlr值为625,那么就可以得到Tout=64 ×625/40=1000ms, 这样看门狗的溢出时间就是1s,只要你在一秒钟之内,有次写入0XAAAA到IWDG_KR,就不会导致看门狗复位(当然写入多次也是可以的)。这里需要注意的是由于时钟不是准确的40Khz,所以在喂狗的时候不要太晚,不然也会导致看门狗复位。
重载计数值喂狗(向IWDG_KR写入0XAAAA)
库函数里面重载计数值的函数是:
IWDG_ReloadCounter(); //按照IWDG重装载寄存器的值重装载IWDG计数器
通过这句,将使 STM32 重新加载 IWDG_RLR的值到看门狗计数器里面,即实现独立看门狗的喂狗操作。
启动看门狗(向IWDG_KR写入0XCCCC)
库函数里面启动看门狗的函数是:
IWDG_Enable(); //使能IWDG
通过这句,来启动STM32 STM32的看门狗。 注意IWDG在一旦启用,就不能再被关闭!想要闭只能重启并且之后不打开IWDG,否则问题依旧,所以如果不用IWDG的话,就不要去打开免得麻烦。
3.1.4 IWDG 软件设计
wdg.c里面的代码如下:
#include “wdg.h”void IWDG_Init(u8 prer,u16 rlr) { IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能对寄存器IWDG_PR和IWDG_RLR的写操作 IWDG_SetPrescaler(prer); //设置IWDG预分频值:设置IWDG预分频值为64 IWDG_SetReload(rlr); //设置IWDG重装载值 IWDG_ReloadCounter(); //按照IWDG重装载寄存器的值重装载IWDG计数器 IWDG_Enable(); //使能IWDG}//*************喂独立看门狗******************void IWDG_Feed(void){ IWDG_ReloadCounter();//reload } 主函数main.c中代码格式如下:
void main(void) { /* 各种初始化 */ { ………… } /* 启动独立看门狗 */ IWDG_START(); while(1) { /* 需要被监控的代码 */ { ………… } /* 喂狗 */ IWDG_FEED(); } }
3.2 WWDG 的使用方法
3.2.1 WWDG介绍
窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成应程序背离正常的运行序列而产生的故障。除非递减计数器值在T6位(WWDG_CR的第六位)变成0前被刷新,看门狗电路在达到预置的时间周期时会产生一个MCU复位。在递减计数器达到窗口配置寄存器(WWDG_CFR)数值之前,如果7位的递减计数器值 (在控制寄存器中 )被刷新,那么也将产生一个MCU复位。这表明递减计数器需要在一个有限的时间窗口中被刷新复位。他们的关系可以用下图说明:

图中,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: WWDGd的预分频系数
T[5:0]: 窗口看门狗的计数器低6位
根据上面的公式,假设Fpclk = 36Mhz,那么可以得到最小-最大超时时间表:
[tr]WDGTB最小超时时间最大超时时间[/tr]0113us7.28ms
1227us14.56ms
2455us29.12ms
3910us58.25ms
3.2.2 WWDG 相关寄存器和功能框图
首先介绍控制寄存器(WWDG_CR),该寄存器的各位描述如下:

可以看出,这里我们的WWDG_CR只有低八位效,T[6:0]用来存储看门狗的计数器值, 随时更新,每个窗口看门狗计数周期(4096 ×2^ WDGTB)减1。当该计数器的值从0X40变为0X3F的时候,将产生看门狗复位。
WDGA位则是看门狗的激活位,该位由软件置1,以启动看门狗,并且一定要注意的是该位一旦设置,就只能在硬件复位后才能清零了。
第二个寄存器是配置寄存器(WWDG_CFR),该寄存器的各位及描述如下:

该位中的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。
下图是窗口看门狗各个寄存器分布示意图:

3.2.3 WWDG 配置方法
介绍完窗口看门狗的寄存器之后,这里介绍库函数中用中断的方式喂狗的方法,窗口看门狗相关的源码和定义分布在文件stm32f10x_wwdg.h和stm32f10x_wwdg.c中),具体步骤如下:
使能WWDG时钟
WWDG不同于IWDG,IWDG有自己独立的40Khz时钟,不存在使能问题。而WWDG使用的是PCLK1的时钟,需要先使能时钟,方法是 :
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG时钟使能
设置窗口值和分频数
设置窗口值的函数是:
void WWDG_SetWindowValue(uint8_t WindowValue);
这个函数的入口参数WindowValue用来设置看门狗的上窗口值。
设置分频数的函数是:
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
这个函数同样只有一入口参数,用来设置看门狗的分频值 。
开启WWDG中断并分组
开启WWDG中断的函数是:
void WWDG_EnableIT(void); // 开启窗口看门狗中断
接下来是进行中断优先级配置,这里就不重复了,使用NVIC_Init NVIC_InitNVIC_Init() 函数即可 。
设置计数器初始值并使能看门狗
这一步在库函数里面的函数是:
void WWDG_Enable(uint8_t Counter)
该函数即设置了计数器的初始值,同时使能了窗口看门狗。
编写中断服务函数
在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当窗口看门狗计数器值减到0X3F的时候,就会引起软复位了。在中断服务函数里面也要将状态寄存器的EWIF位清空。
完成了以上 5个步骤之后,我们就可以使用STM32的窗口看门狗了。
这里有一个问题:如何区分是上电复位还是看门狗复位呢?
在初始化WWDG时候,有一个RCC_GetFlagStatus(RCC_FLAG_WWDGRST)可以用于判断是否发生看门狗复位,如果是重新上电引起的复位这个值当然是系统默认值,如果是看门狗复位的话这个值就会发生变化,这样就可以针对这两种不同状态进行状态恢复。
3.2.4 WWDG 软件设计
相对于独立看门狗,窗口看门狗有所区别,在函数中增加了相关的库函数支持文件stm32f10x_wwdg.c/stm32f10x_wwdg.h,然后再wdg.c里面加入如下代码:
//保存WWDG计数器的设置值,默认为最大。 u8 WWDG_CNT = 0x7f; //初始化窗口看门狗 //tr :T[6:0],计数器值 //wr :W[6:0],窗口值 //fprer:分频系数(WDGTB),仅最低2位有效 //Fwwdg=PCLK1/(4096*2^fprer)。 void WWDG_Init(u8 tr,u8 wr,u32 fprer){ RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG时钟使能 WWDG_CNT=tr&WWDG_CNT; //初始化WWDG_CNT. WWDG_SetPrescaler(fprer);设置IWDG预分频值 WWDG_SetWindowValue(wr);//设置窗口值 WWDG_Enable(WWDG_CNT); //使能看门狗 , 设置 counter 。 WWDG_ClearFlag();//清除提前唤醒中断标志位 WWDG_NVIC_Init();//初始化窗口看门狗 NVIC WWDG_EnableIT(); //开启窗口看门狗中断} //重设置WWDG计数器的值void WWDG_Set_Counter(u8 cnt){ WWDG_Enable(cnt);//使能看门狗 , 设置 counter 。 }//窗口看门狗中断服务程序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_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure);//NVIC初始化}void WWDG_IRQHandler(void) { WWDG_SetCounter(WWDG_CNT); //当禁掉此句后,窗口看门狗将产生复位 WWDG_ClearFlag(); //清除提前唤醒中断标志位 LED1=!LED1; //LED状态翻转 }
主函数main.c中代码如下:

int main(void) { delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); KEY_Init(); //按键初始化 LED0=0; delay_ms(300); WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为7f,窗口寄存器为5f,分频数为8 while(1) { LED0=1; } }
3.3 IWDG 和 WWDG 的区别

两种看门狗主要区别如下表
[tr]IWDG独立看门狗WWDG窗口看们狗[/tr]独立于系统之外,因为有独立时钟,所以不受系统影响的系统故障探测器,主要用于监视硬件错误系统内部的故障探测器,时钟与系统相同。如果系统时钟不走了,这个狗也就失去作用了,主要用于监视软件错误
只有下限有下限和上限
没有中断有中断
有硬件软件控制之分只能软件控制
12位计数递减7位计数递减
内部的大约40KHZ RC振荡器系统时钟APB1ENR
4.总结
未总结,待续……
举报

更多回帖

发帖
×
20
完善资料,
赚取积分