stm32 獨(dú)立看門狗[操作寄存器+庫函數(shù)]
造成程序跑飛,只是程序的正常運(yùn)行狀態(tài)被打斷而進(jìn)入死循環(huán),從而使單片機(jī)控制的系統(tǒng)無法正常工作??撮T狗就是一種專門用于檢測單片機(jī)程序運(yùn)行狀態(tài)的硬件結(jié)構(gòu)。
stm32也是如此。
stm32的獨(dú)立看門狗由內(nèi)部專門的40Khz低速時鐘驅(qū)動,即使主時鐘發(fā)生故障時,它也仍然有效。這里需要注意的是獨(dú)立看門狗的時鐘是一個內(nèi)部時鐘,所以不是準(zhǔn)確的40Khz,而是在30~60Khz之間的一個可變化的時鐘,看門狗的時鐘對時間的要求不是很精確,所以時鐘有偏差可以接受。
本例直接操作寄存器實(shí)現(xiàn)驗(yàn)證獨(dú)立看門狗的復(fù)位功能,設(shè)定一個800ms的喂狗時間,在主函數(shù)中實(shí)現(xiàn)LED閃爍,如果設(shè)定一個1s的延時,則觸發(fā)獨(dú)立看門狗復(fù)位,LED常亮。
庫函數(shù)實(shí)現(xiàn)當(dāng)外部中斷發(fā)生(按下PA0按鍵),長時間不喂狗,引發(fā)獨(dú)立看門狗復(fù)位時,向外用串口輸出復(fù)位提示。
直接操作寄存器
使用獨(dú)立看門狗,需要了解一下寄存器:
鍵值寄存器:(IWDG_KR)
低16位有效的寄存器,只寫寄存器,讀出值恒為0x0000.
軟件必須以一定的間隔寫入0xAAAA,否則,當(dāng)計(jì)數(shù)器為0時,看門狗會產(chǎn)生復(fù)位。
寫入0x5555表示允許訪問IWDG_PR和IWDG_RLR寄存器。
寫入0xCCCC,啟動看門狗工作。
預(yù)分頻寄存器:(IWDG_PR)
第三位有效寄存器,用于設(shè)置看門狗的分頻系數(shù),最低為4,最高位256.
通過設(shè)置PR[2:0]:位來選擇計(jì)數(shù)器時鐘的預(yù)分頻因子。要改變預(yù)分頻因子,IWDG_SR寄存器的PVU位必須為0。
000: 預(yù)分頻因子=4 100: 預(yù)分頻因子=64
001: 預(yù)分頻因子=8 101: 預(yù)分頻因子=128
010: 預(yù)分頻因子=16 110: 預(yù)分頻因子=256
011: 預(yù)分頻因子=32 111: 預(yù)分頻因子=256
重裝載寄存器:(IWDG_RLR)
低12位有效,RL[11:0]。用于定義看門狗計(jì)數(shù)器的重裝載值。
每當(dāng)向IWDG_KR寄存器寫入0xAAAA時,重裝載值會被傳送到計(jì)數(shù)器中。隨后計(jì)數(shù)器從這個值開始遞減計(jì)數(shù)??撮T狗超時周期可通過此重裝載值和時鐘預(yù)分頻值來計(jì)算。 只有當(dāng)IWDG_SR寄存器中的RVU位為0時,才能對此寄存器進(jìn)行修改。
狀態(tài)寄存器:(IWDG_SR)
只有低兩位有效。都由硬件置’1’和 清’0’。
RVU[1]: 看門狗計(jì)數(shù)器重裝載值更新
PVU[0]:看門狗預(yù)分頻值更新
代碼如下: (system.h 和 stm32f10x_it.h 等相關(guān)代碼參照 stm32 直接操作寄存器開發(fā)環(huán)境配置)
User/main.c
01 #include
02 #include "system.h"
03 #include "wdg.h"
04
05 #define LED1 PAout(4)
06 #define LED2 PAout(5)
07
08 void Gpio_Init(void);
09
10 int main(void)
11 {
12
13 Rcc_Init(9); //系統(tǒng)時鐘設(shè)置
14
15 Gpio_Init();
16
17 Iwdg_Init(3,1000); //設(shè)定為800ms內(nèi)喂狗
18
19 while(1){
20
21 LED1 = !LED1;
22
23 delay(100000); //延時100ms后喂狗,LED閃爍
24
25 //delay(1000000); //延時1000ms,引發(fā)獨(dú)立看門狗復(fù)位,LED不閃爍
26
27 Iwdg_Feed(); //喂狗
28
29 }
30
31 }
32
33
34 void Gpio_Init(void)
35 {
36 RCC->APB2ENR|=1<<2; //使能PORTA時鐘
37
38 GPIOA->CRL&=0x0000FFFF; // PA0~3設(shè)置為浮空輸入,PA4~7設(shè)置為推挽輸出
39 GPIOA->CRL|=0x33334444;
40
41 }
Library/wdg.c (此文件包含了獨(dú)立看門狗和窗口看門狗的驅(qū)動函數(shù))
01 #include
02 #include "wdg.h"
03
04 /********************************************
05 *
06 *本文件包含窗口看門狗和獨(dú)立看門口的相關(guān)函數(shù)
07 *
08 *********************************************/
09
10 u8 Wwdg_Cnt = 0x7F; //計(jì)數(shù)器值,默認(rèn)為最大值127
11
12 //獨(dú)立看門狗初始化
13 //參數(shù)說明:
14 // pre:分頻數(shù)(0~7),相應(yīng)分頻因子為4*(2^pre)
15 // rlr:低12位有[11:0]
16 // 喂狗時間計(jì)算: T = (4*(2^pre)*rlr)/40;(ms)
17 void Iwdg_Init(u8 pre,u16 rlr)
18 {
19 IWDG ->KR = 0x5555; //使能對PR RLR寄存器的寫操作
20 IWDG ->PR =pre; //設(shè)置分頻數(shù)
21 IWDG ->RLR = rlr; //設(shè)定重裝值
22 IWDG ->KR = 0xAAAA; //裝載RLR值到看門狗計(jì)數(shù)器,即喂狗
23 IWDG ->KR = 0xCCCC; //啟動看門狗
24 }
25
26 //獨(dú)立看門狗喂狗
27 void Iwdg_Feed()
28 {
29 IWDG -> KR = 0xAAAA; //喂狗
30 }
31
32 //窗口看門狗初始化
33 //參數(shù)說明:
34 // cnt計(jì)數(shù)器的值,最大 127,0x7F
35 // w_cnt 窗口值,最大 127,0x7F
36 //pre 預(yù)分頻器的時基值,低兩位有效;實(shí)際時鐘為: PLCK1/4096/2^pre
37 //需要再主函數(shù)中開啟中斷 WWDG_IRQChannel
38 //設(shè)定喂狗時間范圍必須在:(WWDG時鐘為PCLK1,36Mhz)
39 // Tmax =(4096*2^pre*(cnt-63)/36) (us)
40 // Tmin =(4096*2^pre*(cnt-w_cnt)/36) (us)
41 //超出次時間喂狗復(fù)位
42
43 void Wwdg_Init(u8 cnt,u8 w_cnt,u8 pre)
44 {
45 u8 Cnt_Max = 0x7f; //計(jì)數(shù)器最大值
46
47 Wwdg_Cnt = Cnt_Max&cnt; //設(shè)定計(jì)數(shù)器的值,防止溢出
48
49 RCC->APB1ENR |= 1<<11;
50
51 WWDG -> CFR |=pre<<7; //設(shè)定預(yù)分頻器的時基,實(shí)際分頻值我
52 WWDG -> CFR |= 1<<9; //使能中斷
53
54 WWDG -> CFR &= 0xFF80; //初始化低七位,即窗口值清0
55 WWDG -> CFR |= w_cnt; // 設(shè)定窗口值
56
57 WWDG -> CR |= Wwdg_Cnt|(1<<7); //設(shè)定計(jì)數(shù)器值,并激活開門狗
58
59 }
60
61 //窗口看門狗喂狗
62
63 void Wwdg_Feed()
64 {
65 WWDG->CR |= (Wwdg_Cnt&0x7F);
66
67 }
Library/wdg.h
1 #include
2
3 void Iwdg_Init(u8pre,u16 rlr);
4 void Iwdg_Feed(void);
5
6 void Wwdg_Init(u8 cnt,u8 w_cnt,u8);
7 void Wwdg_Feed(void);
需要注意的是 獨(dú)立看門狗沒有響應(yīng)的中斷。
評論