zoukankan      html  css  js  c++  java
  • stm32 窗口看门狗学习(一)

    什么是窗口看门狗?

    1)独立看门狗  
                 限制喂狗时间在0-x内,x由相关寄存器决定。喂狗的时间不能过晚。
    2)窗口看门狗 
                 之所以称为窗口就是因为其喂狗时间是一个“窗口”,
    不能过早也不能过晚。

    STM32F10x 的窗口看门狗中有一个7位的递减计数器,出现下述2种情况之一时产生看门狗复位:  

    1)当计数器的数值从0x40减到0x3F时 ,这里的0x3F可以看成是窗口的下限;  

    2)喂狗的时候,如果计数器的值大于某一设定数值(这个数值是窗口的上限),此数值在WWDG_CFR寄存器中配置。

    对于一般的看门狗,程序可以在它产生复位前的任意时刻刷新看门狗。但这有一个隐患,有可能程序跑乱了又跑回到正常的地方,或者说跑乱的程序正好执行了刷新看门狗操作,这样的情况一般的看门狗不好检测;  

    如果使用窗口看门狗,程序员可以根据程序正常执行的时间设置一个时间窗口,保证不会提前刷新看门狗也不会滞后刷新看门狗,这样可以检测出程序没有按照正常的路径运行的情况。

    如果非要说窗口看门狗的具体应用,我一时也说不上来,因为没有用过。但是这不妨碍我们做实验学习窗口看门狗。

    先看一幅图,直观地认识窗口看门狗。


    T[6:0]是一个7位的递减计数器,我们刷新看门狗,就是重载这个计数器;W[6:0]是提前配置好的一个数值,作为窗口的上限;0x3F是窗口的下限,是固定值,程序无法修改。

    假如设置T[6:0]的重载值是0x7F,  W[6:0]为0x5F,  那么计数器从0x7F递减到0x5F的过程中(也就是T[6:0]大于W[6:0]的时候),是不能喂狗的。如果喂狗就会复位。

    当T[6:0]从W[6:0]递减到0x3F的过程中,需要喂狗,不然计数器等于0x3F的时候就会复位。


    时间怎么计算?


    根据手册,计数器的计数周期 = T_PCLK1 * 2^WDGTB * 4096,

    这里WDGTB是预分频系数,取值范围是(0,1,2,3)

    假设我们实验中PCLK1的频率是36MHz,WDGTB取3,那么计数器的计数周期 

    T = (1/(36M))* 8 * 4096(s)= 910.222 us


    我们设计一下实验一。

    1.实验中PCLK1的频率是36MHz,WDGTB取3;

    2.T[6:0]设置为0x7F,W[6:0]设置为0x41; 那么刷新窗口就是(0x41~0x3F), 在(0x7F~0x41)是不允许刷新的;

    不允许刷新的时间 = (0x7F - 0x41) * 910.222 us = 56.43 ms

    3.我们在在(0x7F~0x41)这段时间刷新,看看是不是复位(预期结果是一定复位)。

    <span style="font-size:18px;"><span style="font-size:18px;">//初始化窗口看门狗
    //tr :T[6:0],计数器初始值
    //wr :W[6:0],窗口上限
    //fprer:预分频系数,WDGTB[1:0]
    //计数器的计数频率 F_wwdg = PCLK1/(4096*2^fprer). 
    
    void WWDG_Init(u8 tr,u8 wr,u32 fprer)
    { 
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  //   WWDG时钟使能
    	
    	WWDG_SetPrescaler(fprer);//设置预分频系数
    
    	WWDG_SetWindowValue(wr);//设置窗口上限
    
    	WWDG_Enable(tr);	 //设置计数器初值并且使能看门狗                  
    
    } </span></span>

    喂狗的函数是:

    <span style="font-size:18px;"><span style="font-size:18px;">void WWDG_SetCounter(uint8_t Counter)</span></span>


    看看main函数。

    <span style="font-size:18px;">int main(void)
    {	
    	delay_init();	     
    	uart_init(9600);	 
    	LED_Init();
    	
    	printf("Hello World ! 
    ");
     	delay_ms(970);
    	
    	WWDG_Init(0x7F,0x41,3);//窗口看门狗初始化
    	delay_ms(30); //必须小于56.43ms
    	
    	WWDG_SetCounter(0x7F);	//喂狗,应该产生复位
    	
    
    	while(1)
    	{
    		LED0 = !LED0;
    		delay_ms(300);	  
    	}
    	
    }</span>

    看看实验结果。


    确实1s左右会重启一次。

    如果我们不喂狗,把那行语句注释调

    <span style="font-size:18px;">//WWDG_SetCounter(0x7F);	//喂狗,应该产生复位</span>

    结果是也会复位,但是LED没有闪烁,为什么呢?估计是还没有执行到操作LED的语句的时候就复位了。

    <span style="font-size:18px;">//delay_ms(30); </span>
    把这句也注释了,就可以看到灯的闪烁。

    实验二

    1.实验中PCLK1的频率是36MHz,WDGTB取3;

    2.T[6:0]设置为0x7F,W[6:0]设置为0x7E; 那么刷新窗口就是(0x7E~0x3F), 在(0x7F~0x7E)是不允许刷新的;

    不允许刷新的时间 = (0x7F - 0x7E) * 910.222 us = 0.91 ms

    3.我们在在(0x7E~0x3F),这段时间刷新,看看是不是复位(预期结果是不复位)。

    <span style="font-size:18px;">int main(void)
    {	
    	delay_init();	     	  
    	
    	uart_init(9600);	
    	LED_Init();
    	delay_ms(200);
    	LED0=0; //led on
    	printf("Hello World ! 
    ");
     	delay_ms(200);
    	LED0= 1; //led off
    	
    	WWDG_Init(0x7F,0x7E,3); 
    	
    	while(1)
    	{
    		
    		delay_ms(1);	 
    		WWDG_SetCounter(0x7F);	//喂狗
    	}
    	
    }
    </span>
    实验结果是不复位,灯不闪烁,串口也不打印。

    如果把喂狗的语句注释调,就会看到灯一直在闪烁,串口一直打印,说明一直复位。

    上面的代码,喂狗的时间不好掌握,很容易错过窗口。参考网上的例子,有一种查询的方法喂狗。

    	while(1)
    	{
    		if((WWDG->CR & 0x7F) == 0x55)
    			WWDG_SetCounter(0x7F);	
    	}

    今天就说到这里,下次接着玩。



  • 相关阅读:
    vue 启动报错:`TypeError: Cannot read property 'range' of null`
    手动创建自己的npm包
    uni-app 拦截页面传参
    uni-app的vue.config.js
    插入排序
    选择排序
    设计模式--享元模式
    设计模式--代理模式
    原型链图片
    深度优先遍历和广度优先遍历
  • 原文地址:https://www.cnblogs.com/longintchar/p/5224425.html
Copyright © 2011-2022 走看看