【連載】【ALIENTEK 戰艦STM32開發板】STM32開發指南–第十二章 窗口看門狗(WWDG)實驗 - 正點原子’s Blog

發布時間:2017/6/1

山西快乐十分钟下载:第十二章 窗口門狗(WWDG)實驗

山西快乐十分任三口诀 www.jucocx.com.cn

這一章,我們將向大家介紹如何使用STM32的另外一個看門狗,窗口看門狗(以下簡稱WWDG)。在本章中,我們將使用窗口看門狗的中斷功能來喂狗,通過DS0和DS1提示程序的運行狀態。本章分為如下幾個部分:

12.1 STM32窗口看門狗簡介

12.2 硬件設計

12.3 軟件設計

12.4 下載驗證

12.1 STM32窗口看門狗簡介

窗口看門狗(WWDG)通常被用來監測由外部干擾或不可預見的邏輯條件造成的應用程序背離正常的運行序列而產生的軟件故障。除非遞減計數器的值在T6位(WWDG->CR的第六位)變成0前被刷新,看門狗電路在達到預置的時間周期時,會產生一個MCU復位。在遞減計數器達到窗口配置寄存器(WWDG->CFR)數值之前,如果7位的遞減計數器數值(在控制寄存器中)被刷新, 那么也將產生一個MCU復位。這表明遞減計數器需要在一個有限的時間窗口中被刷新。他們的關系可以用圖12.1.1來說明:

![](file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image001.png)

圖12.1.1 窗口看門狗工作示意圖

圖12.1.1中,T[6:0]就是WWDG_CR的低七位,W[6:0]即是WWDG->CFR的低七位。T[6:0]就是窗口看門狗的計數器,而W[6:0]則是窗口看門狗的上窗口,下窗口值是固定的(0X40)。當窗口看門狗的計數器在上窗口值之外被刷新,或者低于下窗口值都會產生復位。

上窗口值(W[6:0])是由用戶自己設定的,根據實際要求來設計窗口值,但是一定要確保窗口值大于0X40,否則窗口就不存在了。

窗口看門狗的超時公式如下:

Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1;

其中:

Twwdg:WWDG超時時間(單位為ms)

Fpclk1:APB1的時鐘頻率(單位為Khz)

WDGTB:WWDG的預分頻系數

T[5:0]:窗口看門狗的計數器低6位

根據上面的公式,假設Fpclk1=36Mhz,那么可以得到最小-最大超時時間表如表12.1.1所示:

![](file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image003.png)

表12.1.1 36M時鐘下窗口看門狗的最小最大超時表

接下來,我們介紹窗口看門狗的3個寄存器。首先介紹控制寄存器(WWDG_CR),該寄存器的各位描述如圖12.1.2所示:

![](file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image004.png)圖12.1.2 WWDG_CR寄存器各位描述

可以看出,這里我們的WWDG_CR只有低八位有效,T[6:0]用來存儲看門狗的計數器值,隨時更新的,每個看窗口看門狗計數周期(4096×2^ WDGTB)減1。當該計數器的值從0X40變為0X3F的時候,將產生看門狗復位。

WDGA位則是看門狗的激活位,該位由軟件置1,以啟動看門狗,并且一定要注意的是該位一旦設置,就只能在硬件復位后才能清零了。

窗口看門狗的第二個寄存器是配置寄存器(WWDG_CFR),該寄存器的各位及其描述如圖12.1.3所示:

![](file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image006.png)

圖12.1.3 WWDG_ CFR寄存器各位描述

該位中的EWI是提前喚醒中斷,也就是在快要產生復位的前一段時間(T[6:0]=0X40)來提醒我們,需要進行喂狗了,否則將復位!因此,我們一般用該位來設置中斷,當窗口看門狗的計數器值減到0X40的時候,如果該位設置,并開啟了中斷,則會產生中斷,我們可以在中斷里面向WWDG_CR重新寫入計數器的值,來達到喂狗的目的。注意這里在進入中斷后,必須在不大于1個窗口看門狗計數周期的時間(在PCLK1頻率為36M且WDGTB為0的條件下,該時間為113us)內重新寫WWDG_CR,否則,看門狗將產生復位!

最后我們要介紹的是狀態寄存器(WWDG_SR),該寄存器用來記錄當前是否有提前喚醒的標志。該寄存器僅有位0有效,其他都是保留位。當計數器值達到40h時,此位由硬件置1。它必須通過軟件寫0來清除。對此位寫1無效。即使中斷未被使能,在計數器的值達到0X40的時候,此位也會被置1。

在介紹完了窗口看門狗的寄存器之后,我們介紹要如何啟用STM32的窗口看門狗。這里我們介紹的方法是用中斷的方式來喂狗的。采取的步驟如下:

1)使能WWDG時鐘

WWDG不同于IWDG,IWDG有自己獨立的40Khz時鐘,不存在使能問題。而WWDG使用的是PCLK1的時鐘,需要先使能時鐘。

2)設置WWDG_CFR和WWDG_CR兩個寄存器

在時鐘使能完后,我們設置WWDG的CFR和CR兩個寄存器,對WWDG進行配置。包括使能窗口看門狗、開啟中斷、設置計數器的初始值、設置窗口值并設置分頻數WDGTB等。

