引言
随着微处理器的快速发展,其在工业领域中得到了越来越广泛的应用。但是由于工业现场的条件复杂,微处理器受到各种随机的干扰,常常使程序出现跑飞,给工业系统带来十分严重的损失。传统的微处理器系统是依靠看门狗电路使微处理器强行复位,重新开始执行程序来阻止程序跑飞的。但是在实际生产过程中,很多情况下是不允许程序重新执行的。另外,如果重新执行程序,将会使所有的寄存器全恢复到初始状态,所有端口清零,对事故现场造成严重破坏。所以在用户程序中,加入程序跑飞的恢复措施就显得尤为重要。要实现程序的较高质量恢复,不但要求有效地对程序进行监控,还要求在程序跑飞后能够有效地恢复,甚至某些情况下做到精确恢复。
1传统硬件复位的不足
传统的硬件恢复方法如图1所示。微处理器每隔一段时间给看门狗芯片(MAX706)一个输入脉冲,看门狗的RESET引脚保持在低电位,微处理器正常运行。当程序跑飞时,输入脉冲会消失,此时RESET引脚会变成高电平,微处理器被强行复位。

图1传统看门狗电路
微处理器在复位以后,所有参数均恢复到初始状态,程序重新执行,以前执行过的控制过程也将全部重新执行,严重影响了控制的安全性;并且由于数据没有被保存下来,无法检查故障发生的地点,不利于故障的处理。更为重要是,微处理器被强行复位后,所有端口在初始化时会被瞬间拉高。这样会造成许多物理设备误动作,很容易引发工业事故。用软件方法恢复程序,不会使微处理器复位,不但能够让程序继续执行,而且保留了现场数据,为故障处理提供了依据,有效地克服了用硬件复位造成的上述缺点。
2软件恢复方法
软件恢复微处理器程序可以分成两个部分: 一是对用户程序的监控,使其发生跑飞时被及时发现;二是对用户程序的恢复,即在跑飞发生后能够准确地找到程序跑飞地址并对其进行恢复,使程序能够从跑飞地点继续执行。下面对这两部分进行介绍。
2.1对用户程序的监控
用户程序无论长短,都是对控制功能的实现,因此可以把用户程序按功能分成相对独立的程序段。当一段程序跑飞后,只会影响到本段程序的寄存器状态,因此只要对程序进行分段监控,并且对本段程序进行恢复就可以了。这样不仅可以提高程序监控的实时性,而且可以提高程序恢复的准确性。
2.1.1对用户主程序的监控
(1) 对每段程序进行编码
对每段程序采用连续编码。编码可以用伪指令为每段程序加上一个标志,当程序进行恢复时,可以根据所加的编码找到程序的入口。例如第一个程序段命名为PROG01,第二段为PROG02,依此类推。注意,这里的编码是伪指令,仅仅为了方便使用,本身并不参加任何运算。
(2) 程序段状态寄存器与段码寄存器
程序段状态寄存器可以是一个字节也可以是一个标志位(为方便起见,本文用一个字节来说明问题),作用是标识当前程序是否执行完毕。在程序初始化时把寄存器清零,当一段程序执行完成后把寄存器置0FFH。
段码寄存器用来存储程序当前段码。与程序编码不同,程序段码是一个立即数,参与到程序运算当中,用来检测当前执行的程序段是否正确,并且在恢复程序中计算程序跑飞的地址。
(3) 参数备份寄存器
参数备份寄存器用来备份各种参数的数值,以便在恢复程序时能够很好地还原现场数据,以防止程序发生二次跑飞。一般每个参数都会有一个备份寄存器。
2.1.2对非程序区的监控
程序由于干扰可能会跑飞到未编程的RAM空间。对于这种情况,一般采用常规的软件冗余和软件陷阱技术。当程序跑飞到这一区域后, 均执行空操作指令, 因而不会引起误操作; 同时在该区域内每隔一段设置一个软件陷阱, 即加入一条跳转指令, 使程序直接跳转到恢复程序。下面通过流程图(图2)详细介绍程序的监控步骤。

