引言
在單片機運行的過程中,我們可能會遇到程序陷入死循環的情況。很顯然我們需要對這種情況進行提前的預防。看門狗就是用來進行該工作的。看門狗分為獨立看門狗和窗口看門狗,這一節介紹的是獨立看門狗。
看門狗介紹
STM32的獨立看門狗由內部專門的40KHz低速時鍾驅動,與系統主時鍾分開工作,也就是說,主時鍾損壞時,看門狗仍然可以正常使用。這個低速時鍾是一個RC時鍾,並不是很精確,頻率在30~60KHz之間。
看門狗的作用就是在一定時間內(通過定時計數器實現) 沒有接收喂狗信號(表示 MCU 已經掛了),便實現處理器的自動復位重啟(發送復位信號)。
設置看門狗的步驟如下:
- 取消寄存器寫保護
- 設置獨立看門狗的預分頻系數和重裝載值
- 喂狗(重載計數值)
- 啟動看門狗
設預分頻系數為prer,重裝載值為rlr,則喂狗的時間計算公式為(T的單位為ms):
\[T=\frac{4 \times 2^{p r e r} \times r l r}{40} \]
$\frac{1}{40} $ 即 $\frac{1}{f} $ 是一個周期的長度,也就是計數器加一所需要的時間。\(4\times 2^{prer}\)是預分頻系數的值。預分頻系數乘以周期得到的是分頻后計數器加一所用的時間。而這個時間再乘以重裝載值rlr得到的是一次喂狗的時間。
可能有人會問,\(2^{prer}\)不是預分頻系數了嗎?為什么還要乘以4?這里可以看一下庫函數中對分頻系數的一系列預定義。
#define IWDG_Prescaler_4 ((uint8_t)0x00) #define IWDG_Prescaler_8 ((uint8_t)0x01) #define IWDG_Prescaler_16 ((uint8_t)0x02) #define IWDG_Prescaler_32 ((uint8_t)0x03) #define IWDG_Prescaler_64 ((uint8_t)0x04) #define IWDG_Prescaler_128 ((uint8_t)0x05) #define IWDG_Prescaler_256 ((uint8_t)0x06)
可以看到,當設置prer參數為0時,預分頻系數為4,也就是說,我們設置參數為0時,預分頻系數都不是0,而是4。因此,這里需要把這個4乘進去。
編碼
main.c
int main(void){
delay_init();
//下列幾個初始化函數在之前的博客中可以找到
LED_Init();
KEY_Init();
IWDG_Init(4, 625); //預分頻系數為4,重裝載數為625,喂狗時間約為1s。
delay_ms(500); //進行延遲,使led的滅掉可以看到。
LED0 = 0;
while(1){
if(KEY_Scan() == 1){ //如果WK_UP按鍵按下,就進行喂狗。
IWDG_Feed();
}
delay_ms(10);
}
}
wdg.h
#ifndef __WDG_H
#define __WDG_H
#include "sys.h"
void IWDG_Init(u8 prer, u16 rlr); //獨立看門狗初始化函數
void IWDG_Feed(void); //喂狗函數
#endif
wdg.c
#include "wdg.h"
void IWDG_Init(u8 prer, u16 rlr){
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //取消寫保護
IWDG_SetPrescaler(prer); //設置預分頻系數
IWDG_SetReload(rlr); //設置重裝載值
IWDG_ReloadCounter(); //重載計數器喂狗
IWDG_Enable(); //使能看門狗
}
void IWDG_Feed(void){
IWDG_ReloadCounter(); //重載計數器喂狗函數
}
至此,我們就完成了獨立看門狗的學習。為了手中單片機的性命,還是盡量讓看門狗發揮一點作用吧。