前言
Watchdog Timer(看門狗計時器,WDT)是嵌入式系統中最重要的可靠性保障機制。在工業控制、IoT 設備、車載電子等需要長時間穩定運行的場景中,WDT 能在系統因軟體錯誤、硬體干擾或電源不穩而「卡住」時自動復位,讓設備自我修復。本文將從 WDT 的基本原理講起,深入 STM32 IWDG 與 ESP32 TWDT 的實作細節,並提供完整的生產級程式碼範例。
一、Watchdog Timer 基本原理
1.1 什麼是 Watchdog Timer?
Watchdog Timer 是一個硬體計時器,其核心邏輯非常簡單:
- 啟動計數:系統啟動後 WDT 開始計數(遞減或遞增)
- 定期餵狗(Kick):正常運行時,軟體在計數器溢位前將其重置
- 系統復位:若軟體因故未在時間內餵狗,WDT 計數器歸零 → 觸發系統硬體復位
圖 1:Watchdog Timer 正常工作 — 主程式中每次循環末尾餵狗,計數器持續重置
1.2 為什麼需要 WDT?
即使程式寫得再嚴謹,嵌入式系統仍然可能遇到:
- 硬體干擾:電源雜訊、EMI 導致 PC 指標錯亂或暫存器值異常
- 通訊卡住:I2C/SPI 從設備無回應,while 迴圈無法跳出
- 記憶體異常:棧溢出(Stack Overflow)、堆積碎片導致 malloc 失敗
- RTOS 死鎖:多工環境下的互斥鎖死鎖導致所有任務停擺
- 低電量行為異常:電壓低於 MCU 最低工作電壓時邏輯行為不可預測

