对于看门狗的功能,代码也不是很多就不单独建立模块了

我们根据上图来总结一下看门狗的配置流程,第一步应该是开启时钟,只有LSI时钟开启了独立看门狗才能够运行,但是这个开启LSI的代码不需要我们写,在参考手册6.2.9章节只写了一句话,如果独立看门狗已经由硬件选项或软件启动,LSI振荡器将被强制在打开状态,并且不能关闭。在LSI振荡器稳定后,时钟供应给IWDG。我们直接进入下一步,就是写入预分频器和重装寄存器了,在写入之前,不要忘了还有写保护,首先写入0x5555键值,解除写保护。所以第二步就是解除写保护。第三步是写入预分频和重装值,具体写多少可以通过超时时间公式来计算

最后当这些配置工作做完之后,我们就可以执行0xCCCC这一条指令来启动看门狗了,然后在主循环里,我们要不断执行0xAAAA来进行喂狗,这些就是独立看门狗的配置流程

独立看门狗总共有以下几条函数:

void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);//写使能控制,函数内容就是在键寄存器写入IWDG_WriteAccess_Enable或IWDG_WriteAccess_Disable,分别就是0x5555和0x0000。分别会产生解除写保护和启动写保护的操作
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);//写预分频器,写PR寄存器
void IWDG_SetReload(uint16_t Reload);//写重装值,写入RLR寄存器
void IWDG_ReloadCounter(void);//重新装载寄存器,就是喂狗,它的操作就是在键寄存器中写入KR_KEY_Reload,就是0xAAAA
void IWDG_Enable(void);//启动看门狗,它就是在键寄存器中写入KR_KEY_Enable,就是0xCCCC
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);//获取标志位状态

除了这里的函数要需要用到RCC里的一个函数,我们想要知道程序复位时,它是看门狗导致的复位,还是上电或复位键导致的复位,这个判断可以通过RCC里的一个标志位来实现,我们需要用的这个查看标志位的函数,查看后要记得清楚标志位

FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);//RCC标志位对应的事件主要分为两种,一种是HSI、HSE这些时钟的Ready,就是判断时钟是否准备好了,另一种就是各种reset标志位,其中Pin Reset就是按复位键复位的时候会置1,POR/PDR reset是上电复位和掉电复位,Software reset是软件复位,Independent Watchdog reset是独立看门狗复位,Window Watchdog reset是窗口看门狗复位,Low Power reset是低功耗复位,这里我们主要关注独立看门狗和窗口看门狗的复位标志位。
void RCC_ClearFlag(void);

到这里函数就看完了,接下来开始写代码:

#include “stm32f10x.h”                  // Device header
#include “Delay.h”
#include “OLED.h”
int main(void)
{
OLED_Init();
OLED_ShowString(1, 1, “IWDG TEST”);
if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET)//查看独立看门狗复位标志位
{
OLED_ShowString(2, 1, “IWDGRST”);
Delay_ms(500);
OLED_ShowString(2, 1, ”       “);
Delay_ms(500);
RCC_ClearFlag();
}
else//否则就只是依次普通的复位
{
OLED_ShowString(2, 1, “RST”);
Delay_ms(500);
OLED_ShowString(2, 1, ”       “);
Delay_ms(500);
}
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//写使能,解除写保护
IWDG_SetPrescaler(IWDG_Prescaler_16);//预分频器选择16分频
IWDG_SetReload(2499);//根据公式T(LSI) x PR预分频系数 x (RL + 1),算出1000ms的超时时间所需要的重装值
IWDG_ReloadCounter();//先喂一次狗再开启看门狗,这样启动之后的第一个喂狗周期就是1000ms
IWDG_Enable();//使能同时会在键寄存器写入0x5555之外的值,就顺便给寄存器写保护了
while (1)
{
IWDG_ReloadCounter();
Delay_ms(1200);
}
}
先试试将喂狗间隔时间超过超时时间进行测试:
会不断地显示看门狗复位,因为目前我们的喂狗时间不满足要求
再加上按键的操作,可以实现平时正常喂狗,长按按键阻塞时阻止喂狗产生看门狗复位
 while (1)
{
Key_GetNum();

IWDG_ReloadCounter();

OLED_ShowString(4, 1, “FEED”);
Delay_ms(200);
OLED_ShowString(4, 1, ” “);
Delay_ms(600);
}


