stm32 独立看门狗[操作寄存器+库函数]

以单片机为核心的微型计算机系统中,单片机经常会受到来自外界电磁场的干扰。
造成程序跑飞,只是程序的正常运行状态被打断而进入死循环,从而使单片机控制的系统无法正常工作。看门狗就是一种专门用于检测单片机程序运行状态的硬件结构。
 
stm32也是如此。
 
stm32 的独立看门狗由内部专门的40Khz低速时钟驱动,即使主时钟发生故障时,它也仍然有效。这里需要注意的是独立看门狗的时钟是一个内部时钟,所以不是准确的40Khz,而是在30~60Khz之间的一个可变化的时钟,看门狗的时钟对时间的要求不是很精确,所以时钟有偏差可以接受。
 
本例直接操作寄存器实现验证独立看门狗的复位功能,设定一个800ms的喂狗时间,在主函数中实现LED闪烁,如果设定一个1s的延时,则触发独立看门狗复位,LED常亮。
库函数实现当外部中断发生(按下PA0按键),长时间不喂狗,引发独立看门狗复位时,向外用串口输出复位提示。
 
 
直接操作寄存器
 
使用独立看门狗,需要了解一下寄存器:
 
键值寄存器:(IWDG_KR)
低16位有效的寄存器,只写寄存器,读出值恒为0x0000.
软件必须以一定的间隔写入0xAAAA,否则,当计数器为0时,看门狗会产生复位。
写入0x5555表示允许访问IWDG_PR和IWDG_RLR寄存器。
写入0xCCCC,启动看门狗工作。
 
预分频寄存器:(IWDG_PR)
第三位有效寄存器,用于设置看门狗的分频系数,最低为4,最高位256.
通过设置PR[2:0]:位来选择计数器时钟的预分频因子。要改变预分频因子,IWDG_SR寄存器的PVU位必须为0。
  • 000: 预分频因子=4                 100: 预分频因子=64
  • 001: 预分频因子=8                 101: 预分频因子=128
  • 010: 预分频因子=16               110: 预分频因子=256
  • 011: 预分频因子=32               111: 预分频因子=256

重装载寄存器:(IWDG_RLR)

低12位有效,RL[11:0]。用于定义看门狗计数器的重装载值。
每当向IWDG_KR寄存器写入0xAAAA时,重装载值会被传送到计数器中。随后计数器从这个值开始递减计数。看门狗超时周期可通过此重装载值和时钟预分频值来计算。 只有当IWDG_SR寄存器中的RVU位为0时,才能对此寄存器进行修改。 
 
状态寄存器:(IWDG_SR)
只有低两位有效。都由硬件置’1’和 清’0’。
RVU[1]: 看门狗计数器重装载值更新
PVU[0]: 看门狗预分频值更新
 
