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

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

上一期文章,我们讲了基于STM32的抗干扰方法:增加硬件失效时软件复位及看门狗功能。这期我们将介绍基于CW32 的抗干扰问题。
在1、2期文章和视频,为了公平起见,所有的MCU使用的是同一个工程程序,(不同的MCU,时钟和GPIO的配置略有不同,使用宏定义区分MCU),除了使用滴答时钟和基本GPIO操作外,没有任何抗干扰手段,全靠MCU内部自身的抗干扰能力进行的测试。结果,只有芯源CW32 MCU没有彻底死机外,其它均有死机现象。
这种死机现象,在我们实际开发产品时,是禁止发生的。为了对付这种干扰,除了硬件上有些技术对策,那软件上又有些什么呢?
当然是我们最熟悉的看门狗了。“看门狗”这个神器在“古老的年代”51时期,那是没有的,需要在外面加一个“昂贵”的芯片来实现。当然,现在新时代,所有的ARM MCU基本上都标配了看门狗外设。
CW32在抗干扰测试时,也偶有自身复位现象。当然如果我们增加了看门狗抗干扰技术,那设计出来的产品不是更稳定吗!
看门狗是啥呢,我们来看一下,CW32芯片的用户手册,关于看门狗的介绍。
这里我们就不详细展开其内容了。直接来看核心代码:


  1. //系统时钟配置为48M HSI倍数
  2. #include "main.h"
  3. #include "cw32f030_gpio.h"

  4. //GPIOA端口
  5. #define SEGA GPIO_PIN_10
  6. #define SEGB GPIO_PIN_9
  7. #define SEGC GPIO_PIN_8

  8. //GPIOB端口
  9. #define SEGD GPIO_PIN_14
  10. #define SEGE GPIO_PIN_15

  11. //GPIOA端口
  12. #define SEGF GPIO_PIN_11
  13. #define SEGG GPIO_PIN_12

  14. //GPIOB端口
  15. #define SEGDP GPIO_PIN_13

  16. //num:需要显示的数字,no:0显示左边数码管,1显示右边数码管
  17. void SEG_DisplayNum(unsigned int num, unsigned int no)
  18. {
  19.     GPIO_WritePin(CW_GPIOA,0xffff,GPIO_Pin_RESET);//关段码、位码
  20.     GPIO_WritePin(CW_GPIOB,0xffff,GPIO_Pin_RESET);//

  21. switch(num) //开断码
  22.     {
  23. case 0: //ABCDEF
  24.             GPIO_WritePin(CW_GPIOA,SEGA|SEGB|SEGC|SEGF,GPIO_Pin_SET);
  25.             GPIO_WritePin(CW_GPIOB,SEGD|SEGE,GPIO_Pin_SET);
  26. break;        
  27. case 1: //BC
  28.             GPIO_WritePin(CW_GPIOA,SEGB|SEGC,GPIO_Pin_SET);
  29. break;        
  30. case 2: //ABDEG
  31.             GPIO_WritePin(CW_GPIOA,SEGA|SEGB|SEGG,GPIO_Pin_SET);
  32.             GPIO_WritePin(CW_GPIOB,SEGD|SEGE,GPIO_Pin_SET);
  33. break;        
  34. case 3: //ABCDG            
  35.             GPIO_WritePin(CW_GPIOA,SEGA|SEGB|SEGC|SEGG,GPIO_Pin_SET);
  36.             GPIO_WritePin(CW_GPIOB,SEGD,GPIO_Pin_SET);      
  37. break;
  38. case 4://BCFG
  39.              GPIO_WritePin(CW_GPIOA,SEGF|SEGB|SEGC|SEGG,GPIO_Pin_SET);         
  40. break;
  41. case 5://ACDFG
  42.             GPIO_WritePin(CW_GPIOA,SEGA|SEGC|SEGG|SEGF,GPIO_Pin_SET);
  43.             GPIO_WritePin(CW_GPIOB,SEGD,GPIO_Pin_SET);              
  44. break;
  45. case 6: //ACDEFG
  46.             GPIO_WritePin(CW_GPIOA,SEGA|SEGC|SEGG|SEGF,GPIO_Pin_SET);
  47.             GPIO_WritePin(CW_GPIOB,SEGD|SEGE,GPIO_Pin_SET);   
  48. break;
  49. case 7: //ABC
  50.             GPIO_WritePin(CW_GPIOA,SEGA|SEGB|SEGC,GPIO_Pin_SET);
  51. break;
  52. case 8: //ABCDEFG
  53.             GPIO_WritePin(CW_GPIOA,SEGA|SEGB|SEGC|SEGG|SEGF,GPIO_Pin_SET);
  54.             GPIO_WritePin(CW_GPIOB,SEGD|SEGE,GPIO_Pin_SET);
  55. break;
  56. case 9: //ABCDFG
  57.             GPIO_WritePin(CW_GPIOA,SEGA|SEGB|SEGC|SEGG|SEGF,GPIO_Pin_SET);
  58.             GPIO_WritePin(CW_GPIOB,SEGD,GPIO_Pin_SET);
  59. break;
  60. case 10: //DP 显示DP  
  61.            GPIO_WritePin(CW_GPIOB,SEGDP,GPIO_Pin_SET);
  62. break;
  63. default:
  64. break;         
  65.     }
  66. if(no==1)
  67.         PB12_SETHIGH();//开位码
  68. else
  69.         PB11_SETHIGH();//开位码
  70. }

  71. void RCC_Configuration(void)
  72. {
  73. /* 0. HSI使能并校准 */
  74.   RCC_HSI_Enable(RCC_HSIOSC_DIV6);

  75. /* 1. 设置HCLK和PCLK的分频系数*/
  76.   RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
  77.   RCC_PCLKPRS_Config(RCC_PCLK_DIV1);

  78. /* 2. 使能PLL,通过PLL倍频到64MHz */
  79.   RCC_PLL_Enable(RCC_PLLSOURCE_HSI, 8000000, 6);     // HSI 默认输出频率8MHz

  80.   __RCC_FLASH_CLK_ENABLE();
  81.   FLASH_SetLatency(FLASH_Latency_3);   

  82. /* 3. 时钟切换到PLL */
  83.   RCC_SysClk_Switch(RCC_SYSCLKSRC_PLL);
  84.   RCC_SystemCoreClockUpdate(48000000);  
  85. }


  86. void GPIOInit(void)
  87. {  
  88.   GPIO_InitTypeDef GPIO_InitStruct;

  89.   __RCC_GPIOB_CLK_ENABLE();
  90.   __RCC_GPIOA_CLK_ENABLE();

  91. //数码管断码位码 IO初始化
  92.   GPIO_InitStruct.IT = GPIO_IT_NONE; //LED1
  93.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  94.   GPIO_InitStruct.Pins = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  95.   GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  96.   GPIO_Init(CW_GPIOA, &GPIO_InitStruct);  

  97.   GPIO_InitStruct.Pins = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  98.   GPIO_Init(CW_GPIOB, &GPIO_InitStruct);   
  99. }


  100. int main()
  101. {
  102. unsigned long i;
  103. unsigned int num=0;

  104.   IWDT_InitTypeDef IWDT_InitStruct = {0};  

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

  106.   RCC_Configuration(); //时钟配置
  107.   GPIOInit();           //数码管GPIO初始化

  108. //使用独立看门狗功能   
  109.   CW_SYSCTRL->APBEN1_f.IWDT = 1U;    //使能IWDT模块
  110.   IWDT_InitStruct.IWDT_ITState = ENABLE;
  111.   IWDT_InitStruct.IWDT_OverFlowAction = IWDT_OVERFLOW_ACTION_INT;   //溢出后产生中断不复位
  112.   IWDT_InitStruct.IWDT_Pause = IWDT_SLEEP_PAUSE;
  113.   IWDT_InitStruct.IWDT_Prescaler = IWDT_Prescaler_DIV4;
  114.   IWDT_InitStruct.IWDT_ReloadValue = (IWDT_FREQ >> 2) / 1000 * 280 - 1;  // 由于IWDT的时钟为RC10K, 设置为280实际溢出时间为256ms左右
  115.   IWDT_InitStruct.IWDT_WindowValue = 0xFFF;
  116.   IWDT_Init(&IWDT_InitStruct);
  117.   IWDT_Cmd();

  118.   __disable_irq();
  119.   NVIC_EnableIRQ(WDT_IRQn);
  120.   __enable_irq();  


  121. while(1)
  122.   {
  123.       num++; //一个循环,数据加1
  124. if(num>=100)num=0; //限数0-99

  125.       SEG_DisplayNum(num/10,0);  //显示数据十位
  126. for(i=0;i<60000;i++);   //延时

  127.       SEG_DisplayNum(num%10,1);  //显示数据个位
  128. for(i=0;i<60000;i++);   //延时
  129.        IWDT_Refresh();  //喂狗

  130.       SEG_DisplayNum(num/10,0);  //显示数据十位
  131. for(i=0;i<60000;i++);   //延时   
  132.       IWDT_Refresh();  //喂狗

  133.       SEG_DisplayNum(num%10,1);  //显示数据个位
  134. for(i=0;i<60000;i++);   //延时


  135.       SEG_DisplayNum(num/10,0);    //显示数据十位  
  136. for(i=0;i<60000;i++);   //延时
  137.       IWDT_Refresh();  //喂狗

  138.       SEG_DisplayNum(num%10,1);  //显示数据个位
  139. for(i=0;i<60000;i++);   //延时
  140.       IWDT_Refresh(); //喂狗
  141.   }
  142. }

  143. //CW32看门狗中断函数
  144. void WDT_IRQHandler(void)
  145. {
  146. unsigned int j;

  147. if(CW_IWDT->SR & IWDT_SR_OV_Msk)
  148.   { //独立看门狗溢出发生   
  149.     IWDT_ClearOVFlag(); /*清除标志 */

  150. while (1)
  151.     {
  152.         SEG_DisplayNum(10,1); //显示右测数码管的小数点位

  153. for(j=0;j<60000;j++);
  154. for(j=0;j<60000;j++);
  155. for(j=0;j<60000;j++);
  156. for(j=0;j<60000;j++);
  157. for(j=0;j<60000;j++);
  158. for(j=0;j<60000;j++);

  159.         __NVIC_SystemReset();  //软件复位,系统重新运行。
  160.     }
  161.   }
  162. }
