6.1.5  中断系统应用实例分析

6.1.5 中断系统应用实例分析

下面对上述实例进行一些必要的分析,分析的重点是程序中的中断初始化语句,中断服务子程序入口地址的设置及中断服务子程序的结构。

1.中断应用程序结构分析

上述实例的参考程序由主程序、中断服务子程序、3个延时子程序及循环计数子程序组成,其相应关系是:

1)主程序在无限循环中不断调用2个延时子程序PO1B与PO19。

2)各个延时子程序对计数器赋值后调用循环计数子程序。

3)主程序响应外部中断INT1后执行中断服务子程序,而中断服务程序运行时调用延时子程序PO1A。

各程序模块具体组成语句情况如下。

(1)主程序组成语句分析

1)主程序的首地址为0190H,其标号是PO10,即在ROM中储存的主程序入口地址是PO10。注意,主程序的入口地址也就是整个应用程序的入口地址或称初始地址,当入口地址为0190H时,才能使整个程序正常运行起来。

2)主程序的末地址为01C9H,其对应语句为“SJMP PO12”,此语句作为主程序结尾语句时,使微机在标号PO12语句至结尾语句间无限循环,直到关机。

3)主程序以首地址0190H至末地址01C9H,共22条指令,其中包括有:6条调用工序定时子程序的指令“ACALL PO1B”;1条调用工序定时子程序的指令“ACALL PO19”。

(2)中断服务子程序组成语句分析

1)中断服务子程序首地址为01E7H,其标号是PO16。即在ROM中储存的中断服务子程序实际入口地址是PO16。

2)这里必须要注意将中断源入口地址与中断服务程序入口地址区分开来。如图6-16所示,外部中断978-7-111-46831-8-Chapter06-64.jpg的中断源入口地址固定为0013H,由表6-1可知,在这个入口地址以下,只有8个字节单元空着可用,为了使计算机能运行较长的中断服务程序,则必须在中断响应后使程序再从中断源入口地址转移到一个地方去开辟“新天地”,在这个“新天地”中,中断服务子程序的组成语句可远远超过8个字节单元,其首地址就是中断服务程序的实际入口地址。

3)中断服务子程序的结束语句必须是中断返回指令RETI,此指令的功能是将保存在堆栈中的断点地址弹入PC寄存器,使计算机返回主程序的断点处,继续正常工作过程。

4)中断服务程序从首地址01E7H到末地址0203H,共13条指令,其中包括有3条调用延时子程序的指令“ACALL PO1A”,即在中断服务程序中同样可以调用其他子程序,以简化程序结构。

978-7-111-46831-8-Chapter06-65.jpg

图6-16 程序的组成及工作关系示意图

(3)延时子程序组成语句分析

1)延时子程序A:

①首地址为0209H,其标号是PO1A,即其他程序采用ACALL PO1A指令就可调用此子程序。

②延时子程序A末地址为020DH,相应指令必定是RET。此指令的作用是结束本子程序运行,并将堆栈中的调子程序前PC当前值弹出送入PC寄存器,使计算机返回原来程序继续运行。

③子程序从首地址0209H到末地址020DH共3条指令。其中,第1条指令“PO1A:MOV R2,#10H”,是对计数器R2赋初值,为调用循环计数子程序作初始化工作;第2条是调用循环计数子程序的指令“ACALL DELY”。

2)延时子程序B:首地址020EH,末地址0212H,共3条指令。其他情况与延时子程序A相同。

3)延时子程序C:首地址0204H,末地址208H,共3条指令。其他情况与延时子程序A相同。

(4)循环计数子程序组成语句分析 首地址为0213H,其标号是“DELY”,即其他程序用“ACALL DELY”指令就可调用本指令。末地址0227H,末指令必为RET,这是子程序的约定。

共11条指令,组成四重循环倒计数,从外层到内层的四重循环入口分别是:DELY、DEL2、DEL3、DEL4,四重循环的倒计数指令是DJNZ R2指令。

2.中断应用程序工作过程分析

