• STM32单片机——看门狗(独立看门狗&窗口看门狗)


    • 在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog)

    独立看门狗(IWDG)

    独立看门狗本质相关概念

    • 独立看门狗概念
        独立看门狗工作在主程序之外,能够完全独立工作,它的时钟是专用的低速时钟(LSI),由VDD 电压供电, 在停止模式和待机模式下仍能工作

    • 独立看门狗本质
        独立看门狗本质是一个 12 位的递减计数器,当计数器的值从某个值一直减到0的时候,系统就会产生一个复位信号,即 IWDG_RESET 。
        如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。

    • 独立看门狗框图

    • 独立看门狗时钟
        独立看门狗的时钟由独立的RC振荡器LSI提供,即使主时钟发生故障它仍然有效,非常独立。启用IWDG后,LSI时钟会自动开启。LSI时钟频率并不精确,F1用40kHz
        LSI经过一个8位的预分频器得到计数器时钟。

    • 预分频寄存器

      分频系数算法

      prer是IWDG_PR 的值

    • 溢出计算时间公式

    独立看门狗实验

    • 需求:开启独立看门狗,溢出时间为1秒,使用按键1进行喂狗

    CubeMX工程配置

    • 配置时钟及时钟树
      1. 采用外部高速晶振
      2. 时钟树配置
    • 独立开门狗配置
      1. 启动独立看门狗
      2. 参数设置(分频系数和重装载值)
    • 打开串口通信
      1. 配置异步通信模式
      2. 串口波特率及参数配置

    HAL库程序设计

    HAL_UART_Transmit(&huart1,(unsigned char *)"hello world\r\n",strlen("hello world\r\n"),200);		//while(1) 之前运行,每1秒溢出,重复程序
    
    //按键喂狗  使得程序继续运行
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    	if(GPIO_Pin == KEY1_Pin)
    	{
    			HAL_IWDG_Refresh(&hiwdg);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    固件库程序设计

    • IWDG独立看门狗操作库函数
      void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);//取消写保护:0x5555使能
      void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);	//设置预分频系数:写PR
      void IWDG_SetReload(uint16_t Reload);//设置重装载值:写RLR
      void IWDG_ReloadCounter(void);//喂狗: 写0xAAAA到KR
      void IWDG_Enable(void);//使能看门狗: 写0xCCCC到KR
      FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);//状态:重装载/预分频 更新
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • 独立看门狗操作步骤
      1.取消寄存器写保护:IWDG_WriteAccessCmd();
      2.设置独立看门狗的预分频系数,确定时钟:IWDG_SetPrescaler();
      3.设置看门狗重装载值,确定溢出时间:IWDG_SetReload();
      4.使能看门狗:IWDG_Enable();
      5.应用程序喂狗:IWDG_ReloadCounter();
    • iwdg.c 独立看门狗程序设计
      //初始化独立看门狗
      //prer:	分频数:0~7(只有低3位有效!)
      //分频因子=4*2^prer.但最大值只能是256!
      //rlr:重装载寄存器值:低11位有效.
      //时间计算(大概):Tout=((4*2^prer)*rlr)/40 (ms).
      void IWDG_Init(u8 prer,u16 rlr) 
      {	
       	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//使能对寄存器IWDG_PR和IWDG_RLR的写操作,取消写保护
      	
      	IWDG_SetPrescaler(prer);	//设置IWDG预分频值:设置IWDG预分频值为64
      	
      	IWDG_SetReload(rlr);		//设置IWDG重装载值
      	
      	IWDG_ReloadCounter();		//按照IWDG重装载寄存器的值重装载IWDG计数器   加载寄存器
      	
      	IWDG_Enable();																//使能看门狗
      }
      //喂独立看门狗
      void IWDG_Feed(void)
      {   
       	IWDG_ReloadCounter();			//重载计数值						   
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
    • 主函数设计
      int main(void)
      {	
      	delay_init();	    	 //延时函数初始化	
      	LED_Init();
      	KEY_Init();
      	delay_ms(1000);			//看得到灭
      	IWDG_Init(4,625);		//预分频数64, 重载值为625, 溢出时间为1s	   
      	LED1=0;					//点亮LED0
      	while(1)
      	{
      		//按键进行对独立看门狗喂狗
      		if(KEY_Scan()==KEY1_PRES)
      		{
      			IWDG_Feed();		//如果KEY1按下,则喂狗
      		}
      		delay_ms(10);
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

    窗口看门狗(WWDG)

    独立看门狗本质相关概念

    • 什么是窗口看门狗?
        窗口看门狗用于监测单片机程序运行时效是否精准,主要检测软件异常,一般用于需要精准检测程序运行时间的场合。
        窗口看门狗的本质是一个能产生系统复位信号提前唤醒中断的6位计数器。
      产生复位条件:

      1. 当递减计数器值从 0x40 减到 0x3F 时复位(即T6位跳变到0)

      2. 计数器的值大于 W[6:0] 值时喂狗会复位。

      产生中断条件: 当递减计数器等于 0x40 时可产生提前唤醒中断 (EWI)。
      在窗口期内重装载计数器的值,防止复位,也就是所谓的喂狗。

    • 窗口看门狗工作原理

    • WWDG框图

    • 控制寄存器

    • 配置寄存器

    • 状态寄存器

    • 超时时间计算

      1. Tout是WWDG超时时间(没喂狗)
      2. Fwwdg是WWDG的时钟源频率(最大36M)
      3. 4096是WWDG固定的预分频系数
      4. 2^WDGTB是WWDG_CFR寄存器设置的预分频系数值
      5. T[5:0]是WWDG计数器低6位,最多63

    窗口看门狗实验

    • 需求:
        开启窗口看门狗,计数器值设置为 0X7F ,窗口值设置为 0X5F ,预分频系数为 8 。程序启动时点亮 LED1 ,500ms 后熄灭。在提前唤醒中断服务函数进行喂狗,同时翻转 LED2 状态。

    CubeMX工程配置

    • 配置时钟及时钟树
      1. 采用外部高速晶振
      2. 时钟树配置
    • 窗口开门狗配置
      1. 开启窗口看门狗及参数设置
      2. 开启提前唤醒中断
    • LED灯配置(略)

    HAL库程序设计

    • main.c主函数设计
      int main(void)
      {
      	HAL_Init();
      	SystemClock_Config();
      	MX_GPIO_Init();
      	HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET);
      	HAL_Delay(500);
      	MX_WWDG_Init();		
      	while (1)
      	{
      		HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET);
      		HAL_Delay(500);
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    • 提前唤醒中断函数喂狗
       void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
      {
      		HAL_WWDG_Refresh(hwwdg);		//喂狗
      		HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5

    固件库程序设计

    • 窗口看门狗配置过程
      1.使能看门狗时钟:RCC_APB1PeriphClockCmd();
      2.设置分频系数:WWDG_SetPrescaler();
      3.设置窗口值:WWDG_SetWindowValue();
      4.开启提前唤醒中断并分组(可选):
      WWDG_EnableIT();
      NVIC_Init();
      5.使能看门狗:
      WWDG_Enable();
      6.喂狗:WWDG_SetCounter();
      7.编写终端服务函数:WWDG_IRQHandler();

    • wwdg.c 窗口看门狗程序设计

      //保存WWDG计数器的设置值,默认为最大. 
      u8 WWDG_CNT=0x7f; 
      //初始化窗口看门狗 	
      //tr   :T[6:0],计数器值 
      //wr   :W[6:0],窗口值 
      //fprer:分频系数(WDGTB),仅最低2位有效 
      //Fwwdg=PCLK1/(4096*2^fprer). 
       
      void WWDG_Init(u8 tr,u8 wr,u32 fprer)										//设置计数器初值、窗口值、预分频系数
      { 
      	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);	//WWDG时钟使能
       
      	WWDG_CNT=tr&WWDG_CNT; 			//初始化WWDG_CNT.  位运算:与
      	WWDG_SetPrescaler(fprer);		//设置IWDG预分频值
      	WWDG_SetWindowValue(wr);		//设置窗口值
      	WWDG_Enable(WWDG_CNT);			//使能看门狗 ,	设置 counter .           
      	WWDG_ClearFlag();				//清除提前唤醒中断标志位 
      	WWDG_NVIC_Init();				//初始化窗口看门狗 NVIC
      	WWDG_EnableIT(); 				//开启窗口看门狗中断
      } 
      //重设置WWDG计数器的值
      void WWDG_Set_Counter(u8 cnt)		//为了和寄存器保持一制,重新包装了一下
      {
          WWDG_Enable(cnt);//使能看门狗 ,	设置 counter .	 
      }
      //使能提前唤醒中断
      void WWDG_NVIC_Init()
      {
      	NVIC_InitTypeDef NVIC_InitStructure;
      	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;    			//WWDG中断
      	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占2,子优先级3,组2	
      	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	 		//抢占2,子优先级3,组2	
       	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; 
      	NVIC_Init(&NVIC_InitStructure);																//NVIC初始化
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
    • 主函数程序初始化

      int main(void)
      {	
      	delay_init();	    	 //延时函数初始化	
      	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
      	LED_Init();
      	LED1=0;							//点亮LED0
      	delay_ms(1000);	  
      	WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为7f,窗口寄存器为5f,分频数为8	
        	while(1)
      	{
      			LED1 = 1;
      			delay_ms(40);
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    • 提前唤醒中断服务函数

      void WWDG_IRQHandler(void)		//窗口看门狗 中断服务函数
      {
       
      	WWDG_SetCounter(WWDG_CNT);	//当禁掉此句后,窗口看门狗将产生复位
      	WWDG_ClearFlag();			//清除提前唤醒中断标志位
      	LED1=!LED1;					//LED状态翻转
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    独立看门狗与窗口看门狗的异同

    对比点独立看门狗窗口看门狗
    时钟源独立时钟,LSI (40KHz) ,不精确PCLK1或PCLK3,精确
    复位条件递减计数到0窗口期外喂狗或减到0x3F
    中断没有中断计数值减到0x40可产生中断
    递减计数器位数12位(最大计数范围:4096 ~ 0)7位(最大计数范围:127~63)
    应用场合防止程序跑飞,死循环,死机检测程序时效,防止软件异常
  • 相关阅读:
    2022年金九银十,秋招Java后端开发最全面试攻略,卷对方向,才拿得到心仪的大厂offer
    【Java 进阶篇】JDBC Statement:执行 SQL 语句的重要接口
    mysql 用户控制命令
    提前实现盈利的快手还有多少成长空间?
    PHP通过sql生成CSV文件并下载,PHP实现文件下载
    vue的第2篇 开发环境vscode的安装以及创建项目空间
    物联网基础建设-园区智能微电网设计方案
    【JavaSE】关于多态那些事儿
    OSN 1800 I 增强型华为多业务光传送设备
    9.17-数值分析
  • 原文地址:https://blog.csdn.net/weixin_46216674/article/details/132906313