“你喂狗了吗?”当你听到这句话时,不要以为是喂狗,闹笑话就不好了,这里说的喂狗是指给MCU加看门狗电路,看门狗不是“狗”,是一种MCU监控电路
什么是看门狗
在实际的MCU 应用系统中,由于常常会受到来自外界的某些干扰,有可能造成程序跑飞而进入死循环,从而导致整个系统的陷入停滞状态并且不会自动恢复到可控的工作状态。所以出于对MCU 运行的安全考虑,便引入了一种专门的复位监控电路WatchDog,俗称看门狗。看门狗电路所起的作用是一旦MCU 运行出现故障,就强制对MCU 进行硬件复位,使整个系统重新处于可控状态
看门狗分为硬件看门狗和软件看门狗
硬件看门狗
硬件看门狗是通过使用外围电路,通过电路来复位芯片来达到对电路重启的功能。本次使用芯片SP706来监控MCU,SP706芯片有以下特点:
分为4 个子型号: SP706P、SP706R、SP706S、SP706T
1 复位输出: P 为高电平有效, R/S/T 为低电平有效
2 精密的低电压监控: P/R 为2.63V 、S 为2.93V、T 为3.08V
3 复位脉冲宽度: 200ms(额定值)
4 独立的看门狗定时器: 1.6 秒超时(额定值)
5 去抖TTL/CMOS 手动复位输入( /MR 管脚)
其中SP706P复位输出高电平,SP706R/S/T复位输出低电平
STM32芯片是低电平复位,所以使用SP706R/S/T系列
硬件电路
两根信号线,MCU的I/0口连到SP706的WDI,信号发送PWM波
SP706的输出RST连到复位引脚
SP706的工作原理:SP706上电工作之后,WDI引脚保持高电平或者低电平不变 ,则1.6S之后,SP706内部的看门狗定时器会溢出并使RST输出低电平使MCU复位,所以需要在MCU复位之前及翻转WDI的状态,SP706正常工作两种状态:
1.定时器生产PWM波
2.使I/O口在1.6s内改变状态一次
软件看门狗:使用软件看门狗分为独立看门狗和窗口看门狗
独立看门狗:独立看门狗是一个12位的递减计数器,当计数器的值从某个值递减到0时,系统就会产生一个复位信号,如果递减计数到0之前,刷新了计数值的话,就不会产生复位信号
使用独立看门狗要先配置IWDG,使他产生一个计数多少时间的计数器,然后喂狗
IWDG配置主要有几点:
计数器时钟:看门股时钟由LSI经过8位预分频器得到,可以操作IWDG_PR预分频寄存器来设置分频因子,分频因子可以是:[4,8,16,32,64,128,256,256],计数器时钟:=40/42^PRV
重装载计数器:重装载计数器是一个12位的寄存器,里面装着要刷新到计数器的值,这个值是计数器要计数的时间,时间=(42^prv)/40*rlv(s) rlv是重装载计数器的值,
IWDG配置
void IWDG_Config(uint8_t prv ,uint16_t rlv)
{
// ʹÄÜ Ô¤·ÖƵ¼Ä´æÆ÷PRºÍÖØ×°ÔØ¼Ä´æÆ÷RLR¿Éд
IWDG_WriteAccessCmd( IWDG_WriteAccess_Enable );
// ÉèÖÃÔ¤·ÖƵÆ÷Öµ
IWDG_SetPrescaler( prv );
// ÉèÖÃÖØ×°ÔØ¼Ä´æÆ÷Öµ
IWDG_SetReload( rlv );
// °ÑÖØ×°ÔØ¼Ä´æÆ÷µÄÖµ·Åµ½¼ÆÊýÆ÷ÖÐ
IWDG_ReloadCounter();
// ʹÄÜ IWDG
IWDG_Enable();
}
喂狗:喂狗一次调用一次IWDG_Feed函数
void IWDG_Feed(void)
{
// °ÑÖØ×°ÔØ¼Ä´æÆ÷µÄÖµ·Åµ½¼ÆÊýÆ÷ÖУ¬Î¹¹·£¬·ÀÖ¹IWDG¸´Î»
// µ±¼ÆÊýÆ÷µÄÖµ¼õµ½0µÄʱºò»á²úÉúϵͳ¸´Î»
IWDG_ReloadCounter();
}
窗口看门狗:窗口看门狗与独立看门狗都是递减计数,但是窗口看门狗可以设计数上限 和下限,递减计数到某一个数之前”喂狗”的话也会产生一次复位,递减计数到下限产生一次复位信号,所以看门狗计数器的值必须在上限与下限之间,在上限与下限之间喂狗。
WWDG配置主要有以下几点:
看门狗时钟:由APB1分频得到,最大时钟频率36MHZ
计数器时钟:等于CNT_CK=PCLK1/4096/(2^WDGTB)
计数器:窗口看门狗是一个递减计数器,共7位,0X40是看门狗能够递减的最小值,最大值是0X7F
窗口值:窗口值要在0X40到0X7F之间,在窗口值与0X40之间喂狗一次,窗口值设置大小根据要计时的时间来设置
计时时间计算如下
WWDG配置:
10 void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
11 {
12 // 开启 WWDG 时钟
13 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
14
15 // 设置递减计数器的值
16 WWDG_SetCounter( tr );
17
18 // 设置预分频器的值
19 WWDG_SetPrescaler( prv );
20
21 // 设置上窗口值
22 WWDG_SetWindowValue( wr );
23
24 // 设置计数器的值,使能WWDG
25 WWDG_Enable(WWDG_CNT);
26
27 // 清除提前唤醒中断标志位
28 WWDG_ClearFlag();
29 // 配置WWDG 中断优先级
30 WWDG_NVIC_Config();
31 // 开WWDG 中断
32 WWDG_EnableIT();
33 }
喂狗:
void WWDG_Feed(void)
3 {
4 // 喂狗,刷新递减计数器的值,设置成最大WDG_CNT=0X7F
5 WWDG_SetCounter( WWDG_CNT );
6 }