由图6-16可见,程序工作过程可分为程序正常工作过程与中断响应过程两种情况。

(1)程序正常工作过程 所谓程序正常工作过程是指不发生中断时程序工作的情况。此时,启动单片机后,CPU自动进入主程序依次进行以下工作。

1)对各工序进行初始化处理。由“PO10:MOV P1,#7FH”语句对并行接口P1的0至6脚设置低电平,相应的灯灭,模拟各工序处于停止的初始状态。

2)循环等待“开工”信号。由“PO11:JNB P3.4 PO11”语句读入开关S1状态,开关S1未合上时,P3接口寄存器的P3.4位单元为0,程序回跳至PO11,继续检查S1信号。

3)接到“开工”信号后,进行中断初始化处理

①在开关S1合上后,上述“PO11:JNB P3.4 PO11”语句执行,程序往下顺序执行。

②由逻辑运算语句“ORL IE,#84H”对中断允许寄存器IE的EA位(总开关)与EX1位(外中断1)写入1,开通INT1外中断源信号输入电路。

4)按预定节拍循环运行工序1至工序7作为模拟实验,程序在这个阶段的工作是依次使P1接口的引脚P1.0至P1.6输出预定时间的低电平,相应的发光二极管LED灯亮,表明工序顺序运行。

①由语句“PO12:MOV P1,#7EH”将P1接口寄存器的最低位P1.0置0(其余位为1),相应的引脚P1.0输出低电平。其他引脚置低电平的情况也相同。请注意,在单片机中二进制的0与1相应于电路中的低电平与高电平,所以当P1接口寄存器的各位依次为0时,就可使相应的引脚输出低电平。

②由ACALL语句调用延时子程序,即程序转入子程序。

③在延时子程序中,由“PO1B:MOV R2,#data”立即寻址传送指令设定计数器R2的初始值,然后由“ACALL DELY”指令调用计数子程序,进行四重循环倒计数延时过程。

5)由语句“SJMP PO12”使PC当前值变为标号PO12地址值01A5H,则程序重新执行步骤4)工作。

注意,由于本语句是使程序无条件回跳到PO12处,故本程序将在这段程序中无限循环下去。

请考虑一下,如果要使开关S1能控制程序的循环时间,该如何修改本语句。

程序无中断发生时工作过程示意如图6-17所示。由图可见,PC值的变化表明了程序的工作流程。

(2)程序中断响应过程 当开关S2合上时,外中断源978-7-111-46831-8-Chapter06-66.jpg(引脚P3.3)高电平,由于在程序正常运行过程中主程序中已对IE寄存器进行开中断初始化,允许响应INT1中断请求,则程序立即转入中断响应过程。图6-18所示是程序中断响应工作过程示意图,中断过程可分为以下三步。

978-7-111-46831-8-Chapter06-67.jpg

图6-17 程序无中断发生时工作过程示意图

978-7-111-46831-8-Chapter06-68.jpg

图6-18 程序中断响应工作过程示意图

1)中断响应。

①PC当前值被中断系统电路自动压入堆栈。

978-7-111-46831-8-Chapter06-69.jpg中断入口地址0013H被中断系统电路自动装入PC寄存器,程序下一条执行转为0013H ROM单元中存放的“LJMP P106”指令。

③CPU执行“LJMP PO16”无条件转移指令,PC当前值被变为中断服务程序的入口地址01E7H,即PC←01E7H,程序进入中断服务子程序。

2)运行中断服务程序:

①语句“PO16:MOV B,R2”用来将循环计数子程序的重要参数R2暂存到寄存器B中保护起来,以便中断结束后,继续使用,即恢复现场。这里考虑一下,为什么要保护计数器R2,而不保护累加器A或其他寄存器的值呢?

②中断服务程序主体为二重循环,如图6-19所示。其中:

PO17为外循环体入口标号地址;

PO18为内循环体入口标号地址;

01F7H处的语句“DJNZ 20H,PO18”为内循环控制语句;

