打印
[应用相关]

STM32 独立看门狗IWDG 与窗口看门狗WWDG

[复制链接]
1081|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
powerful1|  楼主 | 2015-3-27 00:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
独立看门狗Iwdg——有独立时钟(内部低速时钟LSI---40KHz),所以不受系统硬件影响的系统故障探测器。主要用于监视硬件错误。
窗口看门狗wwdg——时钟与系统相同。如果系统时钟不走了,这个狗也就失去作用了,主要用于监视软件错误。
一,独立看门狗
看门狗定时时限= IWDG_SetReload()的值 / 看门狗时钟频率
看门狗时钟频率=LSI(内部低速时钟)的频率(40KHz/ 分频数
1.STM32
独立看门狗IWDG的时限定为280微秒。这个时限可能会随着LSI(内部低速时钟)的频率漂移而产生微小的变化。
/* IWDG timeout equal to 280 ms (thetimeout may varies due to LSI frequency dispersion)-------------------------------------------------------------
*/
/* Enable write access to IWDG_PR and IWDG_RLRregisters */
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
/* IWDG counter clock: 40KHz(LSI) / 32 =1.25 KHz */
IWDG_SetPrescaler(IWDG_Prescaler_32);
/* Set counter reload value to 349 */
IWDG_SetReload(349);
/*该参数允许取值范围为0 0x0FFF *
/* Reload IWDG counter */
IWDG_ReloadCounter();
/* Enable IWDG (the LSI oscillator will beenabled by hardware) */
IWDG_Enable();
2.独立看门狗(IWDG)由专用的40kHz 的低速时钟为驱动;因此,即使主时钟发生故障它也仍然有效。窗口看门狗由从APB1 时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的行为。可通过
IWDG_SetPrescaler(IWDG_Prescaler_32); 对其时钟进行分频,4-256
通过以下方式喂狗
/* Reload IWDG counter */
IWDG_ReloadCounter();
3. 1.25KHz 即每周期 0.8ms
    共计时 350 个周期,即350*0.8ms=280ms
   看门狗定时时限= IWDG_SetReload()的值 / 看门狗时钟频率
   看门狗时钟频率=LSI(内部低速时钟)的频率(40KHz/ 分频数
参考http://www.opelc.org/html/99/t-2599.htmlhttp://blog.chinaunix.net/u3/93821/showart_1999233.html
二,窗口看门狗
STM32F的窗口看门狗中有一个7位的递减计数器,它会在出现下述2种情况之一时产生看门狗复位:
  
  1)当计数器的数值从0x40减到0x3F
  
  2)当刷新看门狗时计数器的数值大于某一设定数值时,此设定数值在WWDG_CFR寄存器定义
  
  对于一般的看门狗,程序可以在它产生复位前的任意时刻刷新看门狗,但这有一个隐患,有可能程序跑乱了又跑回到正常的地方,或跑乱的程序正好执行了刷新看门狗操作,这样的情况下一般的看门狗就检测不出来了;如果使用窗口看门狗,程序员可以根据程序正常执行的时间设置刷新看门狗的一个时间窗口,保证不会提前刷新看门狗也不会滞后刷新看门狗,这样可以检测出程序没有按照正常的路径运行非正常地跳过了某些程序段的情况。

沙发
powerful1|  楼主 | 2015-3-27 00:34 | 只看该作者
STM32窗口看门狗使用?(WWDG)
上午搞定RTC之后,开始弄IWDGWWDG,IWDG比较容易,配置也很简单,参考ST的代码就能很快搞定.但是WWDG就不行了,搞了很久都不行,ST的库做,keil上仿真也不行,主要原因就是WWDG->CR寄存器中的计数值不会减少!
     其他配置也都正确了,WWDG->CR就是不减少,我不知道是不是PCLK1的时钟没有,但是从keil的仿真可以看到PCLK1的时钟是36M,没道理没有,很是郁闷,不知道哪位朋友用过STM32WWDG没有?请指教!