这里的代码与1、2期代码不同,我们使用官方标准库来重新编写。其中数码管的动态扫描没有使用滴答时钟,而是在主程序中直接用延时来完成。区别于之前的代码,我们增加了独立看门狗的功能。看门狗的喂狗操作在MAIN函数的大循环里,数码管的动态扫描中实现。
当程序发生死机时,MAIN函数的大循环将暂停运行,数码管随机显示最近一次数值,不进行动态扫描,所以,只有一位数码管显示。同时,喂狗暂停。
看门狗的代码配置为产生中断不复位。与STM32不同,看门狗可以停止复位,先进中断。因此,当看门狗时间到,进入看门狗中断函数WDT_IRQHandler()中,在中断函数中,将右则数码管小数点显示出来,并进行软件复位。这样通过小数点显示再判断看门狗事件的发生。
除了看门狗复位,还有一种软件复位方式。当MCU发生硬件失效时,会进入Hardfault中数函数。Hardfault是优先级别为-1的固定类型中断,无需初始化设置。常常在MCU死机时,不知明的会进入Hardfault中断。因此,在Hardfault中断函数中,添加软件复位功能也是一种防死机现象的方法。
Hardfault中断函数中代码如下
  1. void HardFault_Handler(void)
  2. {
  3.   /* USER CODE BEGIN HardFault_IRQn */

  4.     unsigned int j;
  5.   /* USER CODE END HardFault_IRQn */
  6.   while (1)
  7.   {
  8.     /* USER CODE BEGIN W1_HardFault_IRQn */
  9.     while (1)
  10.     {
  11.         SEG_DisplayNum(10,0);
  12.         for(j=0;j<60000;j++);
  13.         for(j=0;j<60000;j++);
  14.         for(j=0;j<60000;j++);
  15.         for(j=0;j<60000;j++);
  16.         for(j=0;j<60000;j++);
  17.         for(j=0;j<60000;j++);

  18.         __NVIC_SystemReset();
  19.     }
  20.     /* USER CODE END W1_HardFault_IRQn */
  21.   }
  22. }