01FEH处的语句“JNB P3.3,PO17”为外循环控制语句。

978-7-111-46831-8-Chapter06-70.jpg

图6-19 中断服务程序主体的二重循环结构

二重循环程序的作用是使P1.7引脚输出方波振荡信号,相应的扬声器发出警报声。改变内循体计数器20H的初始化值,就可改变振荡频率,从而改变警报声的音调。

3)中断返回。

①语句0201处“MOV R2,B”用以在中断返回前将保存在寄存器B中的参数送回计数器R2。

②结束语句RETI使堆栈中保存的断点地址弹出给PC,程序从断点处进行正常运行。

这里有一个问题:若中断源提出中断请求,使相应标志位置位,而且对应的允许控制位及EA都置位,CPU是否会马上响应中断请求?

答:不会,必须满足下列条件才可立即响应:

①无同级或高级中断正在服务。

②检测到有中断请求到来的机器周期是当前正在执行指令的最后一个机器周期,这样可保证当前指令的完整执行。

③当前指令是访问IE、IP寄存器指令或RETI指令,必须执行完该指令并再继续执行一条指令,才响应中断。

3.中断应用程序设计要点

通过上述分析,我们已了解中断初始化语句、中断入口地址转移语句、中断服务子程序的结构语句等重要语句的作用与相互配合关系。下面,再来总结一下这些语句的使用要点与设计技巧。

(1)中断初始化语句MCS-51系列单片机中断系统的初始化语句较简单,如实例中只有两条语句:

0199H处语句ORL IE,#84H

019CH处语句ORL IP,#04H

1)作用:第一条语句的作用是将中断允许寄存器IE中的总开关位EA与外中断1位EX1置1,其他各位保持不变(单片机复位后IE=0×000000B),即允许中断源978-7-111-46831-8-Chapter06-71.jpg申请中断,如图6-20a所示。第二条语句的作用是将中断优先级寄存器IP中的外中断1位PX1置1,其他位保持不变(复位后IP=××000000B),即978-7-111-46831-8-Chapter06-72.jpg为高优先级中断源,如图6-20b所示。

请注意,这里虽然采用的是逻辑或指令ORL,执行效果与内部立即数传送指令MOV相同,但工作过程比较复杂。中断初始化指令工作过程如图6-21所示。

例如:ORL IE,#84H的工作过程是:

①CPU将片内SFR区的IE寄存器中的数00H取出。

②再将片外ROM中019BH单元中的立即数#84H取出。

③两者逐位进行逻辑或运算。

④最后将结果送入IE。

“MOV IE,#84H”的工作过程只有取立即数#84H及送入IE两步,因而往往也使用MOV指令来设置IE、IP寄存器。

2)要点:

①单片机开机上电复位后,IE及IP各位被清零,中断应用程序必须按中断源情况对IE、IP寄存器设置初值。

②中断初始化程序语句一定要放在主程序中,如本实例程序放在开头的第1、2条位置是非常合理的。

③IE、IP寄存器可以位寻址,如图6-20所示,所以在程序中也可以用位操作指令来设置。如CLR AFH、SETB A4H、SETB AFH等,但是中断初始化时不如“MOV IE,#data”指令可一次设置各位更方便快捷。

3)讨论:本程序中只用1个中断源978-7-111-46831-8-Chapter06-73.jpg,为什么还要在中断初始化时设置IP寄存器?

答:在本实例中只用1个中断源时,确实不存在中断优先级排队的问题,可以去掉“ORL IP,#04H”语句。但作为教学实例,保持这条语句是为了使读者记住经常使用的中断初始化语句是这两句,以适应各种情况。

978-7-111-46831-8-Chapter06-74.jpg

图6-20 中断初始化语句作用

a)中断允许寄存器IE b)中断优先级寄存器IP

978-7-111-46831-8-Chapter06-75.jpg

图6-21 中断初始化指令工作过程