多谢先.
我用的是STM32F103RBT6.
主函数:
#include "stm32f10x_lib.h"
#include "sys.h"  
#include "led.h"
#include "delay.h"
#include "wwdg.h"           
int main(void)//GPIO
{  
//u32 temp;      
Stm32_Clock_Init();//系统时钟设置      
   led_init();
//DBGMCU->CR=0X00000000;
delay_init(72);//72M系统时钟
   //delay_ms(300);
wwdg_init();  //配置并使能IWDG   
//temp=DBGMCU->CR;
while (1)
   {        
     LED0_SET(0);
//WWDG->CR&=~(1<<6);
delay_us(500000);//在这里系统重启           
   }      
}
wwdg.h代码:
#ifndef __WWDG_H
#define __WWDG_H
//看门狗定时器中断配置
void NVIC_WWDGConfiguration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;  
#ifdef VECT_TAB_RAM            
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else /* VECT_TAB_FLASH  */         
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif     
NVIC_InitStructure.NVIC_IRQChannel =WWDG_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 1;
NVIC_Init(&NVIC_InitStructure);
}
void wwdg_init(void)
{
NVIC_WWDGConfiguration();
        
RCC->APB1ENR|=1<<11; //窗口看门狗时钟使能.        
  WWDG->CFR|=1<<8;    //CLKww=PCLK1/4096/8=244Hz
  WWDG->CFR|=1<<7;   
WWDG->CFR&=0X380;  
WWDG->CFR|=65;   //窗口值设置为65
WWDG->CR=0X7F;   //计数值设定为0X7F
WWDG->CR|=1<<7;      //开启看门狗   
WWDG->SR&=0XFFFFFFFE;//清除EWIF
WWDG->CFR|=1<<9;     //提前唤醒中断
}
//串口看门狗中断
void WWDG_IRQHandler(void)
{        
  WWDG_SetCounter(0x7F);   
  WWDG_ClearFlag();  
}
#endif  
sys.h中的代码:
#ifndef __SYS_H
#define __SYS_H     
#include "stm32f10x_lib.h"
//系统时钟初始化
//使用外部8M晶振,PLL72M频率      
//正点原子@SCUT
//2008/12/04
#define uint unsigned int
#define uchar unsigned char
/*
#define CLOCK 72/8 //时钟=72M
//us延时函数
void delay_us(unsigned int us)
{
u8n;      
while(us--)for(n=0;n<CLOCK;n++);   
}
//ms延时函数
void delay_ms(unsigned int ms)
{
while(ms--)delay_us(1000);  
} */
//把所有时钟寄存器复位
void RCC_RESETInit(void)
{
RCC->APB2RSTR = 0XFFFFFFFF;//外设复位   
RCC->APB1RSTR = 0XFFFFFFFF;            
RCC->APB2RSTR = 0X00000000;//复位恢复   
RCC->APB1RSTR = 0X00000000;  
     
  RCC->AHBENR = 0x00000014; //flash时钟,闪存时钟使能.DMA时钟关闭   
  RCC->APB2ENR = 0x00000000; //外设时钟关闭.      
  RCC->APB1ENR = 0x00000000;   
RCC->CR |= 0x00000001;     //使能内部高速时钟HSION                  
RCC->CFGR &= 0xF8FF0000;   //复位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]      
RCC->CR &= 0xFEF6FFFF;     //复位HSEON,CSSON,PLLON
RCC->CR &= 0xFFFBFFFF;     //复位HSEBYP      
RCC->CFGR &= 0xFF80FFFF;   //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE
RCC->CIR = 0x00000000;     //关闭所有中断
}
//外部8M,则得到72M的系统时钟
void Stm32_Clock_Init(void)
{
unsigned char temp="0";
u8timeout="0";
RCC_RESETInit();
RCC->CR|=0x00010000;  //外部高速时钟使能HSEON
timeout=0;
while(!(RCC->CR>>17)&&timeout<200)timeout++;//等待外部时钟就绪  
//0-24M等待0;24-48M 等待1;48-72M等待2;(非常重要!)   
FLASH->ACR|=0x32;//FLASH 2个延时周期
RCC->CFGR|=0X001D2400;//APB1/2=DIV2;AHB=DIV1;PLL=9*CLK;HSE作为PLL时钟源
RCC->CR|=0x01000000;  //PLLON
timeout=0;
while(!(RCC->CR>>25)&&timeout<200)timeout++;//等待PLL锁定
RCC->CFGR|=0x00000002;//PLL作为系统时钟
while(temp!=0x02&&timeout<200)     //等待PLL作为系统时钟设置成功
{   
temp=RCC->CFGR>>2;
timeout++;
temp&=0x03;
}  
}
#endif
delay.h中的代码:
#ifndef __DELAY_H
#define __DELAY_H      
//使用SysTick的普通计数模式对延迟进行管理
//包括delay_us,delay_ms  
//正点原子@SCUT
//2008/12/13  
static u8 fac_us=0;//us延时倍乘数
static u16 fac_ms=0;//ms延时倍乘数
//初始化延迟函数
void delay_init(u8 SYSCLK)
{
SysTick->CTRL&=0xfffffffb;//选择内部时钟 HCLK/8
fac_us=SYSCLK/8;      
fac_ms=(u16)fac_us*1000;
}           
//延时Nms
//注意Nms的范围
//Nms<=0xffffff*8/SYSCLK
//72M条件下,Nms<=1864
void delay_ms(u16 nms)
{   
SysTick->LOAD=(u32)nms*fac_ms; //时间加载  
SysTick->CTRL|=0x01;               //开始倒数   
while(!(SysTick->CTRL&(1<<16)));   //等待时间到达
SysTick->CTRL&=0XFFFFFFFE;         //关闭计数器
SysTick->VAL=0X00000000;           //清空计数器     
}   
//延时us           
void delay_us(u32 Nus)
{
SysTick->LOAD=Nus*fac_us;       //时间加载      
SysTick->CTRL|=0x01;            //开始倒数   
while(!(SysTick->CTRL&(1<<16)));//等待时间到达
SysTick->CTRL=0X00000000;       //关闭计数器
SysTick->VAL=0X00000000;        //清空计数器     
}  
#endif
WWDG了解及疑惑
void, 时钟
本帖最后由 冬夜冰城 2011-2-13 21:00 编辑
一、主函数:
int main(void)
{
#ifdef DEBUG
debug();
#endif
//配置系统时钟
RCC_Configuration();
GPIO_Configuration();
EXTI_Configuration();
  NVIC_Configuration();
  if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET)  
  {
GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_SET);
   /*可以清除的复位标志位有: RCC_FLAG_PINRST, RCC_FLAG_PORRST, RCC_FLAG_SFTRST,
     RCC_FLAG_IWDGRST,  RCC_FLAG_WWDGRST, RCC_FLAG_LPWRRST */
