[STM32] “看门狗”VS“打狗棒”,谁胜谁负?(STM32篇)——MCU抗干扰实验系列专题(3)

[复制链接]
1403|10
 楼主| MCU研究实验室 发表于 2023-1-18 00:20 | 显示全部楼层 |阅读模式
本帖最后由 MCU研究实验室 于 2023-2-2 14:13 编辑

后台有许多读者留言说先弄点干货。今天应读者要求,我们先来一篇干货。大家有什么要求,欢迎留言,关于MCU的应用、测试要求,我们都会尽量满足。
  在上两期文章和视频中,为了公平起见,所有的MCU使用的是同一个工程程序,(不同的MCU,时钟和GPIO的配置略有不同,使用宏定义区分MCU),除了使用滴答时钟和基本GPIO操作外,没有任何抗干扰手段,全靠MCU内部自身的抗干扰能力进行的测试。结果,只有芯源CW32MCU没有彻底死机外,其它均有死机现象。
这种死机现象,在我们实际开发产品时,是禁止发生的。为了对付这种干扰,除了硬件上有些技术对策,那软件上又有些什么呢?
当然是我们最熟悉的看门狗了。“看门狗”这个神器在“古老的年代”51时期,那是没有的,需要在外面加一个“昂贵”的芯片来实现。当然,现在新时代,所有的ARM MCU基本上都标配了看门狗外设。
看门狗是啥,我们来看一下,STM32芯片的用户手册,关于看门狗的介绍
这里我们就不详细展开其内容了。直接来看核心代码。
  1. //摘要:
  2. /*
  3. 系统时钟,使用内部高速HSI倍数,系统时钟为48M。
  4. */
  5. //Programed by Cache.Lee 2023.1.4

  6. #include "stm32f0xx.h"
  7. #include "stm32f0xx_gpio.h"

  8. //GPIOA
  9. #define SEGA GPIO_Pin_10
  10. #define SEGB GPIO_Pin_9
  11. #define SEGC GPIO_Pin_8

  12. //GPIOB
  13. #define SEGD GPIO_Pin_14
  14. #define SEGE GPIO_Pin_15

  15. //GPIOA
  16. #define SEGF GPIO_Pin_11
  17. #define SEGG GPIO_Pin_12

  18. //GPIOB
  19. #define SEGDP GPIO_Pin_13

  20. //num:需要显示的数字,no:0显示左边数码管,1显示右边数码管
  21. void SEG_DisplayNum(unsigned int num, unsigned int no)  
  22. {
  23.     GPIO_ResetBits(GPIOA,0xffff);//关段码、位码
  24.     GPIO_ResetBits(GPIOB,0xffff);//关段码、位码
  25.   
  26.     switch(num) //开段码
  27.     {
  28.         case 0: //ABCDEF
  29.             GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC|SEGF);
  30.             GPIO_SetBits(GPIOB,SEGD|SEGE);
  31.             break;        
  32.         case 1: //BC
  33.             GPIO_SetBits(GPIOA,SEGB|SEGC);
  34.             break;        
  35.         case 2: //ABDEG
  36.             GPIO_SetBits(GPIOA,SEGA|SEGB|SEGG);
  37.             GPIO_SetBits(GPIOB,SEGD|SEGE);
  38.             break;        
  39.         case 3: //ABCDG            
  40.             GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC|SEGG);
  41.             GPIO_SetBits(GPIOB,SEGD);      
  42.             break;
  43.         case 4://BCFG
  44.              GPIO_SetBits(GPIOA,SEGF|SEGB|SEGC|SEGG);         
  45.             break;
  46.         case 5://ACDFG
  47.             GPIO_SetBits(GPIOA,SEGA|SEGC|SEGG|SEGF);
  48.             GPIO_SetBits(GPIOB,SEGD);              
  49.             break;
  50.         case 6: //ACDEFG
  51.             GPIO_SetBits(GPIOA,SEGA|SEGC|SEGG|SEGF);
  52.             GPIO_SetBits(GPIOB,SEGD|SEGE);   
  53.             break;
  54.         case 7: //ABC
  55.             GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC);
  56.            break;
  57.         case 8: //ABCDEFG
  58.             GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC|SEGG|SEGF);
  59.             GPIO_SetBits(GPIOB,SEGD|SEGE);
  60.             break;
  61.         case 9: //ABCDFG
  62.             GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC|SEGG|SEGF);
  63.             GPIO_SetBits(GPIOB,SEGD);
  64.            break;
  65.         case 10: //DP 显示DP  
  66.            GPIO_SetBits(GPIOB,SEGDP);
  67.            break;
  68.         default:
  69.             break;         
  70.     }
  71.     if(no==1)
  72.        GPIO_SetBits(GPIOB,GPIO_Pin_12);
  73.     else
  74.        GPIO_SetBits(GPIOB,GPIO_Pin_11);//关位码
  75. }

  76. void GPIOInit(void)
  77. {
  78.   GPIO_InitTypeDef  GPIO_InitStructure;

  79.   //数码管断码位码 IO初始化
  80.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);   
  81.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

  82.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;
  83.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  84.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  85.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  86.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  87.   GPIO_Init(GPIOA, &GPIO_InitStructure);


  88.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
  89.   GPIO_Init(GPIOB, &GPIO_InitStructure);
  90. }


  91. int main(void)
  92. {
  93.   unsigned long i;
  94.   unsigned int num=0;

  95.   for(i=0;i<60000;i++);   //上电延时
  96.   GPIOInit();  

  97.   /* IWDG timeout equal to 250 ms (the timeout may varies due to LSI frequency
  98.      dispersion) */
  99.   /* Enable write access to IWDG_PR and IWDG_RLR registers */
  100.   IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);

  101.   /* IWDG counter clock: LSI/32 */
  102.   IWDG_SetPrescaler(IWDG_Prescaler_32);

  103.   /* Set counter reload value to obtain 250ms IWDG TimeOut.
  104.      Counter Reload Value = 250ms/IWDG counter clock period
  105.                           = 250ms / (LSI/32)
  106.                           = 0.25s / (LsiFreq/32)
  107.                           = LsiFreq/(32 * 4)
  108.                           = LsiFreq/128
  109.    */
  110.   IWDG_SetReload(40000/128);
  111.   /* Reload IWDG counter */
  112.   IWDG_ReloadCounter();
  113.   /* Enable IWDG (the LSI oscillator will be enabled by hardware) */
  114.   IWDG_Enable();
  115.   SEG_DisplayNum(10,1);
  116.   for(i=0;i<60000;i++);  

  117.   while(1)
  118.   {


  119.      num++;
  120.      if(num>=100)num=0;
  121.       SEG_DisplayNum(num/10,0);
  122.       for(i=0;i<60000;i++);   //延时

  123.       SEG_DisplayNum(num%10,1);
  124.       for(i=0;i<60000;i++);   //延时

  125.       SEG_DisplayNum(num/10,0);
  126.       for(i=0;i<60000;i++);   //延时   
  127.       IWDG_ReloadCounter(); //喂狗

  128.       SEG_DisplayNum(num%10,1);
  129.       for(i=0;i<60000;i++);   //延时

  130.       SEG_DisplayNum(num/10,0);      
  131.       for(i=0;i<60000;i++);   //延时

  132.       SEG_DisplayNum(num%10,1);
  133.       for(i=0;i<60000;i++);   //延时
  134.       IWDG_ReloadCounter();  //喂狗
这里的代码与上期代码不同,我们使用官方标准库来重新编写。其中数码管的动态扫描没有使用滴答时钟,而是在主程序中直接用延时来完成。区别于之前的代码,我们增加了独立看门狗的功能。看门狗的喂狗操作在MAIN函数的大循环里,数码管的动态扫描中实现。
当程序发生死机时,MAIN函数的大循环将暂停运行,数码管随机显示最近一次数值,不进行动态扫描,所以,只有一位数码管显示。同时,喂狗暂停。当看门狗时间到,将发生看门狗复位操作,系统将重新复位运行。这样程序就实现了看门狗复位功能。
在实验中,由于打狗棒电压干扰的威力巨大,STM32芯片被打坏了几个引脚。驱动A、F、G的端口功能异常,而且芯片略烫,应该是引脚被打坏了。但不影响下载,其它位码显示正常。
除了看门狗复位,还有一种软件复位方式。当MCU发生硬件失效时,会进入Hardfault中数函数。Hardfault是优先级别为-1的固定类型中断,无需初始化设置。常常在MCU死机时,不知明的会进入Hardfault中断。因此,在Hardfault中断函数中,添加软件复位功能也是一种防死机现象的方法。
代码如下


  1. void HardFault_Handler(void)
  2. {
  3.   unsigned int j;
  4.   /* Go to infinite loop when Hard Fault exception occurs */
  5.   while (1)
  6.   {
  7.         SEG_DisplayNum(10,0);
  8.         for(j=0;j<60000;j++);
  9.         for(j=0;j<60000;j++);
  10.         for(j=0;j<60000;j++);
  11.         for(j=0;j<60000;j++);
  12.         for(j=0;j<60000;j++);
  13.         for(j=0;j<60000;j++);

  14.         NVIC_SystemReset();  
  15.   }
  16. }
接下来的两个视频,来对比,软件添加和不添加抗干扰手段的运行测试。
(点击蓝色文字即可跳转B站播放)

  • 没“狗”时,被一棒打死!——“看门狗”VS“打狗棒”(STM32篇
  • 有了看门的“狗”,不分胜负!——“看门狗”VS“打狗棒”(STM32篇)
如文章有不妥之处,还请各位指正。
下期我们将测试CW32芯片,精彩不容错过!










本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评论

@MCU研究实验室 :谢谢,暂时不需要,毕竟我对软件不懂。  发表于 2023-1-19 22:54
@MCU研究实验室 :楼主太客气了,能跟着楼主学习俺非常高兴,就是对程序一窍不通,看个热闹。  发表于 2023-1-19 22:32
@王栋春 :就只有一张图,就是您看到的这样,下面半截没显示不知道是个啥,应该是我修改之前未能显示的那张,不好意思,影响您的阅读体验,很抱歉  发表于 2023-1-19 22:27
@MCU研究实验室 :只显示了一半,楼主还是再修改一下。  发表于 2023-1-19 22:06
@王栋春 :我修改一下啊,稍等  发表于 2023-1-19 21:39
为何图一始终无法显示,楼主看一下。  发表于 2023-1-18 22:20
 楼主| MCU研究实验室 发表于 2023-1-19 21:39 | 显示全部楼层
我重新修改一下
steelen 发表于 2023-1-30 14:28 | 显示全部楼层
这样的实验可以吸引眼球
但实际应用价值有限
强干扰下,硬件看门狗也会挂的
软件抗干扰其实是个笑话
E=MC2U 发表于 2023-2-3 10:36 | 显示全部楼层
打铁还需自身硬
归去来兮979797 发表于 2023-3-10 11:41 来自手机 | 显示全部楼层
cw32mcu抗干扰能力真强
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

17

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部