点击链接即可观看视频及讲解:
“看门狗”VS“打狗棒”,谁胜谁负?(CW32篇)
(CW32篇)程序讲解

这就是CW32关于看门狗的一个介绍。
CW32芯片本身在内部设计的时候充分考虑了各种ESD抗干扰手段,所以即使软件上不加任何软件抗干扰处理,它自身已经有比较强的抗干扰能力了。然后,所以我们做实验的结果,没有STM32那么明显,就是加看门狗和不加看门狗都没那么明显,它本身就可以扛得住各种干扰了。
但是,一个规范性的程序,一个可靠性的软硬设计都非常重要。建议用户在产品开发的时候,还是应该把看门狗功能加上去。因为外面可能有雷击,有各种电网的波动,各种意外。那么当意外发生的时候,MCU不能死机,但可以复位,可以重新运行,不能死锁。所以我们要养成良好的编程习惯,养成良好的产品设计思维,要把我们抗干扰这个手段加上去,这也是我们给大家一直来做这个抗干扰实验的一个目的和意义所在。




本帖子中包含更多资源

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

×
hzl123456 发表于 2023-3-1 15:31 | 显示全部楼层
这个好,怎么加粉丝群?
归去来兮979797 发表于 2023-3-10 18:24 来自手机 | 显示全部楼层
YYDScw32
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

17

帖子

1

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