圖 5:Watchdog Timer 常見應用場景 — 從硬體保護到工業自動化
二、STM32 IWDG(Independent Watchdog)
2.1 IWDG 硬體架構
STM32 的 IWDG 是獨立看門狗,使用專屬的 LSI(Low Speed Internal,約 32 kHz)振盪器,即使主時鐘故障仍能運作。其內部結構包含:
- LSI 時鐘源:獨立 RC 振盪器,約 30~60 kHz(典型 32 kHz)
- Prescaler(除頻器):可設為 4/8/16/32/64/128/256 倍除頻
- 12-bit 遞減計數器:範圍 0~4095
- Key Register(KVR):寫入 0xAAAA 重載計數器,寫入 0x5555 允許配置
- Status Register(SR):PVU(Prescaler Update)和 RVU(Reload Update)旗標
圖 3:STM32 IWDG 內部架構 — LSI 經除頻後驅動 12-bit 計數器
2.2 IWDG 超時計算
| 除頻值 | LSI=32kHz 時 Prescaler | 最大超時 (4096 ticks) | 典型設定 (Reload=0xFFF) |
|---|---|---|---|
| 4 | 8,192 Hz | 0.5 秒 | 125 μs / tick |
| 8 | 4,096 Hz | 1.0 秒 | 250 μs / tick |
| 16 | 2,048 Hz | 2.0 秒 | 500 μs / tick |
| 32 | 1,024 Hz | 4.0 秒 | 1.0 ms / tick |
| 64 | 512 Hz | 8.0 秒 | 2.0 ms / tick |
| 128 | 256 Hz | 16.0 秒 | 4.0 ms / tick |
| 256 | 128 Hz | 32.0 秒 | 8.0 ms / tick |
公式:Timeout = (Prescaler × Reload_Value) / LSI_Frequency
例如 Prescaler=64, Reload=0xFFF(4095):Timeout = (64 × 4096) / 32000 ≈ 8.19 秒
2.3 STM32 HAL IWDG 程式碼
// stm32_iwdg_wdt.c — STM32 IWDG 初始化與餵狗範例
#include "stm32f1xx_hal.h"
IWDG_HandleTypeDef hiwdg;
// IWDG 初始化:超時約 4 秒 (LSI=32kHz, Prescaler=32, Reload=0xFFF)
void WDT_Init(void)
{
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_32; // 32 kHz / 32 = 1 kHz
hiwdg.Init.Reload = 0xFFF; // 4096 ticks × 1ms = ~4.096 秒
if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
{
Error_Handler(); // IWDG 啟動失敗(通常不會發生)
}
}
// 餵狗函式 — 主循環中定期調用
void WDT_Feed(void)
{
HAL_IWDG_Refresh(&hiwdg); // 寫入 0xAAAA 到 KVR
}
// 注意:IWDG 一旦啟動無法關閉!
// 除非觸發系統復位,否則 WDT 持續運行
2.4 STM32 IWDG 注意事項
- 無法關閉:IWDG 一旦使能(透過 IWDG->KR 寫 0xCCCC),只有系統復位才能停用
- 寫保護:修改 Prescaler 或 Reload 前須先向 KVR 寫入 0x5555
- 狀態旗標:修改 Prescaler 後需等待 PVU 清除(約 5~6 個 LSI 週期)
- 低功耗模式:IWDG 在 Stop 和 Standby 模式下仍能運行
- HAL 延遲:HAL_IWDG_Init() 內部包含等待 PVU/RVU 的 while 迴圈,建議在 main 初始化時一次性完成
三、ESP32 TWDT(Task Watchdog Timer)
3.1 TWDT 與 IWDG 的差異
ESP32 提供兩種 WDT:
- TWDT(Task Watchdog Timer):監控 RTOS 任務是否在超時時間內執行特定操作(如 taskYIELD 或餵狗)
- IWDT(Interrupt Watchdog Timer):監控 ISR 處理是否超過允許時間,防止中斷卡死
- RTC WDT:由 RTC 模組驅動,可在 Deep Sleep 模式下運作
與 STM32 IWDG 最大的不同在於:ESP32 TWDT 是以任務為單位的監控機制,能精確指出哪個任務卡住,而非僅觸發全域復位。
3.2 ESP32 TWDT 程式碼
// esp32_twdt.c — ESP32 TWDT 初始化與餵狗範例
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
// TWDT 初始化:超時 10 秒,監控所有任務
void WDT_Init(void)
{
// 初始化 TWDT,超時 10 秒
esp_task_wdt_config_t twdt_config = {
.timeout_ms = 10000, // 10 秒超時
.trigger_panic = true, // 超時時觸發 panic(系統復位)
};
ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
// 將當前任務註冊到 TWDT 監控
ESP_ERROR_CHECK(esp_task_wdt_add(NULL)); // NULL = 當前任務
}
// 餵狗函式 — 在任務主循環中定期調用
void WDT_Feed(void)
{
esp_task_wdt_reset(); // 重置當前任務的 WDT 計數器
}
// 任務範例:處理感測器資料
void sensor_task(void *pvParameters)
{
WDT_Init(); // 註冊此任務到 TWDT
while (1) {
read_sensor_data(); // 讀取感測器
process_data(); // 資料處理
send_via_mqtt(); // MQTT 發送
WDT_Feed(); // 餵狗
vTaskDelay(pdMS_TO_TICKS(100)); // 100ms 延遲
}
}
// 注意:TWDT 預設監控 IDLE 任務
// 若 IDLE 任務未得到 CPU 時間(高優先級任務霸佔 CPU),TWDT 也會觸發
3.3 ESP32 IWDT(Interrupt Watchdog)
// esp32_iwdt.c — 中斷看門狗設定
#include "soc/cpu.h"
#include "esp_intr_alloc.h"
// IWDT 超時時間設定(ISP 級別)
void IWDT_Init(void)
{
// IWDT 在 ESP32-IDF 中預設啟用
// 可在 menuconfig 中設定超時:
// CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
// CONFIG_ESP_INT_WDT=y
// IWDT 會在 ISR 執行超過設定時間時觸發 panic
// 幫助開發者找出耗時過長的中斷處理程式
printf("IWDT active: interrupt watchdog enabled\n");
}
四、WDT 觸發行為與時序分析
4.1 正常工作 vs 超時觸發
圖 1:正常運作 — 主任務在計數器溢位前寫入 KVR(0xAAAA)重置計數器
圖 2:超時觸發 — 任務卡住後未在 WDT 溢位前餵狗,計數器歸零 → 產生系統復位脈衝
4.2 從復位原因診斷問題
系統重啟後,檢查復位原因能快速定位是否由 WDT 觸發:
// STM32 — 檢查復位原因
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) {
printf("系統復位:IWDG Watchdog 觸發!\n");
}
__HAL_RCC_CLEAR_RESET_FLAGS();
// ESP32 — 檢查復位原因
esp_reset_reason_t reason = esp_reset_reason();
if (reason == ESP_RST_WDT) {
printf("系統復位:Task Watchdog 觸發!\n");
} else if (reason == ESP_RST_INT_WDT) {
printf("系統復位:Interrupt Watchdog 觸發!\n");
}
五、STM32 vs ESP32 WDT 比較

