关于硬件:
经验一:重视墨菲定理,不要忽略细节,保持敏感性!
经验二:异常死机,先查硬件。
经验三:电源!时钟!复位!
(1)重视墨菲定理,不要忽略细节,保持敏感性!
产品研发中如果出现异常,请不要忽略掉。要相信墨菲定理。疫情期间由于封控,设计的产品在公司长时间跑稳定性,突然有一天设备死机了,而且只有一台,由于是同事发现的,重启之后也就好了。当时也没找到原因,以为是电源接触不良的问题,就忽略了。后面批量生产铺出去后,种种问题慢慢的复现出来了。所以请保持对设计产品的敬畏之心,要有足够的敏感性,不要忽略这些细节,墨菲定理真的很可怕!
(2)异常死机,先查硬件
单片机莫名死机,软件问题? 硬件问题?或者叠加?
如果只纠结在软件上,可能会找不到根本原因,甚至会质疑自己的逻辑,甚至会出现“见鬼”这种问题。
但是,做设计的要始终相信无神论,万事都有原因!不要单纯的纠结在软件的异常,而忽略硬件上的不可靠。
其实软件问题一般来说,用一些设计手段可以规避,但是硬件问题颇为棘手,早找出来损失越小。
硬件是软件运行的基础,稳健的硬件是软件的基石!先排查一些更加常见且易查的硬件问题.,保持对问题的敏感度,很重要!
而这份敏感度就来源于你对整个系统的理解和把握。当然这份敏感度也是一种经验的积累。
(3)电源!时钟!复位
如果你新打样一个板子,发现不能正常工作。你首先要排查什么?当然:三件套 电源!时钟!复位
也就是说,这三大件是硬件工作正常与否的基石。在面对偶发性问题的时候,首先排除硬件上的不可靠. 切记!切记!切记!
电源问题:
对于电源问题引起的死机,在这么多年软件调试过程了至少有碰到过10次左右,特别是一些经验不是特别丰富的软件工程师们在开发的过程中很少去质疑硬件问题,所以一言不合就从嵌入式软件开始排查,同时也有许多硬件伙计觉得软件可以优化非常多的硬件问题。
所以,嵌入式软件没有一定经验的话,在调试硬件问题会比较难受,那么对于电源这块能量的核心,主要是电压、功率和稳定性等。
大部分芯片都会有一个稳定运行的电压范围,过高或者过低都有可能导致运行异常,注意是可能,不是一定,甚至同一个型号,不同批次的芯片都有所差异~
所以功率不够,电压过低会导致芯片内外供电不够,使得相应模块、外设运行异常,最终程序死机、跑飞是经常发生的。特别是整个系统的功率需求并不是特别稳定,且电源的设计并没有太多的余量,当出现比如动作继电器等等功耗较大的动作时,其电源就有可能出现不稳定状态,最终影响到芯片运行。
当然如果你是购买的劣质或者参数虚标的电源,就要更多的去测试和监控一下电源的稳定程度了。
所以我目前亲自开发的项目,在项目的设计评审初期,会要硬件多留一个MCU的AD采样电路用来实时采集供电电压等,软件内部做一些快速的电压保护或者故障侦测,以检测出大部分电源异常问题。
这里提供一个小技巧:如果你做的是工业产品,如果对成本不是很敏感的话,输入电源还是选择电源块吧。
复位电路干扰
相比电源问题会少一些,不过也遇到过几次,大部分都是板子刚打样回来上电调试的时候,MCU直接不运行的情况,大多都是复位电路中的电阻或者电容贴错了,虚焊了等等;如果是采用复位芯片的大多估计供电不足,选型有问题等等。
不过,有一次遇到是在PCB走线上,复位电路与功率部分挨得比较近导致MCU概率性复位,当然如果有使用外部看门狗的话就更需要排查一下了。
比如我遇到复旦微的单片机复位引脚就特别狗血,不能加电容也不能加硬件看门狗!
晶振失效或受干扰
晶振本身失效或者受干扰,一般MCU都会选择外部晶振,相比内部的会更加准确一些。
然而对于这个MCU的心脏也是有概率出问题的,之前有个项目采用定时测量时间,每次测量信号的误差都是忽大忽小,后来直接把捕获的信号用IO信号翻转出来与实际信号进行对比,发现并无差异,才定位到是计时这块的频率出了问题,最终定位外部晶振电路存在干扰,导致时钟频率发生变化,最终影响测量结果,如果干扰再大一些估计就跑飞宕机了。
对于当出现了一些死机或者计时不准的问题,不仅仅要看软件,也要从硬件晶振时钟这块进行排查,所以对于目前主流的一些MCU都会存在时钟频率输出的引脚,一方面是用来供外部进行内部时钟的监控,另外一个应用就是进行不同芯片之间时钟上的同步。
最后几小点
最后,静电问题说实在的在开发中真的是虚无缥缈的存在,曾经一个伙计徒手换芯片,10个芯片换上去,坏了一半,大概率是因为天气比较干燥,用手触碰了几下芯片,后来硬件人手准备一套装备~
同时在系统中与MCU没有隔离的IO口,通信等等都要做好保护,这些对外的接口会把静电、或者是浪涌电压等引入MCU内部,使得MCU内部逻辑混乱导致死机。
高速运行的MCU会受外界辐射等电磁干扰,做好一些屏蔽措施等。
总结起来就是:电源保有裕量,稳定可靠。复位和时钟这种关键信号,在其EMC设计上给予一些关注。
关于软件:
经验一:数组越界/溢出
经验二:中断服务程序缺失
经验三:看门狗复位**
(1) 数组越界/溢出
现象:单片机程序在函数中运行时,总是在运行到函数末尾,要跳出函数时,程序跑飞。
原因:
数组越界(数组溢出),函数中定义的数组元素的个数小于程序中实际使用的数组元素的个数,例如在函数中定义了一个数组ucDataBuff[10],这个数组只有10个元素,但是在函数中却有这样的语句ucDataBuff[10]=0x1a,这个语句是给数组的第11个元素赋值,:由于定义的数组只有10个元素,从而导致赋值语句中不知道把0x1a放到什么地方,从而导致程序跑飞。
解决方法:
如果在调试程序时,发现程序总是在函数执行完毕时跑飞,多数情况是发生了数组越界(数组溢出)的错误,仔细检查函数中调用的数组是否存在越界(溢出)的情况。
(2)中断服务程序缺失
现象:程序运行过程中总是跑飞。
原因:程序中打开了某个中断,但是却没有相应的中断服务程序,从而导致在中断发生后,找不到中断服务程序入口,从而导致程序跑飞。
解决方法:检查程序中是否存在打开了某个中断,但是没有相对应的中断服务程序。
(3)看门狗复位
现象:在执行一段较为耗费时间的程序时,程序跑飞,并且总是跳到复位位置处。
原因:程序中使用了看门狗,但是没有及时“喂狗”,从而导致看门狗复位,使程序直接跳到复位位置。
解决方法:根据程序运行时间,尤其是一定要计算清楚最耗时的那段程序的运行时间,然后准确设置看门狗的复位时长,定时“喂狗”,尤其是如果有死循环的情况,一定要在死循环中记得“喂狗”。
硬件层的应对策略:
外加硬件看门狗:
常用的硬件看门狗芯片:(待完善)
TLP5010 定时器看门狗,最大基数2个小时。
其他:带电压监控功能:
软件层的应对策略:
软件看门狗:https://baijiahao.baidu.com/s?id=1721287986080215172&wfr=spider&for=pc
STM32F10xxx内置两个看门狗,(独立看门狗和窗口看门狗)可用来检测和解决由软件错误引起的故障;当计数器达到给定的超时值时,触发一个中断(仅适用于窗口型看门狗)或产生系统复位。
独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。
窗口看门狗,之所以称为窗口是因为其喂狗时间是一个有上下限的范围(窗口),喂狗的时间不能过早也不能过晚。
(1)多任务环境中如何喂狗
假设系统中有4个任务,DefaultTask、Task01、Task02、Task03。我们先建立一个全局变量dog_flag用于存储各个任务的喂狗状态;在前3个任务的主循环中,把dog_flag对应的bit位置位,DefaultTask置位bit0、Task01置位bit1、Task02置位bit2;在最后的Task03任务中,循环检查是否所有在使用的bit位都被置位,如果都被置位,则说明其他所有的任务的主循环都在正常运行,那么可以喂狗;同时最后要将dog_flag清零,以用于下一次监测置位。
(后记:,这段代码原先有点问题,对于dog_flag这个变量的读写,在多任务环境下是有可能冲突的,所以在访问它时,要当作临界段处理)
(2)事件标志组应用于多任务喂狗
在大部分的RTOS中,有一种更优雅的实现方式,那就是利用事件标准组。
我们之前讲freeRTOS的时候,在事件标志组相关的章节提到过,在事件标准组的变量中,每个bit位表示了一个事件,正好相对于这里我们用于监测各个任务主循环是否执行到的bit位。同时,事件标志组可以通知其他任务,我们可以利用这个特性,在喂狗的任务中等待其他所有任务的发送的事件标志,如果全都等到了,就喂狗并清除事件。
以freeRTOS环境为例,示例如下:
要注意一下,使用事件标志组时,由于要等到所有的事件后,才能向后执行完一个循环,所以,一般建议单独建立一个任务用于喂狗,这个任务中不再执行其他操作。