一、独立看门狗
STM32的独立看门狗由内部专门的40Khz低速时钟驱动,即便主时钟发生毛病,它也依然有用。
看门狗的原理:单片机体系在外界的搅扰下会呈现程序跑飞的现象导致呈现死循环,看门狗电路便是为了防止这种状况的发生。看门狗的效果便是在必守时刻内(经过守时计数器完成)没有接纳喂狗信号(表明MCU现已挂了),便完成处理器的主动复位重启(发送复位信号)。
在键值寄存器(IWDG_KR)中写入0xCCCC,开端启用独立看门狗;此刻计数器开端从其复位值0xFFF递减计数。当计数器计数到结尾0x000时,会发生一个复位信号(IWDG_RESET)。不管何时,只需键寄存器IWDG_KR中被写入0xAAAA,IWDG_RLR中的值就会被从头加载到计数器中然后防止发生看门狗复位。
IWDG_PR和IWDG_RLR寄存器具有写维护功用。要修正这两个寄存器的值,有必要先向IWDG_KR寄存器中写入0x5555。将其他值写入这个寄存器将会打乱操作次序,寄存器将从头被维护。重装载操作(即写入0xAAAA)也会发动写维护功用。
只需对以上三个寄存器进行相应的设置,咱们就能够发动STM32的独立看门狗,发动进程能够按如下过程完成(独立看门狗相关的库函数和界说散布在文件stm32f10x_iwdg.h和stm32f10x_iwdg.c中):
1)撤销寄存器写维护(向IWDG_KR写入0X5555)
经过这步,咱们撤销IWDG_PR和IWDG_RLR的写维护,使后边能够操作这两个寄存器,设置IWDG_PR和IWDG_RLR的值。这在库函数中的完成函数是:
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
2)设置独立看门狗的预分频系数和重装载值
设置看门狗的分频系数的函数是:
voidIWDG_SetPrescaler(uint8_TIWDG_Prescaler);//设置IWDG预分频值
设置看门狗的重装载值的函数是:
voidIWDG_SetReload(uint16_tReload);//设置IWDG重装载值
设置好看门狗的分频系数prer和重装载值就能够知道看门狗的喂狗时刻(也便是看门狗溢出时刻),该时刻的核算办法为:
Tout=((4×2^prer)×rlr)/40
其间Tout为看门狗溢出时刻(单位为ms);prer为看门狗时钟预分频值(IWDG_PR值),规模为0~7;rlr为看门狗的重装载值(IWDG_RLR的值);
比方咱们设定prer值为4,rlr值为625,那么就能够得到Tout=64×625/40=1000ms,这样,看门狗的溢出时刻便是1s,只需你在一秒钟之内,有一次写入0XAAAA到IWDG_KR,就不会导致看门狗复位(当然写入屡次也是能够的)。这儿需求提示咱们的是,看门狗的时钟不是精确的40Khz,所以在喂狗的时分,最好不要太晚了,不然,有可能发生看门狗复位。
3)重载计数值喂狗(向IWDG_KR写入0XAAAA)
库函数里边重载计数值的函数是:
IWDG_ReloadCounter();//依照IWDG重装载寄存器的值重装载IWDG计数器
经过这句,将使STM32从头加载IWDG_RLR的值到看门狗计数器里边。即完成独立看门狗的喂狗操作。
4)发动看门狗(向IWDG_KR写入0XCCCC)
库函数里边发动独立看门狗的函数是:
IWDG_Enable();//使能IWDG
经过这句,来发动STM32的看门狗。留意IWDG在一旦启用,就不能再被封闭!想要封闭,只能重启,而且重启之后不能翻开IWDG,不然问题仍旧,所以在这儿提示咱们,假如不必IWDG的话,就不要去翻开它,以免费事。
/**
*初始化独立看门狗
*prer:分频数:0~7(只要低3位有用!)
*分频因子=4*2^prer.但最大值只能是256!
*rlr:重装载寄存器值:低11位有用。
*时刻核算(大约):Tout=((4*2^prer)*rlr)/40(ms)。
*/
voidIWDG_Init(u8prer,u16rlr)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);/*使能对寄存器IWDG_PR和IWDG_RLR的写操作*/
IWDG_SetPrescaler(prer);/*设置IWDG预分频值:设置IWDG预分频值*/
IWDG_SetReload(rlr);/*设置IWDG重装载值*/
IWDG_ReloadCounter();/*依照IWDG重装载寄存器的值重装载IWDG计数器*/
IWDG_Enable();/*使能IWDG*/
}
/**
*喂独立看门狗
*/
voidIWDG_Feed(void)
{
IWDG_ReloadCounter();/*reload*/
}
/**
*main函数
*/
voidmain(void)
{
NVIC_ConfiguraTIon();//优先级装备
IWDG_Init(4,625);//初始化独立看门狗,分频数为64,重装载值为625,溢出时刻核算为:64*625/40=1000ms=1s
while(1)
{
delay_ms(500);//0.5秒喂一次狗
IWDG_Feed();//喂狗
}
}
二、窗口看门狗
窗口看门狗(WWDG)通常被用来监测由外部搅扰或不行预见的逻辑条件形成的应用程序违背正常的运转序列而发生的软件毛病。除非递减计数器的值在T6位(WWDG-》CR的第六位)变成0前被改写,看门狗电路在到达预置的时刻周期时,会发生一个MCU复位。在递减计数器到达窗口装备寄存器(WWDG-》CFR)数值之前,假如7位的递减计数器数值(在操控寄存器中)被改写,那么也将发生一个MCU复位。这表明递减计数器需求在一个有限的时刻窗口中被改写。
小总结:
1、有个7位递减计数器(WWDG-》CR),就这个计数器和窗口计数器(WWDG-》CFR)决议什么时分喂狗。狗喂早了,复位——“早”体现在计数器值(tr)》窗口值(wr),也便是计数器值还没有减到窗口值以下;
2、当0x40《计数器值(tr)《窗口值(wr)时,这时分最适合喂狗了,也只要在这时分喂狗才适宜;
3、当计数器的值从0x40变到0x3F的时分,将发生看门狗复位;当然在要发生复位的前一段时刻,假如敞开了提早唤醒中止,那么就会进入中止,在中止函数里,咱们需求及时喂狗,不然会发生复位;
4、据网上材料介绍,在这个中止里边一般不进行喂狗,一般是体系逝世前的“遗言”,比方存储重要的数据等。这个就需求依据个人需求规划。
库函数顶用中止的办法来喂狗的办法,窗口看门狗库函数相关源码和界说散布在文件stm32f10x_wwdg.c文件和头文件stm32f10x_wwdg.h中。过程如下:
1)使能WWDG时钟
WWDG运用的是PCLK1的时钟,需求先使能时钟。办法是:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);//WWDG时钟使能
2)设置窗口值和分频数
设置窗口值的函数是:
voidWWDG_SetWindowValue(uint8_tWindowValue);
这个函数就一个进口参数为窗口值,很简单了解。
设置分频数的函数是:
voidWWDG_SetPrescaler(uint32_tWWDG_Prescaler);
这个函数相同只要一个进口参数便是分频值。
3)敞开WWDG中止并分组
敞开WWDG中止的函数为:
WWDG_EnableIT();//敞开窗口看门狗中止
接下来是进行中止优先级装备,运用NVIC_Init()函数即可。
4)设置计数器初始值并使能看门狗
这一步在库函数里边是经过一个函数完成的:
voidWWDG_Enable(uint8_tCounter);
该函数既设置了计数器初始值,一起使能了窗口看门狗。
5)编写中止服务函数
在最终,仍是要编写窗口看门狗的中止服务函数,经过该函数来喂狗,喂狗要快,不然当窗口看门狗计数器值减到0X3F的时分,就会引起软复位了。在中止服务函数里边也要将状况寄存器的EWIF位清空。
完成了以上5个过程之后,咱们就能够运用STM32的窗口看门狗了。
staTIcu8WWDG_CNT=0x7f;/*保存WWDG计数器的设置值,默以为最大。*/
/**
*初始化窗口看门狗
*tr:T[6:0],计数器值
*wr:W[6:0],窗口值
*fprer:分频系数(WDGTB),仅最低2位有用
*Fwwdg=PCLK1/(4096*2^fprer)。
*/
voidWWDG_Init(u8tr,u8wr,u32fprer)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);/*WWDG时钟使能*/
WWDG_SetPrescaler(fprer);/*设置IWDG预分频值*/
WWDG_SetWindowValue(wr);/*设置窗口值*/
WWDG_CNT=tr&WWDG_CNT;/*初始化WWDG_CNT.*/
WWDG_Enable(WWDG_CNT);/*使能看门狗,设置counter。*/
WWDG_ClearFlag();/*铲除提早唤醒中止标志位*/
WWDG_NVIC_Init();/*初始化窗口看门狗NVIC*/
WWDG_EnableIT();/*敞开窗口看门狗中止*/
}
/**
*窗口看门狗中止服务程序
*/
voidWWDG_NVIC_Init(void)
{
NVIC_InitTypeDefNVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn;/*WWDG中止*/
/*抢占2,子优先级3*/
NVIC_InitStructure.NVIC_IRQChannelPreempTIonPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
NVIC_Init(&NVIC_InitStructure);/*NVIC初始化*/
}
/**
*重设置WWDG计数器的值
*/
voidWWDG_Set_Counter(u8cnt)
{
WWDG_Enable(cnt);/*使能看门狗,设置counter。*/
}
/**
*看门狗中止服务程序
*/
voidWWDG_IRQHandler(void)
{
WWDG_Set_Counter(WWDG_CNT);
WWDG_ClearFlag();/*铲除提早唤醒中止标志位*/
LED1=~LED1;/*LED状况翻转*/
}