圖 4:STM32 IWDG 與 ESP32 TWDT 差異比較 — IWDG 為硬體層級獨立計時器,TWDT 為 RTOS 任務監控
| 項目 | STM32 IWDG | ESP32 TWDT |
|---|---|---|
| 時鐘源 | 獨立 LSI (32 kHz RC) | RC 振盪器 (~615 kHz) |
| 計數器 | 12-bit 遞減 (0~4095) | 32-bit 遞增 (0~2³²) |
| 除頻器 | 4/8/16/32/64/128/256 | 無硬體除頻 |
| 最長超時 | ~26.3 秒 (÷256 × 4096) | ~7 秒 |
| 監控粒度 | 硬體層級(系統全域) | 任務層級(可指定任務) |
| 可否關閉 | 不可(啟動後永久運行) | 可(esp_task_wdt_deinit) |
| 低功耗支援 | Stop/Standby | Active/Modem-sleep |
| 復位方式 | 硬體復位(不可遮罩) | 硬體復位 / panic 中斷 |
六、進階技巧與最佳實踐
6.1 多層級 WDT 架構
在工業級產品中,建議採用多層級 WDT:
- 第一層 — MCU IWDG:硬體層級最後防線,超時設定在 5~10 秒
- 第二層 — RTOS TWDT:監控每個任務的執行週期,超時設定在 2~5 秒
- 第三層 — 外部 WDT IC(如 MAX6369):在 MCU 完全失效時由外部硬體切斷電源
6.2 餵狗策略
- 不要在 ISR 中餵狗:中斷服務程式中餵狗會遮蔽主程式卡住的問題
- 不要在高優先級任務中餵狗:低優先級任務卡住時高優先級任務仍可正常餵狗
- 使用「心跳任務」:建立一個專屬任務,只在確認所有子系統正常後才餵狗
- 分階段餵狗:在長任務中設置多個檢查點,分別餵不同的 WDT
6.3 生產級心跳任務範例
// heartbeat_task.c — 生產級心跳監控任務
void heartbeat_task(void *pvParameters)
{
TickType_t last_wake = xTaskGetTickCount();
const TickType_t interval = pdMS_TO_TICKS(1000); // 1 秒
while (1) {
vTaskDelayUntil(&last_wake, interval);
// 檢查各子系統狀態
bool comm_ok = (HAL_GetTick() - last_comm_tick < 5000);
bool sensor_ok = (sensor_error_count < 3); bool stack_ok = (uxTaskGetStackHighWaterMark(NULL) > 128);
if (comm_ok && sensor_ok && stack_ok) {
WDT_Feed(); // 所有子系統正常,餵狗
led_green_on();
} else {
led_red_on();
// 記錄錯誤但不餵狗,讓 WDT 復位
log_error("System unhealthy: comm=%d sensor=%d stack=%d",
comm_ok, sensor_ok, stack_ok);
}
}
}
6.4 常見陷阱
- Debugger 干擾:使用偵錯器時 WDT 會持續計數,導致中斷點停留時觸發復位。解決方案:在 DEBUG 模式下禁用 WDT,或在 HardFault_Handler 中無限迴圈
- Bootloader 相容性:若 IWDG 在 Bootloader 中已啟用,主程式啟動前需先重新初始化超時
- WDT 初始化時機:應在 main() 的最早階段初始化 WDT,防止系統初始化過程中卡住
- 任務堆疊不足:TWDT 每次餵狗涉及系統呼叫,堆疊空間不足可能導致餵狗本身失敗
七、總結
Watchdog Timer 是嵌入式系統中投資報酬率最高的可靠性機制 — 只需幾行程式碼就能讓系統在異常時自動復位。無論是 STM32 的硬體 IWDG 還是 ESP32 的任務層級 TWDT,正確設計餵狗策略、搭配復位原因檢查,就能大幅提升產品的長期穩定性。在工業 4.0 和 IoT 應用中,WDT 不是選配,而是標配。
文章評論