RCC_ClearFlag();
  }
else
  {
  GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_RESET);
  }
WWDG_Configuration();
  /*Infinite loop */
while (1);
}
二、窗口看门狗初始化函数
void WWDG_Configuration(void)
{
   /* 开启窗口看门狗时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
//  /* Deinitialize the WWDG registers将外设 WWDG寄存器重设为缺省值  */
//   从其底层函数可以看出,初始化关闭窗口看门狗时钟
//  WWDG_DeInit();
   /*Set WWDG prescaler to 8 设置 WWDG 预分频值PCLK1/4096/8=1098.6 */
  WWDG_SetPrescaler(WWDG_Prescaler_8);
   /*Set WWDG window value to 0x41指定的窗口值,该参数取值必须在0x40 0x7F之间。  */
  WWDG_SetWindowValue(0x41);
  /*Enable WWDG and set counter value to 0x7F 使能窗口看门狗,并把看门狗计数器的值设为0x7f*/
   WWDG_Enable(0x7f);
   /*Clear EWI flag 清除早期唤醒中断标志位 */
  WWDG_ClearFlag();  
   /*Enable WWDG Early wakeup interrupt 使能 WWDG 早期唤醒中断(EWI  */
  WWDG_EnableIT();  
}
三、中断处理函数
void WWDG_IRQHandler(void)
{
   /*Set WWDG counter value to 0x70 设置计数器值为0x7f*/
   WWDG_SetCounter(0x7f);
/* Clear EWI flag清除早期唤醒中断标志位 */
   WWDG_ClearFlag();
/*闪烁PB14*/
  GPIO_WriteBit(GPIOB,GPIO_Pin_14,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_14)));
}
四、外中断设置函数等省略
五、问题及解决
1.遇到问题为  当复位后存在标志位使PB15点亮,点亮后清除标志位但标志位一直存在2.    为什么开启窗口看门狗时钟,再关闭时看门狗还正常运行
即先写:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
后写:
   WWDG_DeInit();(其底层函数为  
RCC_APB1PeriphResetCmd(RCC_APB1Periph_WWDG,ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_WWDG, DISABLE);
解决:把
    WWDG_Enable(0x7f);
     WWDG_ClearFlag();  
     WWDG_EnableIT();顺序写反了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

88

主题

430

帖子

4

粉丝