简介看门狗的作用就是在程序出问题时复位程序让程序从头运行。看门狗本质是定时器计数器在自减程序在规定时间内重置计数器喂狗不让计数器归0如果程序出问题没有及时重置导致计数归0硬件电路就会自动复位。独立看门狗的独立表现在它有专用的时钟LSI时间要求是不能晚于一个时间点喂狗窗口看门狗的时钟是APB1总线时钟没有专用时钟时间要求是不能早于一个时间点喂狗也不能晚于一个时间点喂狗所以它比独立看门狗能处理更多问题比如程序跑飞但依然会在一个时间点之前喂狗程序有时比较早喂狗有时比较晚喂狗。IWDG结构IWDG中预分频器是8位的最多可以256分频计数器是12位最大值是4095。时钟LSI经过预分频后控制计数器自减一次的时间预先在RLR寄存器中写入重装值然后在键寄存器中写入特定数据0xAAAA重装值就会复制到计数器中完成重置喂狗。SR状态寄存器就是标准电路运行状态的。其中的寄存器都位于1.8v供电区工作电路位于VDD供电区。停机和待机模式下HSE,HSI时钟关闭但是IWDG使用LSI时钟没有影响计数器可以继续自减。程序是可能受到干扰的如果常规使用控制寄存器里的某一位来控制看门狗电路有可能会因为干扰使得1变成0或者0变成1改变电路而产生问题。所以使用16位的键寄存器用16位数据来控制电路哪怕因为干扰改变了某几位的值改变之后的值刚好是0xcccc,0xaaaa,0x5555的概率也是很小的如果变成了0x5555以外的值会马上开启对寄存器的写保护增强了抗干扰能力。时间计算IWDG计数器归0的时间*预分频系数*重装值1。就是LSI时钟频率倒数即0.025ms而预分频系数就不是什么写入值1了这里0~7的写入值有分别对应的预分频值。0.025ms*预分频系数即为计数器自减一次所用时间再乘上重装值即为从重装值自减到0所需时间必须在这个时间内喂狗。WWDG结构来自APB1的36MHZ时钟经过预分频后控制计数器自减的时间。在这里设计的是计数器和控制寄存器CR合二为一了T0~T5位用于计数器自减T6位是溢出标志位T61表示未溢出T60表示溢出也就是说对于整个控制寄存器来说自减到10 0000即0x40时就相当于归0了再减就是01 1111T60了表示溢出对于寄存器的T5~T0位来说是自减到0就归0。需要喂狗即重置计数器时直接将值写入CR寄存器就行了。控制寄存器中还有一位WDGA使能位1就看门狗使能WDGA位和取反之后经过一个或门的T6位结果会经过一个与门控制是否复位WDGA0看门狗不使能时与门直接输出为0不复位WDGA1T61即未归0取反后是0经过或门输出值由另一端确定;T60即归0取反是1输出结果为1即归0后会复位。但是看门狗一旦开启就不能关闭了让WDGA0也没用。WWDG除了计数归0会复位之外过早喂狗也会复位。这个较早的时间窗口值在CFR寄存器写入当执行喂狗操作即写入CR寄存器时图中另一个与门的写入CR寄存器这个输入端就1了比较写入重装值之前CR寄存器的值和设置的CFR寄存器的值大小后如果CR的值大于CFR的值说明计数器还没有自减到较早的时间值就喂狗了即喂狗喂早了不在设置的时间窗口内喂狗与门另一端输入1输出结果1再经过或门输出1最后通过与门输出1看门狗复位。工作特性控制寄存器值0x40时T6位1这时还不会复位再自减一次到0x3F时T6位0了就复位了。在0x40时会产生一个中断提醒你马上要复位了中断里可以重置计数器避免复位。时间计算PCLK1时钟在预分频前会进行一个4096分频因为36MHZ还是太快了。所以在计算时间的时候会额外乘上4096这样*4096*预分频系数就是计数器自减一次所用时间再乘上寄存器的T5~T0位1就是计数器从重装值归0的时间。预分频系数2^写入值范围是1、2、4、8。以T5~T0位为准计数器最大可以自减2^6-1即63次。窗口时间即最早喂狗时间*4096*预分频系数*T5~T0位的值 - CFR寄存器低五位的值这就是计数器从重装值自减到最早喂狗的时间。喂狗时间必须在这两个时间点之间。对比IWDG代码使用IWDG需要先开启LSI时钟但开启看门狗时LSI时钟会自动开启所以不需要手动开启了。接下来先解除对寄存器的写保护之后才能写入预分频值和重装值最后开启看门狗在程序中不断循环喂狗。/* 使用IWDG需要先开启LSI时钟但开启看门狗时LSI时钟会自动开启所以不需要手动开启了。接下来先解除对寄存器的写保护 之后才能写入预分频值和重装值最后开启看门狗在程序中不断循环喂狗。 */ int main() { OLED_Init(); key_init(); OLED_ShowString(1,1,IWDG TEST); if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST)SET)//用标志位来判断复位是IWDG导致的还是普通复位 { OLED_ShowString(2,1,IWDGRST); Delay_ms(500); OLED_ShowString(2,1, ); RCC_ClearFlag();//清除看门狗标志位 } else { OLED_ShowString(2,1,RST); Delay_ms(500); OLED_ShowString(2,1, ); } //设定IWDG设置超时时间为1000ms,10000.025*分频系数*重装值1 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//解除写保护。这个函数就是关于写保护的enable就是在键寄存器写入了0x5555即解除写保护 IWDG_SetPrescaler(IWDG_Prescaler_16);//预分频系数尽量选小的频率快可以减小误差 IWDG_SetReload(2500-1);//重装值 //启动看门狗前可以喂一次狗这样开启后就是从重装值开始自减 IWDG_ReloadCounter();//喂狗 IWDG_Enable();//开启看门狗 while(1) { key_num();//按键使用的是阻塞式写法按住按键不松开程序会一直卡死在获取按键就不能执行喂狗操作了,看门狗就会不断复位 IWDG_ReloadCounter(); OLED_ShowString(3,1,FEED);//喂一次狗就闪现一次FEED Delay_ms(500); OLED_ShowString(3,1, ); Delay_ms(300);//间隔800ms或1000ms喂一次狗满足时间要求1000ms内看门狗不会复位,手动按下复位键时屏幕闪现“RST”。间隔1200ms就超时了看门狗复位屏幕会闪现“IWDGRST” } }WWDG代码使用WWDG需要手动开启时钟接下来写入预分频值和最早时间窗口值最后开启看门狗在程序中不断循环向控制寄存器CR写入值即喂狗。使能,也是一次喂狗。看门狗关闭时计数器也在运行着开启看门狗时计数器可能是任何值所以在使能的时候要再赋一次值并与上0x40将T6位置1防止出现一打开就复位的情况还要注意上面的使能喂狗到下面循环喂狗的间隔时间也要满足要求因为这是两次喂狗。/* 使用WWDG需要手动开启时钟接下来写入预分频值和最早时间窗口值最后开启看门狗在程序中不断循环向控制寄存器CR写入值即喂狗。 */ int main() { OLED_Init(); key_init(); OLED_ShowString(1,1,WWDG TEST); if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST)SET)//用标志位来判断复位是WWDG导致的还是普通复位 { OLED_ShowString(2,1,WWDGRST); Delay_ms(500); OLED_ShowString(2,1, ); RCC_ClearFlag();//清除看门狗标志位 } else { OLED_ShowString(2,1,RST); Delay_ms(500); OLED_ShowString(2,1, ); } //设定WWDG时间为30~50ms。得出预分频选择8T5~T0位是54窗口值是21 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); WWDG_SetPrescaler(WWDG_Prescaler_8); WWDG_SetWindowValue(0x40|21);//窗口值用的是低五位所以与上0x40把第六位置1 WWDG_Enable(0x40|54);//使能,也是一次喂狗。看门狗关闭时计数器也在运行着开启看门狗时计数器可能是任何值所以在使能的时候要再赋一次值并与上0x40将T6位置1防止出现一打开就复位的情况 //注意上面的使能喂狗和下面循环的喂狗间隔时间也要满足要求因为这是两次喂狗。 Delay_ms(40); while(1) { key_num();//按键使用的是阻塞式写法按住按键不松开程序会一直卡死在获取按键就不能执行喂狗操作了,看门狗就会不断复位屏幕闪现“WWDGRST” WWDG_SetCounter(0x40|54);//喂狗 OLED_ShowString(3,1,FEED);//喂一次狗就闪现一次FEED Delay_ms(20); OLED_ShowString(3,1, ); Delay_ms(20);//间隔40ms喂一次狗满足时间要求看门狗不会复位,手动按下复位键时屏幕闪现“RST”。 } }