(2)中断入口地址转移语句 由于MCS-51系列单片机中断系统的5个中断源入口地址是固定的,见表6-1,此安排很紧凑,给每个中断源的服务程序只留下8个字节单元的可编程长度。所以较长的中断服务程序必须放在ROM的其他区,这时就要在中断响应后,将PC当前值从中断入口地址转移到实际中断服务程序的首地址。本实例中的978-7-111-46831-8-Chapter06-76.jpg中断入口地址转移语句是ROM中0013H单元处的“LJMP PO16”。

1)作用:CPU响应外中断978-7-111-46831-8-Chapter06-77.jpg时,将程序从978-7-111-46831-8-Chapter06-78.jpg中断源的固定入口0013H处转移到实际的中断服务程序首地址01E7H(标号PO16),如图6-16、图6-18所示。

“LJMP PO16”是无条件长转移指令,即标号PO16是16位地址并可以是64KBROM区中的任一单元地址。

执行此指令时的PC当前值=0013H+指令3字节长度=0016H。

执行此指令后的PC=标号PO16地址值=01E7H。

2)要点:

①必须记住MCS-51系列单片机中断系统5个中断源的固定入口地址,见表6-1,即这些入口地址是单片机在中断系统电路中自动确定的,是生产厂做好的“死地址”,是不可改变的安排。所以在选用不同的中断源时,就必须找到对应的中断服务程序入口地址,不得有误!如本例若改用外中断978-7-111-46831-8-Chapter06-79.jpg作为报警模拟信号输入端时,其引脚为P3.2,其中断服务程序入口地址为0003H,则中断入口地址转移语句就要写在ROM的0003H单元中,即ORG 0003H

000BH LJMP PO16否则,程序无法对978-7-111-46831-8-Chapter06-80.jpg中断进行响应。

②中断服务子程序长度不超过8字节,可直接写在中断入口地址后面的8个单元中,不必采用中断入口地址转移语句。这样可加快中断响应处理过程。

③中断入口地址转移指令目标地址采用某标号时,此标号代表的是实际中断服务程序首地址,则在编写中断服务子程序时,其首条语句必须是伪指令ORG,第二条语句必须用上述标号,以便“自认家门”。如在实例中的中断服务程序前两个语句为:

ORG 01E7H

PO16:MOV R2,B这样就能在汇编时给标号PO16赋具体值01E7H,使中断响应时PC当前值顺利转为实际服务程序入口地址01E7H。

(3)中断服务程序 中断服务程序由开头、主体、结尾三部分组成,结尾必须是RETI中断返回指令,主体随具体要求而定。

这里要强调的是,在开头部分必须对程序使用的各种变量数据进行压入堆栈保护等措施。本实例中断服务的开头语句是

PO16:MOV B,R2

1)作用:这是一条寄存器寻址内部传送指令,在一个机器周期内完成B←R2的过程,可快捷保存循环计数器指针R2的内容。

2)要点:

①为什么要保护R2的数据呢?请回顾一下图6-16反映的工作情况,不难看出中断发生时,很可能程序正处于循环计数子程序的工作过程,即R2计数器的值若丢失就会使得中断后,程序不能正常进行下去,这是保存R2的理由之一。

理由之二是,在中断服务程序主体部分也要调用延时子程序,后者又要调用循环计数子程序,则R2会被重新赋值,也就是说中断服务程序也要使用R2计数器,所以必须将原程序的R2值保存好以免混淆。

②为什么不保护A、PSW的数据呢?请读者仔细分析一下本实例中断服务程序中有何处在使用A与PSW寄存器呢?应该说没有,这样也就没有必要保护它们。所以请记住在中断服务程序开头语句的设计原则是:凡在中断服务程序主体与其他程序中都要使用的寄存器或内存单元都应予以保护。

③保护数据的方式中,更常用的是压入堆栈,送入内存单元等,如“PUSH ACC”“PUSH02H”“XCH A,direct”及“MOV direct,R2”等。但在退出中断服务程序前必须用相应的语句来恢复数据。如“POP ACC”“POP 02H”“XCH A,direct”及“MOV R2,direct”等。