单片机是一种智能型器件,它的运行是依照制作者根据具体场合的需要而预先设置好的程序进行的。因此可以说单片机的运行是“智能”的,同时也是“机械”的。它虽然能“理解”人的意志而运行,但也仅仅只是依人的意志“按部就班”地机械地运行,不会辨别人为的过失,更不会绕道避免人为的错误。所以,要使单片机运行在预先计划的理想状态,务必使编写的程序不得有任何的差错。然而在编写过程中“人非圣贤,孰能无过”,其中,单片机内存资源的冲突就是一类常有的过失。尤其是用汇编语言编写的程序。下面列举两例加以介绍。
最高温度出乱
笔者所在公司生产的干式变压器上配套使用的智能温控仪是我们自行研制开发的。温控仪与风机等配合主要用来检测控制变压器A、B、C三相绕组的温升,其中有一个功能,按一下相关的按钮,温控仪会显示当前A、B、C三相中之最高温度。最高温度显示处理中有这么一段小程序:
Handle:CLR C;清零进位位
C,为下面进行比较作准备
MOV A,31H;31H单元是A相
温度寄存器
SUBB A,32H;32H单元是B相
温度寄存器
JC H1
MOV A,31H
SUBB A,33H;33H单元是C相
温度寄存器
JC H2
MOV 51H,#0AH;将相序参量
存入51H单元
MOV 3FH,31H;将比较得到的
最高温度暂存3FH单元
LJMP H0
H1:MOV A,32H
SUBB A,33H
JC H2
MOV 51H
MOV 3FH,32H
LJMP H0
H2:MOV 51H
MOV 3FH,33H
H0:RET
这段处理程序主要是将从变压器A、B、C三相绕组读入的、暂存到31H、32H、33H三个内存单元的温度数据进行比较,并将比较得到的最高者及其相序标志分别另存到内存3FH、51H单元中,以供显示当前最高温度。起初,程序运行后最高温度显示的结果往往并非三相中的最高者,几经检查后发现,原来当时在编写这段小程序时由于“笔误”,把小程序的第三条指令(SUBB A,32H)中的“32H”错打成了“32”(漏了一个“H”字符),也就是将单片机内存中第32H单元寄存器错当成了第32单元寄存器。而这十进制“32”相当于十六进制“20H”,即本想调用32H单元中的数据来进行比较,事实上调用的却是20H单元中的数据,而在系统程序中20H单元已被别处所用,它寄存的是一组状态量而不是温度数据,这样比较获得的“最高温度”自然不会是理想的结果了,也就是内存资源32H单元与20H单元混淆而冲突了。
数码显示混乱甚至死机
笔者在搞35kV变压器车间温湿度无线采集监控系统时曾碰到过这样一个问题:平时温湿度采集显示都很正常,然而一旦启动与上位机电脑进行串口通信时数码显示屏就会混乱闪烁,有时甚至会使单片机死机。
检查与串口通信相关的程序。从上到下地逐条查看未发现异常,检查显示的相关程序也未发现错处。然而当将串口通信部分的发送子程序与显示部分的发送子程序放在一起看时,发现两个子程序中都用上了工作寄存器R0。显示部分的发送子程序与串口通信部分的发送子程序分别如下:
XSEND:MOV A,Dsend;显示
部分发送子程序
MOV R0,#08H;小循环次数设置
XSEND:CLR SSclk
RRC A;带进位位右移
MOV SData,C;进位位之值赋
给输出端口
NOP
NOP
SETB
NOP
DJNZ R0, X
RET
RSEND:MOV 57H,#05H;串口
通信部分发送子程序
MOV 58H,#06H
MOV 59H,#0EEH
MOV 5AH,#0FFH
MOV 5BH,72H;地址码数据
MOV 5CH,60H;采温数据寄存器
MOV 5DH,61H;湿度数据寄存器
MOV R0, #57H;读取地址初
值设置
MOV R6,#07H;发送小循环次
数设置
RSEND1:M
MOV SBUF,A;发送一个字节
JNB TI,$;等待发送完毕
CLR TI
INC R0
DJNZ R6,R
RET
以上可以看出,两个子程序中都有一个工作寄存器R0,虽然R0在其中的作用并不一样 :在显示部分发送子程序中R0是限定子程序中的小循环次数的,一个字节8位数,循环8次;串口通信部分发送子程序中R0是预置子程序发送读数的起始地址用的。但是它们动用的是同一个工作寄存器R0,所以也就埋下了资源冲突的隐患。
扫描显示是在大循环中进行的,每一大循环要调用两次显示发送子程序,即发送两个字节的数据:一个是显示笔段数据串,一个是显示位码数据串。而串口通信发送子程序是接收了上位机电脑读数据命令后在串口中断服务程序中进行的。因而,在循环扫描显示调用发送子程序的运行当中(如果上位机有读取数据的要求),往往会被读取命令的中断服务程序所打断,当中断服务处理后返回到显示发送子程序的断口处时,串口通信部分发送子程序中的R0“地址”之值也被带回显示发送子程序的运行之中了,于是显示发送子程序的小循环不再是8次了。这样正常的大循环扫描显示被破坏,以致数码显示屏混乱闪烁,严重时还会使单片机死机。
问题小结
内存资源冲突必然会导致单片机运行的故障,而故障现象则因具体的内存单元的不同作用而各呈千秋。在单片机开发应用的调试过程中,有关内存资源冲突的问题是经常会碰到的,因为,除了在编写程序过程中的一些偶然的“笔误”外,还有其他方面的种种因素。比如由于年长月久,不少调试“成熟”的子程序段都保存下来了,一旦碰上类似的程序场合就随时会被“移植”调用。而这些被“移植”来的子程序段中的资源变量及内存单元,往往一不小心就会与当前程序中的内存资源发生冲突。因此在开发调试过程中,如果单片机的程序运行有故障时,别忘了检查系统程序是否存在内存资源冲突问题。
文/张春峰