3)開啟WWDG中斷并分組

在設置完了WWDG后,需要配置該中斷的分組及使能。這點通過我們之前所編寫的MY_NVIC_Init函數實現就可以了。

4)編寫中斷服務函數

在最后,還是要編寫窗口看門狗的中斷服務函數,通過該函數來喂狗,喂狗要快,否則當窗口看門狗計數器值減到0X3F的時候,就會引起軟復位了。在中斷服務函數里面也要將狀態寄存器的EWIF位清空。

完成了以上4個步驟之后,我們就可以使用STM32的窗口看門狗了。這一章的實驗,我們將通過DS0來指示STM32是否被復位了,如果被復位了就會點亮300ms。DS1用來指示中斷喂狗,每次中斷喂狗翻轉一次。

12.2 硬件設計

本實驗用到的硬件資源有:

1)  指示燈DS0和DS1

2)  窗口看門狗

其中指示燈前面介紹過了,窗口看門狗屬于STM32的內部資源,只需要軟件設置好即可正常工作。我們通過DS0和DS1來指示STM32的復位情況和窗口看門狗的喂狗情況。

12.3 軟件設計

這里,我們在之前的IWDG看門狗實例內增添部分代碼來實現這個實驗。首先打開上次的工程,然后在wdg.c加入如下代碼(之前代碼保留):

//保存WWDG計數器的設置值,默認為最大.

u8 WWDG_CNT=0x7f;

//初始化窗口看門狗

//tr   :T[6:0],計數器值

//wr   :W[6:0],窗口值

//fprer:分頻系數(WDGTB),僅最低2位有效

//Fwwdg=PCLK1/(4096*2^fprer).

void WWDG_Init(u8 tr,u8 wr,u8 fprer)

{

RCC->APB1ENR|=1<<11;       //使能wwdg時鐘

WWDG_CNT=tr&WWDG_CNT; //初始化WWDG_CNT.

WWDG->CFR|=fprer<<7;       //PCLK1/4096再除2^fprer

WWDG->CFR&=0XFF80;

WWDG->CFR|=wr;                  //設定窗口值

WWDG->CR|=WWDG_CNT;      //設定計數器值

WWDG->CR|=1<<7;               //開啟看門狗

MY_NVIC_Init(2,3,WWDG_IRQChannel,2);//搶占2,子優先級3,組2

WWDG->SR=0X00;                    //清除提前喚醒中斷標志位

WWDG->CFR|=1<<9;          //使能提前喚醒中斷

}

//重設置WWDG計數器的值

void WWDG_Set_Counter(u8 cnt)

{

WWDG->CR =(cnt&0x7F);//重設置7位計數器

}

//窗口看門狗中斷服務程序

void WWDG_IRQHandler(void)

{

WWDG_Set_Counter(WWDG_CNT);//重設窗口看門狗的值!

WWDG->SR=0X00;//清除提前喚醒中斷標志位

LED1=!LED1;

}

新增的這三個函數都比較簡單,第一個函數void WWDG_Init(u8 tr,u8 wr,u8 fprer)用來設置WWDG的初始化值。包括看門狗計數器的值和看門狗比較值等。該函數就是按照我們上面的4個思路設計出來的代碼。注意到這里有個全局變量WWDG_CNT,該變量用來保存最初設置WWDG_CR計數器的值。在后續的中斷服務函數里面,就又把該數值放回到WWDG_CR上。

WWDG_Set_Counter函數比較簡單,就是用來重設窗口看門狗的計數器值的。該函數很簡單,我們就不多說了。

最后中斷服務函數里面,先重設窗口看門狗的計數器值,然后清除提前喚醒中斷標志。最后對LED0(DS0)取反,來監測中斷服務函數的執行了狀況。我們再把這幾個函數名加入到頭函數里面去,以方便其他文件調用。

在完成了以上部分之后,我們就回到主函數,輸入如下代碼:

int main(void)

{

Stm32_Clock_Init(9);    //系統時鐘設置

uart_init(72,9600);      //串口初始化為9600

delay_init(72);                  //延時初始化

LED_Init();                        //初始化與LED連接的硬件接口

BEEP_Init();                //初始化蜂鳴器端口

KEY_Init();           //初始化與按鍵連接的硬件接口

LED0=0;

delay_ms(300);

WWDG_Init(0X7F,0X5F,3); //計數器值為7f,窗口寄存器為5f,分頻數為8

while(1)

{

LED0=1;

}

}

該函數通過LED0(DS0)來指示是否正在初始化。而LED1(DS1)用來指示是否發生了中斷。我們先讓LED0亮300ms,然后關閉以用于判斷是否有復位發生了。在初始化WWDG之后,我們回到死循環,關閉LED1,并等待看門狗中斷的觸發/復位。

在編譯完成之后,我們就可以下載這個程序到戰艦STM32開發板上,看看結果是不是和我們設計的一樣。

12.4 下載驗證

將代碼下載到戰艦STM32后,可以看到DS0亮一下之后熄滅,緊接著DS1開始不停的閃爍。每秒鐘閃爍5次左右,和我們預期的一致,說明我們的實驗是成功的。