14 关于单片机死机的一些问题

2019-04-15 12:11发布

博主在最近的一个项目中测试系统的高低温实验,结果意外的发现经过高低温实验后(80℃到-20摄氏度)单片机有些已经死机了,所以不得不着手研究一下这个问题,在网上查阅资料后,基本上可以归结于以下几个问题: 1. 意外中断。是否打开了某个中断,但是没有响应和清除中端标志,导致程序一直进入中断,造成死机假象   2. 中断变量处理不妥。若定义某些会在中断中修改的全局变量,这时要注意两个问题:首先为了防止编译器优化中断变量,要在这些变量定义时前加volatile,其次在主循环中读取中断变量前应该首先关闭全局中断,防止读到一半被中断给修改了,读完之后再打开全局中断;否则出现造成数据乱套。
   3. 地址溢出,常见错误为指针操作错误。我要着重说的是数组下标使用循环函数中循环变量,如果循环变量没控制好则会出现数组下标越界,意外修改系统的寄存器造成死机,这种情况下如果死机说明运气好,否则后面不知道发生什么头疼的事。
   4. 无条件的死循环;比如使用while(x);等待电平变化,正常情况下x都会变成0,就怕万一,因此最好加上时间限制;
   5. 看门狗没有关闭。有的单片机即使没使用看门狗开机时也有可能意外自动开启了最小周期的看门狗,导致软件不断复位,造成死机,这个要看芯片手册,最好在程序复位后首先应该显式清除看门狗再关闭看门狗;   6. 堆栈溢出。最难查找的问题,对于容量小的单片机,尽量减少函数调用层级,减少局部变量,从而减少压栈的时候所需的空间。当你把以上几条都试过不能解决问题,试一试把你的被调用少函数直接内置到调用的地方并且把占用RAM大的局部变量改成全局变量,试一试说不定就可以了。 这个几个问题可以从代码编程风格上解决的大部分都能够解决,例如外部中断或者全局变量,还有一些事在中断函数中的递归比较繁琐。 如果在注意编程风格的前提下不能解决当前的问题,那么就要注意使用单片机自带的寄存器来监察异常状况。 在atmega8这款单片机中的MCUCSR寄存器来监察当前情况 MCU 控制和状态寄存器-
MCUCSR
MCU 控制和状态寄存器提供了有关引起MCU 复位的复位源的信息。
• Bit 7..4 – Res: 保留
这几位保留,读操作始终为"0”。
• Bit 3 – WDRF: 看门狗复位标志
看门狗复位发生时置位。上电复位将使其清零,也可以通过写”0” 来清除。
• Bit 2 – BORF: 掉电检测复位标志
掉电检测复位发生时置位。上电复位将使其清零,也可以通过写”0” 来清除。
• Bit 1 – EXTRF: 外部复位标志
外部复位发生时置位。上电复位将使其清零,也可以通过写”0” 来清除。
• Bit 0 – PORF: 上电复位标志
上电复位发生时置位。只能通过写”0” 来清除。
为了使用这些复位标志来识别复位条件,用户应该尽早读取此寄存器的数据,然后将其复位。如果在其他复位发生之前将此寄存器复位,则后续复位源可以通过检查复位标志来了解。 在目前的项目工作中,经过排查我们发现了主要原因是,当主程序死机时定时器却还在不停的计数,于是导致看门狗不能复位,所以导致了程序跑死的结果。 代码中我们可以这样进行改进: 主程序中我们可以声明一个变量看门狗的复位标志,然后在中断中进行判断:bit wdtflag=0; 在主程序中对其进行赋值: void main(void) { while(1) {   bit wdtflag=1;//每次进入while循环的时候将其置位
}
}
中断程序中进行判断 interrupt [TIM0_OVF] void timer0_ovf_isr(void) {
    if(wdtflag) //防止主程序死机而中断不死机
    {   
        wdtflag=0;
        #asm("wdr")   
    }  
} 这样就可以和主程序中的看门狗进行一个联系,防止主程序已经跑飞但是在中断函数中却不能复位的问题。