每日更新教程,評論區答疑解惑,小白也能變大神!"
目錄
一.窗口看門狗(WWDG)簡介
二.窗口看門狗寄存器列表
三.窗口看門狗復位案例
一.窗口看門狗(WWDG)簡介
- ?CW32F030C8T6 內部集成窗口看門狗定時器 (WWDT),用戶需要在設定的時間窗口內進行刷新,否則將觸發系統復位。 WWDT 通常被用來監測有嚴格時間要求的程序執行流程,防止由外部干擾或未知條件造成應用程序的執行異常, 導致發生系統故障。
1.1主要特性
- ?7 位向下計數器。
- ?PCLK 時鐘驅動,8 級預分頻,最大分頻 524288。
- ?支持預溢出中斷和計數溢出、加載計數值出錯復位。
- ?開啟后不可關閉,除非系統復位。
1.2功能框圖
1.3工作方式
- 系統復位后,窗口看門狗 WWDT 處于關閉狀態,設置控制寄存器 WWDT_CR0 的 EN 位域為 1,可啟動 WWDT。 WWDT 開啟后,除非發生復位,否則不能被關閉。 啟動 WWDT 之前,用戶必須預設看門狗溢出時間和窗口時間。設置 WWDT_CR0.WCNT 的值,可更新計數器的 初始值,設置 WWDT_CR1.WINR 的值,可配置看門狗的窗口值,窗口值必須小于看門狗計數器的初始值。啟動 WWDT 后,計數器從初始值開始遞減計數。
- 當計數器遞減到 0x40 時,將產生預溢出信號 POV,設置 WWDT_CR1.IE 為 1 將產生預溢出中斷。
- 當計數器遞減到 0x3F 時,將產生溢出信號 OV,該溢出信號可觸發系統復位。
- 在當前計數值 WCNT 大于窗口值 WINR 時,更新看門狗計數器,也會觸發系統復位。
1.4刷新計數器
- WWDT 運行時,只有在計數值小于等于窗口值且計數值遞減到 0x3F 之前,才能刷新計數器,即喂狗操作,否則 將產生系統復位。 設置 WWDT_CR1.WINR 的值,可配置復位前延時時間窗口的上限值,延時時間窗口的下限固定為 0x3F,窗口看 門狗的喂狗操作時機,如下圖所示:
1.5喂狗時間
- 窗口看門狗的喂狗時間計算公式:
- 喂狗時間下限: TWWDT_MIN = TPCLK×4096×2PRS×( WCNT – WINR )
- 喂狗時間上限: TWWDT_MAX = TPCLK×4096×2PRS×( WCNT – 0x3F )
- 其中: TPCLK:PCLK 的時鐘周期 PRS:預分頻系數 WCNT:計數器當前計數值 WINR:
- 看門狗窗口值
- 例: 當 PCLK 頻率為 24MHz 時,預分頻系數 PRS 設置為 0x01,WCNT 設置為 0x6F,窗口值 WINR 設置為 0x4F,
- 則喂狗時間如下: TWWDT_MIN = 1 / 24MHz×4096×21 ×( 0x6F - 0x4F ) ≈ 10.922 ms TWWDT_MAX = 1 / 24MHz×4096×21 ×( 0x6F - 0x3F ) = 16.384 ms
- 即,喂狗時間最早不能早于 10.922ms,否則將發生加載計數值出錯而引起系統復位;喂狗最晚不能遲于 16.384ms,否則將發生下溢出引起系統復位。正確喂狗的時間窗口大小約為 5ms。
1.6復位與中斷
- 當計數器 WCNT 的值遞減到 0x40 時,預溢出中斷標志位 WWDT_SR.POV 由硬件置位,若設置了控制寄存器 WWDT_CR1 的 IE 位域為 1(注:該位置 1 后不可清 0),將產生預溢出中斷請求。用戶可在中斷服務程序中更 新計數器 WCNT,以避免 WWDT 產生復位。 在以下條件之一成立時,均可觸發系統復位:
- 1. 計數器 WCNT 的值遞減到 0x3F;
- 2. 更新計數器 WCNT 時當前計數值大于窗口值;
- 3. 向 WWDT_CR0.WCNT 寫入小于或等于 0x3F 的值。
1.7?WWDT 基本配置流程
- 步驟 1:設置 SYSCTRL_APBEN1.WWDT 為 1,使能 WWDT 的配置時鐘及工作時鐘;
- 步驟 2:通過 WWDT_CR1.PRS 配置窗口看門狗計數器時鐘的預分頻;
- 步驟 3:通過 WWDT_CR1.WINR 配置窗口看門狗計數的比較值;
- 步驟 4:通過 WWDT_CR0.WCNT 配置計數器的初始值;
- 步驟 5:根據是否需要使能預溢出中斷,配置 WWDT_CR1.IE;
- 步驟 6:設置 WWDT_CR0.EN 為 1 啟動窗口看門狗。 WWDT 喂狗 當計數器 WCNT 的值遞減到小于等于 WWDT_CR1.WINR,且大于 0x3F 之前,向 WWDT_CR0.WCNT 重新寫入計 數器的初始值。
二.窗口看門狗寄存器列表
三.窗口看門狗復位案例
以下是針對代碼生成的詳細注釋,按功能模塊劃分:
/*** @brief 主函數入口,初始化硬件并進入主循環* @return int32_t 程序執行狀態(通常不返回)*/
int32_t main(void)
{// 系統時鐘配置(HSI->PLL 48MHz)RCC_Configuration();// GPIO初始化(按鍵輸入PA1)GPIO_Configuration();// LED1初始化(PB9),默認點亮LED1.LED_Port = CW_GPIOB;LED1.LED_Pin = GPIO_PIN_9;LED_Init(&LED1);LED1.LED_On(&LED1);// LED2初始化(PB8),默認熄滅LED2.LED_Port = CW_GPIOB;LED2.LED_Pin = GPIO_PIN_8;LED_Init(&LED2);LED2.LED_Off(&LED2);// 系統節拍定時器初始化(250ms中斷周期)SysTick_Config(SystemCoreClock / 1000 * 250);// 窗口看門狗配置(窗口值82,分頻262144)WWDT_Config();// 中斷控制器配置(優先級設定)NVIC_Configuration();// 檢測是否因看門狗復位if (RCC_GetRstFlag(RCC_FLAG_WWDTRST)){LED2.LED_On(&LED2); // 若復位則點亮LED2指示}// 主循環(空跑)while (1) {}
}
/*** @brief 系統時鐘配置(HSI->PLL 48MHz)* - HSI啟用并校準(8MHz/6分頻)* - PLL倍頻到48MHz* - FLASH等待周期設為2(適應48MHz時鐘)*/
void RCC_Configuration(void)
{// HSI使能,預分頻6(默認8MHz輸出)RCC_HSI_Enable(RCC_HSIOSC_DIV6);// AHB/APB總線無分頻RCC_HCLKPRS_Config(RCC_HCLK_DIV1);RCC_PCLKPRS_Config(RCC_PCLK_DIV1);// PLL配置(HSI作為源,8MHz輸入,6倍頻至48MHz)RCC_PLL_Enable(RCC_PLLSOURCE_HSI, 8000000, 6);RCC_PLL_OUT();// FLASH等待周期配置(48MHz需2周期)__RCC_FLASH_CLK_ENABLE();FLASH_SetLatency(FLASH_Latency_2);// 切換系統時鐘源至PLLRCC_SysClk_Switch(RCC_SYSCLKSRC_PLL);RCC_SystemCoreClockUpdate(48000000);
}
/*** @brief 窗口看門狗配置* - 時鐘頻率183Hz(分頻262144)* - 窗口值82(約450ms窗口期)* - 計數器初始值0x7F(最大127)* - 啟用中斷*/
static void WWDT_Config(void)
{WWDT_InitTypeDef WWDT_InitStruct = {0};__RCC_WWDT_CLK_ENABLE();WWDT_InitStruct.WWDT_CounterValue = 0x7F;WWDT_InitStruct.WWDT_ITState = ENABLE;WWDT_InitStruct.WWDT_Prescaler = WWDT_Prescaler_DIV262144; // 5.46ms/周期WWDT_InitStruct.WWDT_WindowValue = 82; // 窗口期≈82*5.46ms≈450msWWDT_Init(&WWDT_InitStruct);WWDT_Cmd(); // 啟動看門狗
}
/*** @brief SysTick中斷服務函數* - 每250ms觸發一次* - 喂狗操作(防止復位)* - LED1狀態翻轉*/
void SysTick_Handler(void)
{WWDT_FEED(0x7F); // 喂狗(重置計數器)LED1.LED_Toggle(&LED1); // LED1閃爍
}/*** @brief 看門狗中斷服務函數* - 首次進入時喂狗2次并點亮LED1* - 后續若仍進入則觸發系統復位*/
void WDT_IRQHandler(void)
{static uint8_t flag = 0;WWDT_ClearFlag(); // 清除中斷標志if (flag < 2){WWDT_FEED(0x7F); // 喂狗延緩復位LED1.LED_On(&LED1); // LED1常亮作為預警flag++;}
}
/*** @brief GPIO配置* - PA1設置為下降沿觸發輸入(按鍵檢測)*/
void GPIO_Configuration(void)
{GPIO_InitTypeDef GPIO_InitStruct;__RCC_GPIOA_CLK_ENABLE();GPIO_InitStruct.IT = GPIO_IT_FALLING; // 下降沿中斷GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pins = GPIO_PIN_1;GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
}/*** @brief NVIC中斷優先級配置* - SysTick優先級1* - GPIO/WDT中斷優先級0(最高)*/
void NVIC_Configuration(void)
{__disable_irq();NVIC_SetPriority(SysTick_IRQn, 1);NVIC_SetPriority(GPIOA_IRQn, 0);NVIC_SetPriority(WDT_IRQn, 0);NVIC_EnableIRQ(WDT_IRQn);NVIC_EnableIRQ(GPIOA_IRQn);__enable_irq();
}