?學習來源----->江協科技STM32
WDG簡介
- WDG(Watchdog)看門狗
- 看門狗可以監控程序的運行狀態,當程序因為設計漏洞、硬件故障、電磁干擾等原因,出現卡死或跑飛現象時,看門狗能及時復位程序,避免程序陷入長時間的罷工狀態,保證系統的可靠性和安全性
- 看門狗本質上是一個定時器,當指定時間范圍內,程序沒有執行喂狗(重置計數器)操作時,看門狗硬件電路就自動產生復位信號
- STM32內置兩個看門狗
- 獨立看門狗(IWDG):獨立工作,對時間精度要求較低
- 窗口看門狗(WWDG):要求看門狗在精確計時窗口起作用
STM32F10xxx內置兩個看門狗,提供了更高的安全性、時間的精確性和使用的靈活性。兩個看門狗設備(獨立看門狗和窗口看門狗)可用來檢測和解決由軟件錯誤引起的故障;當計數器達到給定的超時值時,觸發一個中斷(僅適用于窗口型看門狗)或產生系統復位。
獨立看門狗(IWDG)由專用的低速時鐘(LSI)驅動,即使主時鐘發生故障它也仍然有效。窗口看門狗由從APB1時鐘分頻后得到的時鐘驅動,通過可配置的時間窗口來檢測應用程序非正常的過遲或過早的操作。
IWDG最適合應用于那些需要看門狗作為一個在主程序之外,能夠完全獨立工作,并且對時間精度要求較低的場合。 WWDG最適合那些要求看門狗在精確計時窗口起作用的應用程序。
IWDG主要性能
● 自由運行的遞減計數器
● 時鐘由獨立的RC振蕩器提供(可在停止和待機模式下工作)
● 看門狗被激活后,則在計數器計數至0x000時產生復位
IWDG框圖??
?
1.?核心模塊組成
- 寄存器模塊:
- 預分頻寄存器(IWDG_PR):配置 8 位預分頻器參數,對輸入時鐘(LSI)進行分頻,調整計數器計數頻率。
- 重裝載寄存器(IWDG_RLR):存儲 12 位重裝載數值,用于初始化 12 位遞減計數器的計數初值。
- 鍵寄存器(IWDG_KR):寫入特定命令(如啟動看門狗、喂狗操作),控制看門狗功能的開啟與重置。
- 狀態寄存器(IWDG_SR):記錄看門狗狀態標志(如計數器溢出標志),供軟件查詢。
- 時鐘與計數模塊:
- LSI 時鐘輸入:采用 40 kHz 的低速內部時鐘(LSI)作為獨立看門狗的時鐘源,確保在主時鐘故障時仍能工作。
- 8 位預分頻器:對 LSI 時鐘分頻,輸出給 12 位遞減計數器,擴展計數周期。
- 12 位遞減計數器:根據預分頻后的時鐘遞減計數,當計數到 0 時觸發 IWDG 復位。
2.?工作流程
- 初始化配置:通過 IWDG_PR 設置預分頻系數,通過 IWDG_RLR 設置重裝載值,通過 IWDG_KR 寫入命令啟動看門狗。
- 計數與喂狗:計數器在預分頻時鐘驅動下遞減,若系統正常運行,需定期通過 IWDG_KR 執行 “喂狗”(寫入特定值),重新裝載計數器初值,避免計數到 0。
- 復位觸發:若未及時喂狗,計數器遞減至 0 時,觸發 IWDG 復位信號,強制系統重啟。
3.?供電特性
圖中紅色標注強調:獨立看門狗功能位于 VDD 供電區,即使系統進入停機或待機模式,仍能正常工作,確保在低功耗模式下也能監控系統狀態,提升可靠性。
?IWDG鍵寄存器
- ?鍵寄存器本質上是控制寄存器,用于控制硬件電路的工作
- ?在可能存在干擾的情況下,一般通過在整個鍵寄存器寫入特定值來代替控制寄存器寫入一位的功能,以降低硬件電路受到干擾的概率
寫入鍵寄存器的值 | 作用 |
0xCCCC | 啟用獨立看門狗 |
0xAAAA | IWDG_RLR中的值重新加載到計數器(喂狗) |
0x5555 | 解除IWDG_PR和IWDG_RLR的寫保護 |
0x5555之外的其他值 | 啟用IWDG_PR和IWDG_RLR的寫保護 |
鍵寄存器(IWDG_KR)是獨立看門狗(IWDG)的核心控制寄存器,通過寫入特定指令碼實現以下功能:
- 啟動看門狗:向?IWDG_KR?寫入?
0xCCCC
,激活獨立看門狗,使能內部 12 位遞減計數器開始工作。 - 喂狗操作(重裝載計數器):系統正常運行時,需定期寫入?
0xAAAA
,觸發計數器重新裝載重裝載寄存器(IWDG_RLR)?中的初始值,避免計數器遞減至 0 引發復位。 - 寄存器寫使能:寫入?
0x5555
?可臨時使能對?預分頻寄存器(IWDG_PR)?和?重裝載寄存器(IWDG_RLR)?的寫權限,允許修改預分頻系數或重裝載值,完成配置后寫權限自動關閉,保障寄存器配置的安全性。
IWDG_KR 通過特定指令碼實現對看門狗的啟動、喂狗及寄存器配置控制,是軟件與硬件看門狗交互的關鍵接口。
?IWDG超時時間
寫程序的時候超時時間要設置多少,要根據自己的項目來設置 ,如果沒有特別要求,卡死后過個一兩秒再復位也不影響的話,那這個超時時間可以設置大一點
- 超時時間:TIWDG = TLSI × PR預分頻系數 × (RL + 1)
- 其中:TLSI = 1 / FLSI?
?
WWDG簡介
窗口看門狗通常被用來監測,由外部干擾或不可預見的邏輯條件造成的應用程序背離正常的運行序列而產生的軟件故障。除非遞減計數器的值在T6位變成0前被刷新,看門狗電路在達到預置的時間周期時,會產生一個MCU復位。在遞減計數器達到窗口寄存器數值之前,如果7位的遞減計數器數值(在控制寄存器中)被刷新, 那么也將產生一個MCU復位。這表明遞減計數器需要在一個有限的時間窗口中被刷新。
WWDG功能描述
如果看門狗被啟動(WWDG_CR寄存器中的WDGA位被置’1’), 并且當7位(T[6:0])遞減計數器從0x40翻轉到0x3F(T6位清零)時,則產生一個復位。如果軟件在計數器值大于窗口寄存器中的數值時重新裝載計數器,將產生一個復位。
?WWDG工作特性
- ?遞減計數器T[6:0]的值小于0x40時,WWDG產生復位
- 遞減計數器T[6:0]在窗口W[6:0]外被重新裝載時,WWDG產生復位
- 遞減計數器T[6:0]等于0x40時可以產生早期喚醒中斷(EWI),用于重裝載計數器以避免WWDG復位
- 定期寫入WWDG_CR寄存器(喂狗)以避免WWDG復位
該窗口看門狗時序圖展示了計數器遞減過程、刷新窗口限制及復位觸發邏輯,具體解讀如下:
1.?計數器遞減過程
- T [6:0] 遞減計數器:從初始值開始持續遞減,橫坐標為時間,縱坐標為計數器值。
- 關鍵閾值:
- W [6:0](窗口值):預設的上限閾值,定義 “不允許刷新” 與 “刷新窗口” 的分界。
- 0x3Fh:計數器的下限閾值(T6 位變為 0),若此時未完成喂狗,觸發復位。
2.?刷新窗口限制
- 不允許刷新區間:計數器值?> W[6:0]?時,若執行 “喂狗”(刷新計數器),會觸發復位。這是因為此時刷新屬于 “窗口外操作”,違背時序要求。
- 刷新窗口區間:計數器值處于?W[6:0] ~ 0x3Fh?時,允許通過寫寄存器更新計數器(合法喂狗),避免計數器遞減至 0x3Fh 觸發復位。
3.?T6 位與復位觸發
- T6 位變化:當計數器遞減至 0x3Fh 時,T6 位從 1 變為 0。
- 復位邏輯:若計數器到達 0x3Fh 仍未喂狗,硬件觸發復位信號,強制系統重啟,確保程序異常時恢復運行
?WWDG超時時間
要根據自己的項目要求來設置,確定想要設置的超時時間(最晚時間)和窗口時間(最晚時間)
超時時間: ?? ?
- TWWDG = TPCLK1 × 4096 × WDGTB預分頻系數 × (T[5:0] + 1)
窗口時間: ?? ?
- TWIN = TPCLK1 × 4096 × WDGTB預分頻系數 × (T[5:0] - W[5:0])
- 其中:TPCLK1 = 1 / FPCLK1 =1/36MHz
?計算方法和IDWG看門狗一樣
?IWDG和WWDG對比
IWDG獨立看門狗 | WWDG窗口看門狗 | |
復位 | 計數器減到0后 | 計數器T[5:0]減到0后、過早重裝計數器 |
中斷 | 無 | 早期喚醒中斷 |
時鐘源 | LSI(40KHz) | PCLK1(36MHz) |
預分頻系數 | 4、8、32、64、128、256 | 1、2、4、8 |
計數器 | 12位 | 6位(有效計數) |
超時時間 | 0.1ms~26214.4ms | 113us~58.25ms |
喂狗方式 | 寫入鍵寄存器,重裝固定值RLR | 直接寫入計數器,寫多少重裝多少 |
防誤操作 | 鍵寄存器和寫保護 | 無 |
用途 | 獨立工作,對時間精度要求較低 | 要求看門狗在精確計時窗口起作用 |
?獨立看門狗程序
初始化IWDG?
?①開啟LSI時鐘(但是不需我們手動開啟)
?
②寫入鍵值0x5555解除寫保護,然后再寫入預分頻值和重裝載值
③寫入鍵寄存器0xCCCC啟動獨立看門狗
④然后再主循環執行喂狗操作?
int main(void)
{OLED_Init(); //OLED初始化Key_Init(); //按鍵初始化OLED_ShowString(1, 1, "IWDG TEST");/*判斷復位信號來源*/if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) //如果是獨立看門狗復位{OLED_ShowString(2, 1, "IWDGRST"); //OLED閃爍IWDGRST字符串Delay_ms(500);OLED_ShowString(2, 1, " ");Delay_ms(100);RCC_ClearFlag(); //清除標志位}else //否則,即為其他復位{OLED_ShowString(3, 1, "RST"); //OLED閃爍RST字符串Delay_ms(500);OLED_ShowString(3, 1, " ");Delay_ms(100);}/*IWDG初始化*/IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //獨立看門狗寫使能IWDG_SetPrescaler(IWDG_Prescaler_16); //設置預分頻為16IWDG_SetReload(2499); //設置重裝值為2499,獨立看門狗的超時時間為1000msIWDG_ReloadCounter(); //重裝計數器,喂狗IWDG_Enable(); //獨立看門狗使能while (1){Key_GetNum(); //調用阻塞式的按鍵掃描函數,模擬主循環卡死IWDG_ReloadCounter(); //重裝計數器,喂狗OLED_ShowString(4, 1, "FEED"); //OLED閃爍FEED字符串Delay_ms(200); //喂狗間隔為200+600=800msOLED_ShowString(4, 1, " ");Delay_ms(600);}
}
獨立看門狗超時時間計算上面草稿有寫,如果不懂就跳轉視頻看看:超時時間計算
相關函數:?
?void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess)//啟用或禁用對IWDG_PR和IWDG_RLR寄存器的寫訪問
參數 | 說明 |
IWDG_WriteAccess | IWDG_PR和IWDG_RLR寄存器寫訪問的新狀態 |
?void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)//設置IWDG預分頻值
參數 | 說明 |
IWDG_Prescaler | 指定IWDG預分頻器值 |
void IWDG_SetReload(uint16_t Reload)//設置IWDG 重裝值?
參數 | 說明 |
Reload | 指定IWDG的重裝值,該參數必須為0 ~ 0x0FFF之間的數字 |
?void IWDG_ReloadCounter(void)//用重新加載寄存器中定義的值重新加載IWDG計數器
void IWDG_Enable(void)//啟用IWDG(開啟對IWDG_PR和IWDG_RLR寄存器的寫保護)
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)//檢查是否設置了指定的RCC標志?
參數 | 說明 |
RCC_FLAG | 指定要檢查的標志 |
?窗口看門狗
WWDG初始化?
①開啟窗口看門狗ABP1的時鐘
②配置各個寄存器(設置預分頻和設置窗口值)
③寫入控制寄存器CR(包含看門狗使能位,計數器標志溢出位,計數器有效位)
④最后,再運行過程中向計數器寫入想要的計數重裝值
int main(void)
{OLED_Init(); //OLED初始化Key_Init(); //按鍵初始化OLED_ShowString(1, 1, "WWDG TEST");/*判斷復位信號來源*/if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) //如果是窗口看門狗復位{OLED_ShowString(2, 1, "WWDGRST"); //OLED閃爍WWDGRST字符串Delay_ms(500);OLED_ShowString(2, 1, " ");Delay_ms(100);RCC_ClearFlag(); //清除標志位}else //否則,即為其他復位{OLED_ShowString(3, 1, "RST"); //OLED閃爍RST字符串Delay_ms(500);OLED_ShowString(3, 1, " ");Delay_ms(100);}/*開啟時鐘*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //開啟WWDG的時鐘/*WWDG初始化*/WWDG_SetPrescaler(WWDG_Prescaler_8); //設置預分頻為8WWDG_SetWindowValue(0x40 | 21); //設置窗口值,窗口時間為30msWWDG_Enable(0x40 | 54); //使能并第一次喂狗,超時時間為50mswhile (1){Key_GetNum(); //調用阻塞式的按鍵掃描函數,模擬主循環卡死OLED_ShowString(4, 1, "FEED"); //OLED閃爍FEED字符串Delay_ms(20); //喂狗間隔為20+20=40msOLED_ShowString(4, 1, " ");Delay_ms(20);WWDG_SetCounter(0x40 | 54); //重裝計數器,喂狗}
}
?超時時間和窗口時間計算和獨立看門狗一樣:計算步驟
?相關函數:
?void WWDG_SetPrescaler(uint32_t WWDG_Prescaler)//設置WWDG預分頻器
參數 | 說明 |
WWDG_Prescaler | 指定WWDG預分頻器 |
void WWDG_SetWindowValue(uint8_t WindowValue)//設置WWDG窗口值?
參數 | 說明 |
WindowValue | 指定要與下計數器進行比較的窗口值,該參數必須小于0x80 |
?void WWDG_SetCounter(uint8_t Counter)//設置WWDG計數器值
參數 | 說明 |
Counter | 看門狗計數器的值,該參數必須為0x40 ~ 0x7F之間的數字 |
?void WWDG_Enable(uint8_t Counter)//啟用WWDG窗口看門狗并加載計數器值
參數 | 說明 |
Counter | 看門狗計數器的值,該參數必須為0x40 ~ 0x7F之間的數字 |