代码如下:  (system.h 和 stm32f10x_it.h 等相关代码参照  stm32 直接操作寄存器开发环境配置)
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);             //系统时钟设置
14  
15     Gpio_Init();
16  
17     Iwdg_Init(3,1000);  //设定为800ms内喂狗
18  
19     while(1){
20          
21         LED1 = !LED1;
22  
23         delay(100000);    //延时100ms后喂狗,LED闪烁
24  
25         //delay(1000000);     //延时1000ms,引发独立看门狗复位,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设置为浮空输入,PA4~7设置为推挽输出
39     GPIOA->CRL|=0x33334444;
40    
41 }
Library/wdg.c   (此文件包含了独立看门狗和窗口看门狗的驱动函数)
01 #include
02 #include "wdg.h"
03  
04 /********************************************
05  *
06  *本文件包含窗口看门狗和独立看门口的相关函数
07  *
08  *********************************************/
09  
10 u8 Wwdg_Cnt = 0x7F;  //计数器值,默认为最大值127
11  
12 //独立看门狗初始化
13 //参数说明:
14 //          pre:分频数(0~7),相应分频因子为4*(2^pre)
15 //          rlr:低12位有[11:0]
16 // 喂狗时间计算: 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;     //设置分频数
21     IWDG ->RLR = rlr;        //设定重装值
22     IWDG ->KR =  0xAAAA;    //装载RLR值到看门狗计数器,即喂狗
23     IWDG ->KR =  0xCCCC;    //启动看门狗
24 }
25  
26 //独立看门狗喂狗
27 void Iwdg_Feed()
28 {
29     IWDG -> KR = 0xAAAA;  //喂狗
30 }
31  
32 //窗口看门狗初始化
33 //参数说明:
34 //          cnt     计数器的值,最大 127,0x7F
35 //          w_cnt   窗口值,最大 127,0x7F
36 //          pre     预分频器的时基值,低两位有效;实际时钟为: PLCK1/4096/2^pre
37 //需要再主函数中开启中断 WWDG_IRQChannel
38 //设定喂狗时间范围必须在:(WWDG时钟为PCLK1,36Mhz)
39 //          Tmax =(4096*2^pre*(cnt-63)/36)  (us)
40 //          Tmin =(4096*2^pre*(cnt-w_cnt)/36)   (us)
41 //超出次时间喂狗复位
42  
43 void Wwdg_Init(u8 cnt,u8 w_cnt,u8 pre)
44 {
45     u8 Cnt_Max = 0x7f;    //计数器最大值
46  
47     Wwdg_Cnt = Cnt_Max&cnt;   //设定计数器的值,防止溢出
48  
49     RCC->APB1ENR |= 1<<11;
50  
51     WWDG -> CFR |= pre <<7;  //设定预分频器的时基,实际分频值我
52     WWDG -> CFR |= 1<<9;    //使能中断
53  
54     WWDG -> CFR &= 0xFF80;   //初始化低七位,即窗口值清0
55     WWDG -> CFR |= w_cnt;    // 设定窗口值
56  
57     WWDG -> CR  |= Wwdg_Cnt|(1<<7);  //设定计数器值,并激活开门狗
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(u8 pre,u16 rlr);
4 void Iwdg_Feed(void);
5  
6 void Wwdg_Init(u8 cnt,u8 w_cnt,u8);
7 void Wwdg_Feed(void);
 
需要注意的是 独立看门狗没有响应的中断。
 
库函数操作
 
main.c
view source
print ?
001 #include "stm32f10x.h"
002 #include "stdio.h"
003  
004 #define  PRINTF_ON  1
005  
006 void RCC_Configuration(void);
007 void GPIO_Configuration(void);
008 void NVIC_Configuration(void);
009 void USART_Configuration(void);
010 void IWDG_Configuration(void);
011 void EXTI_Configuration(void);
012  
013 vu32 DelayTime;
014  
015 int main(void)
016 {
017     RCC_Configuration();
018     GPIO_Configuration();
019     NVIC_Configuration();
020     USART_Configuration();
021     EXTI_Configuration();
022     IWDG_Configuration();
023  
024     while(1){  
025         if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET)
026         {
027             printf("\r\n The Stm32 has been reset by IWDG .\r\n");
028             RCC_ClearFlag();
029         }
030  
031         //do sth. here
032         DelayTime = 100000;
033         while(--DelayTime);        
034         // 延时17ms
035                  
036         IWDG_ReloadCounter();   //80ms不喂狗复位
037         GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(1- GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)));
038     }  
039 }
040  
041 void EXTI_Configuration(void)
042 {
043     EXTI_InitTypeDef EXTI_InitStructure;
044  
045     EXTI_InitStructure.EXTI_Line = EXTI_Line0;
046     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
047     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
048     EXTI_InitStructure.EXTI_LineCmd = ENABLE;
049     EXTI_Init(&EXTI_InitStructure);
050  
051     GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
052  
053 }
054  
055 void GPIO_Configuration(void)
056 {
057     GPIO_InitTypeDef GPIO_InitStructure;                                                                                    
058     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
059     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
060     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;          
061     GPIO_Init(GPIOA , &GPIO_InitStructure);
062      
063     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
064     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;           
065     GPIO_Init(GPIOA , &GPIO_InitStructure);     
066  
067  
068     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
069     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        
070     GPIO_Init(GPIOA , &GPIO_InitStructure);
071      
072     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
073     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;          
074     GPIO_Init(GPIOA , &GPIO_InitStructure);
075  
076 }
077  
078 void IWDG_Configuration(void)
079 {
080     RCC_LSICmd(ENABLE);                              //打开LSI
081     while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET);
082  
083     IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
084     IWDG_SetPrescaler(IWDG_Prescaler_32);
085     IWDG_SetReload(100);      //80ms ,max 0xFFF  0~4095 
086     IWDG_ReloadCounter();
087     IWDG_Enable();
088 }
089  
090  
091 void RCC_Configuration(void)
092 {
093     /* 定义枚举类型变量 HSEStartUpStatus */
094     ErrorStatus HSEStartUpStatus;
095  
096     /* 复位系统时钟设置*/
097     RCC_DeInit();
098     /* 开启HSE*/
099     RCC_HSEConfig(RCC_HSE_ON);
100     /* 等待HSE起振并稳定*/
101     HSEStartUpStatus = RCC_WaitForHSEStartUp();
102     /* 判断HSE起是否振成功,是则进入if()内部 */
103     if(HSEStartUpStatus == SUCCESS)
104     {
105         /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
106         RCC_HCLKConfig(RCC_SYSCLK_Div1);
107         

你可能感兴趣的:(微机保护遇到的问题)