14.1 STM32看門狗簡介
在單片機構成的微型計算機系統中,單片機的工作可能會受到外界的電磁干擾或者程序運行的BUG導致程序指針錯誤,或者其他錯誤導致的死循環,引發整個系統陷入停滯狀態,所以需要一個與系統獨立的定時器來監控單片機的運行狀態,這個定時器在系統正常運轉的時候,不停的刷新定時器的計數器,例如隔一段時間給這個定時器的計數器寫100,然后在定時器減運算到0之前再一次寫入100,這樣,就保證了定時器不計數到0,也就意味著通過判斷這個定時器是否計數到0來判斷系統是否陷入死機狀態,實現這種功能的定時器就稱為看門狗,不停的刷新計數器值的行為就稱為“喂狗”,一般計數器計數到0后會直接對單片機進行復位,用于避免系統陷入死循環。
STM32內部有兩種看門狗模塊,一種是窗口看門狗WWDG,另一種是獨立看門狗IWDG,STM32的獨立看門狗由內部專門的40Khz低速時鐘驅動,即使主時鐘發生故障,它也仍然有效。獨立看門狗的時鐘是一個內部RC時鐘,所以并不是準確的40Khz,而是在30~60Khz之間的一個可變化的時鐘,只是我們在估算的時候,以40Khz的頻率來計算。窗口看門狗通常被用來監測由外部干擾或不可預見的邏輯條件造成的應用程序背離正常的運行序列而產生的軟件故障。除非遞減計數器的值在T6位變成0前被刷新,看門狗電路在達到預置的時間周期時,會產生一個MCU復位。在遞減計數器達到窗口配置寄存器數值之前,如果7位的遞減計數器數值在控制寄存器中被刷新,那么也將產生一個MCU復位。這表明遞減計數器需要在一個有限的時間窗口中被刷新。
14.2 獨立看門狗相關寄存器
14.2.1 鍵值寄存器IWDG_KR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
KEY[15:0] |
該寄存器屬于只寫寄存器,讀取的值為0x0000,軟件必須以一定間隔寫入0xAAAA,否則,當計數器為0時,看門狗會產生復位;
寫入0x5555表示允許訪問IWDG_PR和IWDG_RLR寄存器;
寫入0xCCCC表示啟動看門狗工作,如果選擇了硬件看門狗則不受此命令字限制。
14.2.2 預分頻寄存器IWDG_PR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | PR[2:0] |
Bit 2~Bit 0:預分頻因子
000:預分頻因子=4
001:預分頻因子=8
010:預分頻因子=16
011:預分頻因子=32
100:預分頻因子=64
101:預分頻因子=128
110:預分頻因子=256
111:預分頻因子=256
14.2.3 重裝載寄存器IWDG_RLR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | RLR[11:0] |
Bit 11~Bit 0:看門狗計數器重裝載值:每當向IWDG_KR寄存器寫入0xAAAA時,重裝載值會被傳送到計數器中,隨后計數器從這個值開始遞減計數。
14.3 窗口看門狗相關寄存器
14.3.1 控制寄存器WWDG_CR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | WDGA | T6 | T5 | T4 | T3 | T2 | T1 | T0 |
Bit 7:激活位:,此位由軟件置1,但僅能由硬件在復位后清0。當WDGA=1時,看門狗可以產生復位
0:禁止看門狗
1:啟用看門狗
Bit 6~Bit 0:7位計數器,存儲看門狗的計數器值。每(4096x2 ^WDGTB^ )個PCLK1周期減1。當T6變成0產生看門狗復位
14.3.2 配置寄存器WWDG_CFR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | EWI | TB1 | TB0 | W6 | W5 | W4 | W3 | W2 | W1 | W0 |
Bit 9:提前喚醒中斷,此位若置1,則當計數器值達到40h,即產生中斷,此中斷只能由硬件在復位后清除
Bit 8:預分頻器時基
00:CK計時器時鐘不分頻
01:CK計時器時鐘2分頻
10:CK計時器時鐘4分頻
11:CK計時器時鐘8分頻
Bit6~Bit 5:7位窗口值,用來與遞減計數器進行比較用的窗口值
14.3.3 狀態寄存器WWDG_SR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | EWIF |
Bit 0:提前喚醒中斷標志,當計數器值達到40h時,此位由硬件置1。它必須通過軟件寫0來清除。若中斷未被使能,此位也會被置1
14.4 實驗例程
14.4.1 獨立看門狗實驗
功能:如果看門狗沒有復位,接在PB5上的LED常亮,如果PA0的按鍵按下,就喂狗,只要按鍵不停的按,看門狗就一直不會產生復位,保持DS0的常亮,一旦超過看門狗定溢出時間,那么將導致程序重啟,這將導致DS0熄滅一次。
(1)創建wdg.h文件輸入以下代碼。
#ifndef _WDG_H_
#define _WDG_H_
#include "sys.h"
/*********************************************************************************************************
函 數 列 表
*********************************************************************************************************/
void IWDG_Init( u8 prer, u16 rlr ) ; //獨立看門狗初始化
#endif
(2)創建wdg.c文件輸入以下代碼。
#include "wdg.h"
/***************************************************
Name :IWDG_Init
Function :獨立看門狗初始化
Paramater :
prer:分頻數:0~7
rlr:重裝載寄存器值
Return :None
***************************************************/
void IWDG_Init( u8 prer, u16 rlr )
{
IWDG->KR = 0x5555 ; //使能對IWDG->PR和IWDG->RLR的寫
IWDG->PR = prer ; //設置分頻系數
IWDG->RLR = rlr ; //從加載寄存器 IWDG->RLR
IWDG->KR = 0xAAAA ; //更新計數器
IWDG->KR = 0xCCCC ; //使能看門狗
}
(3)在1.c文件中輸入以下代碼。
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "wdg.h"
/***************************************************
Name :LED_Init
Function :LED初始化
Parameter :None
Return :None
***************************************************/
#define LED PBout( 5 ) //定義LED端口
void LED_Init()
{
RCC->APB2ENR |= 1<<3 ;
GPIOB->CRL &= 0xFF0FFFFF ;
GPIOB->CRL |= 0x00300000 ;
LED = 1 ;
}
/***************************************************
Name :KEY_Init
Function :KEY初始化
Parameter :None
Return :None
***************************************************/
#define KEY PAin( 0 ) //定義按鍵端口
void KEY_Init()
{
RCC->APB2ENR |= 1<<2 ;
GPIOA->CRL &= 0xFFFFFFF0 ;
GPIOA->CRL |= 0x00000008;
}
/***************************************************
Name :main
Function :主函數
Parameter :None
Return :None
***************************************************/
int main()
{
STM32_Clock_Init( 9 ) ; //STM32時鐘初始化
SysTick_Init( 72 ) ; //SysTick初始化
USART1_Init( 72, 115200 ) ; //初始化串口1波特率115200
LED_Init() ; //LED初始化
KEY_Init() ; //按鍵初始化
delay_ms( 500 ) ; //延時500ms,讓人可以看到DS0滅的狀態
IWDG_Init( 4, 625 ) ; //與分頻數為64,重載值為625,溢出時間為1s
LED = 0 ; //點亮DS0
while( 1 )
{
if( KEY==1 )
{
delay_ms( 10 ) ;
if( KEY==1 )
{
IWDG->KR = 0xAAAA ; //喂狗
}
}
delay_ms( 20 ) ;
}
}
14.4.2 窗口看門狗實驗
功能:程序一運行使得接在PB5上的LED1亮300ms后關閉,進入死循環。等待WWDG中斷的到來,在中斷里面,喂狗,并對PE5上的LED2進行翻轉操作。可以看到LED2不停的閃爍,LED1只在剛啟動的時候閃一下。
(1)在上一個實驗的wdg.h文件的函數列表區域添加以下代碼。
void WWDG_Init( u8 tr, u8 wr, u8 fprer ) ; //窗口看門狗初始化
(2)在上一個實驗的wdg.c文件末尾添加以下代碼。
/***************************************************
Name :WWDG_IRQHandler
Function :窗口看門狗中斷服務程序
Paramater :None
Return :None
***************************************************/
void WWDG_IRQHandler()
{
WWDG->CR = 0x7F ; //重設置7位計數器
WWDG->SR = 0x00 ; //清除提前喚醒中斷標志位
LED2 != LED2 ;
}
/***************************************************
Name :WWDG_Init
Function :窗口看門狗初始化
Paramater :
tr:計數器值
wr:窗口值
fprer:分頻系數
Return :None
***************************************************/
void WWDG_Init( u8 tr, u8 wr, u8 fprer )
{
RCC->APB1ENR |= 1<<11 ; //使能wwdg時鐘
WWDG->CFR |= fprer<<7 ; //PCLK1/4096再除2^fprer
WWDG->CFR &= 0xFF80 ;
WWDG->CFR |= wr ; //設定窗口值
WWDG->CR |= tr&0x7F ; //設定計數器值
WWDG->CR |= 1<<7 ; //開啟看門狗
NVIC_Init( 2, 3, WWDG_IRQn, 2 ) ; //搶占2,子優先級3,組2
WWDG->SR = 0x00 ; //清除提前喚醒中斷標志位
WWDG->CFR |= 1<<9 ; //使能提前喚醒中斷
}
注:由于在中斷服務函數中引用了LED2,所以需要添加頭文件#include “led.h”。
(3)創建led.h文件,并輸入以下代碼。
#ifndef _LED_H_
#define _LED_H_
#include "sys.h"
/*********************************************************************************************************
硬 件 端 口
*********************************************************************************************************/
#define LED1 PBout( 5 ) //定義LED1端口
#define LED2 PEout( 5 ) //定義LED2端口
/*********************************************************************************************************
函 數 列 表
*********************************************************************************************************/
void LED_Init( void ) ; //LED初始化
#endif
(4)創建led.c文件,并輸入以下代碼。
#include "led.h"
/***************************************************
Name :LED_Init
Function :LED初始化
Paramater :None
Return :None
***************************************************/
void LED_Init()
{
RCC->APB2ENR |= 1<<3 ;
GPIOB->CRL &= 0xFF0FFFFF ;
GPIOB->CRL |= 0x00300000 ;
RCC->APB2ENR |= 1<<6 ;
GPIOE->CRL &= 0xFF0FFFFF ;
GPIOE->CRL |= 0x00300000 ;
LED1 = 1 ;
LED2 = 1 ;
}
(5)在1.c文件中輸入以下代碼。
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "led.h"
#include "wdg.h"
/***************************************************
Name :main
Function :主函數
Parameter :None
Return :None
***************************************************/
int main()
{
STM32_Clock_Init( 9 ) ; //STM32時鐘初始化
SysTick_Init( 72 ) ; //SysTick初始化
USART1_Init( 72, 115200 ) ; //初始化串口1波特率115200
LED_Init() ; //LED初始化
LED1 = 0 ; //點亮DS0
delay_ms( 300 ) ; //延時300ms,讓人可以看到DS0亮的狀態
WWDG_Init( 0x7F, 0x5F, 3 ) ; //計數器值為7f,窗口寄存器為5f,分頻數為8
while( 1 )
{
LED1 = 1 ; //熄滅LED1
}
}
14.5 為何STM32要同時存在窗口看門狗與獨立看門狗
14.5.1 獨立看門狗的使用條件
(1)程序跑飛
(2)出現死循環
(3)睡眠與休眠不合理
(4)外部主晶振損壞
(5)需要重新復位,且不保留任何數據
14.5.2 窗口看門狗使用條件
(1)軟件邏輯出現錯誤
(2)死機或者死循環
(3)軟件執行不按預期效果執行
(4)軟件需要重新復位,但是保留所有數據
14.5.3 兩者的區別
(1)獨立看門狗使用內部專用40kHz低速時鐘
窗口看門狗則使用PCLK1的時鐘
(2)獨立看門狗沒有中斷,超時直接復位
窗口看門狗有中斷,超時可以在中斷服務函數中操作或者喂狗
(3)獨立看門狗一般用于避免程序跑飛或者死循環
窗口看門狗則是為了避免程序不按照預先設定的邏輯執行
(4)獨立看門狗是12位遞減操作
窗口看門狗則是6位遞減操作
-
單片機
+關注
關注
6061文章
44854瀏覽量
645792 -
計算機系統
+關注
關注
0文章
290瀏覽量
24493 -
程序
+關注
關注
117文章
3818瀏覽量
82306
發布評論請先 登錄
WDT看門狗實驗
看門狗實驗有哪些操作步驟
2021-04-20 獨立看門狗實驗

評論