3.1调用子程序过程
主程序调用子程序过程应包括保护断点、跳至子程序首址、保护现场、子程序处理、恢复现场、恢复断点(子程序返回)6步。这六步都是用软件指令完成的。其中前两步保护断点和跳至子程序首址由调用指令CALL完成。保护断点其实就是把断点地址推入堆栈中保护起来,要注意的是保护的断点应是紧跟着调用指令的下一条指令地址,而不是调用指令本身地址,否则会引起重复调用“死循环”,这点必须提醒学生注意。LCALL与ACALL是MCS-51单片机的两条调用指令,分别称为长调用和绝对调用,两指令主要区别在于LCALL后面操作数直接就是16位二进制的子程序入口地址;而ACALL后面操作数只是11位二进制数,子程序入口地址是把这11位数作为低位地址,再加上ACALL的下一条指令地址(即断点地址)的高5位作为高位地址,从而形成16位的子程序入口地址。由此可知,两条调用指令的调用范围是不一样的,LCALL为64KB程序存贮器任何范围,而ACALL在高5位地址不变的同一页2KB范围内。
由于主程序与子程序可能会使用相同的寄存器和存贮单元存放数据,如果两者这些数据无关,那么子程序在使用这些相同寄存器和存贮单元之前,就必须先把主程序存放在这些区间里的数据现场保护起来,子程序在使用这些区间结束后,再把主程序现场恢复出来,以便子程序返回主程序后,主程序继续使用这些区间。现场保护与恢复一般采用堆栈推入PUSH指令与堆栈弹出POP指令实现,当然也可采用改变工作寄存器R0~R7区间指针等方法实现。子程序返回只需用RET指令就可把保护在堆栈中的断点恢复出来,继续执行主程序。
此外,主程序与子程序是密切联系的,它们之间存在着入口参数与出口参数传递问题,也就是主程序如何把输入参数传给子程序,子程序又如何把处理结果的输出参数带回给主程序,两者参数传递一般可采用寄存器或存贮单元、堆栈、数据指针等方法实现。
子程序再调用子程序叫做子程序嵌套,由于MCS-51单片机只能把内部RAM 00~7FH 128字节单元作为堆栈使用,断点地址保护到堆栈中需占2字节单元,所以子程序最多可能嵌套64级,当然实际使用中子程序嵌套一般2~3级,否则程序结构就显得太复杂了。
3.2 中断过程
中断过程远比调用子程序过程要复杂,它包括中断请求(或申请)、中断排队、中断响应、中断服务(或处理)和中断返回5大步。这5大步是由硬件和软件结合完成的。
中断请求由中断源向CPU提出。MCS-51单片机只有T/C0定时/计数器0溢出、T/C1定时/计数器1溢出、TXD/RXD串行口发送与接收一帧完、INT0外部中断0和INT1外部中断1等5个硬件中断源,其中前三个为内部中断源,后两个为外部中断源。
由于CPU在某一时刻只能响应一个中断请求,为处理执行主程序时同时来了多个中断请求和正在处理某一中断时又来了新的中断请求这两种情况,计算机采用硬件或软件给各个中断源按优先权大小进行中断排队,从多个中断申请中选出一个级别最高中断请求而响应之,这一过程称为中断排队。MCS-51单片机用户可用指令设置高、低两个优先级,而且同级中还有5个固定的隐含优先级,从高到低的优先级顺序分别是INT0、T/C0、INT1、T/C1、TXD/RXD。这样,在执行主程序时,同时来了两个以上中断请求,则先按高低两级选择高优先级,如只有一个高级就直接选之,如有两个以上都是同级,则按同级隐含优先级,选择其中一个高级别。如正在执行一个低优先级,又来了一个高优先级(即正在执行的中断级别低于新来的中断级别),则高优先级中断低优先级,这就形成了两级中断嵌套。如正在执行低的又来了另一低的或者正在执行高的又来了一个低的或高的(即正在执行的中断级别高于或等于新来的中断级别),则不予理睬,不会引起中断嵌套,也就是说同级隐含原则在不同时来了同级中断时无效。可见,MCS-51单片机最多形成两级中断嵌套。
CPU在执行任何机器指令时,在每一个机器周期TCY都要抽点时间(MCS-51单片机为S5P2状态节拍)来采集查询有无中断请求,如没有,则继续执行原程序机器指令,如有中断请求,则先从中选出级别最高者,在中断响应条件成立时,去处理响应此中断请求。
MCS-51单片机的中断响应必要条件是中断屏蔽总开关EA和中断请求相应的屏蔽分开关都必须闭合,只有这样,中断请求信号才能送到CPU。此外,还不能碰到以下3种情况,即有优先级更高的中断请求同时提出或者正在执行同级或高级中断,正在执行的指令还没有执行完、正在执行RETI或访问中断屏蔽寄存器IE和中断排队寄存器IP,这3种情况是中断响应的充分条件。这1种情况中断排队轮不