图2用户程序流程图
① 用伪指令给每段程序编码。
② 检测程序是否按照预先的设计顺序执行,即检测上段程序的段码与段码寄存器中的值是否一致。如果不一致,则说明程序发生了向前或者隔段的跑飞,立即跳转至恢复程序。如果一致,则检测上段程序是否执行完毕,即检测上段程序段状态寄存器的值是否为0FFH。如果是,则说明上段程序执行完毕;否则,跳转至恢复程序。
③ 如果上段程序执行完毕,那么将本段程序段码写入段码寄存器。段码更新完成后就可以执行用户程序了。
④ 在执行用户程序的过程中,可以在程序中加入中间段码检测(包括本段段码检测和上段程序状态寄存器检测)。这样做的主要目的是为了防止程序跑飞时直接越过前面的检测措施直接进入程序段;同时记录中间检测的次数,以便在程序段结束时检测程序执行的完整性,以防止程序发生段内跑飞。
⑤ 在用户程序执行完毕后,还要对各参数寄存器进行备份,用于程序恢复时还原现场数据。
⑥ 将本段的程序段状态寄存器写入0FFH,标志本程序段执行完毕。
2.2对用户程序的恢复
当程序出现跑飞时,会自动跳转至恢复程序。如图3所示,恢复程序首先恢复现场数据,把备份的参数值写入各参数RAM中;然后要确定程序跑飞的地址,依次检测每个程序段的程序段状态寄存器,如果这个程序段完全执行完毕,则其程序段状态寄存器就会为0FFH,否则为00H。由于各程序段状态寄存器的地址是连续的,所以只要依次检测每个寄存器直到找到首个值为00H的寄存器,并且记录查找的个数,再利用基址加变址寻址跳转到相应的程序编码(程序入口处)。

图3恢复程序流程
程序示例:
…
LOOPCJNE@RI,#0FFH,JUMP
INCDPTR
INCA
JMPLOOP
…
JUMPJMP@A+PC
LJMPPROG01
LJMPPROG02
…
还有一种更为简单的方法,不需要查询程序段标志的值,只需知道段码寄存器的值就可以了,直接利用基址加变址转到相应的程序段进行恢复。
相比第一种算法,这种算法有很大的灵活性,程序段的编码和段码不一定要是连续的,只需段码和转入程序段入口的跳转语句一一对应。在程序编写过程中,有时要在两段程序之间插入新的程序段。如果按照第一种方法,则需依次修改插入程序段后各程序段的段码。在程序很长的情况下,这种修改工作量非常大。第二种方法则可以避免这种问题,但存在着不稳定性。当程序发生跑飞时,如果正好跳转到另一个程序段的段码更新语句,则无法进行正确的恢复。
2.3某些情况下的精确恢复
下面用一个例子来说明精确恢复算法。
一段程序要通过A、B、C三个阀门向图4中的容器注入3种液体。当从A阀门注入液体以后程序发生跑飞,直接跳转到从C阀门注入液体。按照前面的算法,恢复程序只能从程序段开始执行,因此还要把A阀门的液体重新注入一次。这样会导致容器内的3种液体比例发生变化。

图4三种液体注入容器
在这种情况下,可以给阀门设置一个动作标志寄存器(可以是一个标志位,也可以是一个字节)。在阀门动作后把寄存器置为0FFH。进入恢复程序以后,查询寄存器的值,如果为0FFH,则说明阀门动作已完成,可以跳过阀门打开语句继续执行。这样打开过的阀门就不会重复打开,从而保证容器内的液体比例不发生变化。注意: 在程序段的末尾把该寄存器清零;否则,下次执行时阀门不会动作。
按照本方法编写10段程序,在SONIX8P2700P实验平台上进行调试,对各种情况下的跑飞进行模拟。实验证明,此方法能够有效地发现跑飞并且恢复程序正常运行。
3总结
由于看门狗电路的硬件复位方法具有造成控制过程中断、现场数据丢失和设备误动作等不足,本文介绍了用软件恢复跑飞程序的方法,有效地克服了上述缺点。
将用户程序分块后,进行封闭式监控。通过在程序段入口处、执行中、执行完成后对各项参数的检测,能够有效地发现程序跑飞,并且及时进入恢复程序。通过对各种参数的及时备份,使得在执行恢复程序时能够很好地还原现场数据,使程序能够顺利执行,从而消除了因参数不对造成程序二次跑飞的可能。通过动作标志寄存器记录了物理设备的动作情况。使得在某些情况下可以实现程序的精确恢复,提高了程序的健壮性。