下一个是窗口看门狗,其实两种看门狗都差不多,我们直接在上一个代码上进行修改

先看一下初始化流程,因为窗口看门狗的时钟来源是PCLK1,所以第一步我们需要开启窗口看门狗APB1的时钟,这个第一步需要我们自己来执行,之后第二步就是配置各种寄存器了比如预分频和窗口值,窗口看门狗没有写保护所以第二步就可以直接写这些寄存器了,之后第三步,写入控制寄存器CR,控制寄存器包含看门狗使能位,计数器溢出标志位和计数器有效位,这些需要一起设置。之后在运行过程中我们不断向计数器写入想要的重装值这样就能进行喂狗了。
接着我们再看一下库函数
void WWDG_DeInit(void);//恢复缺省配置
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);//写入预分频器
void WWDG_SetWindowValue(uint8_t WindowValue);//写入窗口值
void WWDG_EnableIT(void);//使能中断,因为只有一个中断就不需要指定参数了
void WWDG_SetCounter(uint8_t Counter);//写入计数器,喂狗用的函数
void WWDG_Enable(uint8_t Counter);//使能窗口看门狗,初始化后就用这个函数使能,因为递减计数器处于自由运行状态,在使能的时候,计数器可能是任何值,为了避免刚一使能就立马复位,所以我们在使能的时候需要顺便同时喂一下狗,在库函数里的体现就是这个使能函数里也有一个参数,需要指定使能的时候喂狗多少
FlagStatus WWDG_GetFlagStatus(void);//获取标志位
void WWDG_ClearFlag(void);//清楚标志位
在计算之前我们需要根据项目要求确定想要设定的超时时间(最晚时间)和窗口时间(最早时间),比如我们要设置的是超时时间是50ms,窗口时间是30ms,我们首先要带入第一个公式确认预分频和喂狗要给的计数器值
由图表可以得出,要想让最大超时值达到50ms,预分频WDGTB最小要选择3,预分频系数就是2的3次方8。TPCLK1是1/36M,计算可以得出T[5:0]应该设定为54,但这只是T[5:0]的值,还有T6位的值也要加上,我们需要将54再或上0x40,也就是把控制寄存器次高位的T6位设置成1
。再将窗口值确定为30ms,计算可得W[5:0] = 21,同样的这里也是只有5位,需要再或上W6位
#include “stm32f10x.h”                  // Device header
#include “Delay.h”
#include “OLED.h”
#include “Key.h”
int main(void)
{
OLED_Init();
Key_Init();
OLED_ShowString(1, 1, “WWDG TEST”);
if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET)//查看独立看门狗复位标志位
{
OLED_ShowString(2, 1, “WWDGRST”);
Delay_ms(500);
OLED_ShowString(2, 1, ”       “);
Delay_ms(500);
RCC_ClearFlag();
}
else//否则就只是依次普通的复位
{
OLED_ShowString(2, 1, “RST”);
Delay_ms(500);
OLED_ShowString(2, 1, ”       “);
Delay_ms(500);
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);//开启窗口看门狗的PCLK1时钟
WWDG_SetPrescaler(WWDG_Prescaler_8);
WWDG_SetWindowValue(0x40 | 21);
WWDG_Enable(0x40 | 54);
while (1)
{
Key_GetNum();
OLED_ShowString(4, 1, “FEED”);
Delay_ms(20);
OLED_ShowString(4, 1, ”    “);
Delay_ms(20);
WWDG_SetCounter(0x40 | 54);
}
}