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