




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第6章中断及其应用6.1中断概述6.2中断响应控制6.3中断过程6.4中断的应用及扩展6.5系统化程序设计中的概念和方法6.6设计课目与演练——位移测量并显示小结
习题
本章首先讲述单片机的中断概念,然后从硬件上说明单片机怎样控制中断请求并产生响应,在中断服务程序中应该如何处理并返回,最后给出中断应用实例和扩展方法。6.1中断概述中断系统是为了使单片机对外界异步事件具有处理能力而设置的。图6-1中描述了中断的一些基本概念。在MCU正在执行程序的过程中,如果外部硬件或者内部某个组件发出请求,要求MCU暂停当前的工作,转而去处理这个临时事件;处理完毕后,再返回到原来被中断的地方,继续执行原来的工作。这个过程就是中断。实现这种功能的组成部件称为中断系统。向MCU发出中断请求的信号源称为中断源。中断发生前正在执行的程序代码称为主程序。中断发生时,主程序被断开的程序代码的位置称为断点。中断之后所执行的程序称为中断服务或者中断子程序。图6-1中断的过程及基本概念描述单片机的中断系统一般允许多个中断源。当几个中断源同时向MCU发出中断请求时,要求单片机既可以区分各个中断源的请求,又要决策首先为哪一个中断源服务,这就要求进行中断优先级的设定。单片机响应中断请求的顺序称为中断的优先级。当单片机正在进行一个中断服务的时候,另一个优先级较高的中断源发出中断请求,这时,单片机可以中断正在执行的中断服务程序,转而去响应这个更高级别的中断请求,执行其中断服务,然后再回到原低级中断继续处理,这个过程称为中断嵌套。
MCS—51系列单片机的中断系统是8位单片机中功能较强的一种,可以提供5(6)个中断请求源,具有两个中断优先级,可实现两级中断服务程序嵌套。6.2中断响应控制在中断响应控制过程中,有很多的寄存器参与其中,整体结构如图6-2所示。6.2.1中断源由图6-2可知,MCS—51中断系统有5个中断源(52增加了一个),通常分为三类:
外部中断:包括、,由外部硬件电路产生。中断的发生有电平触发(51系列为低电平触发,其它的请参考芯片的DATASHEET)和边沿触发(51系列为下降沿触发)。对于电平触发,在MCU的时钟周期内如果检测到有效的低电平信号,则认为产生中断请求,CPU开始执行中断处理。对于边沿触发,在MCU的时钟周期内如果检测到有高电平向低电平的变化信号(下降沿),则认为产生中断请求,开始执行中断处理。图6-2中断响应控制结构
定时中断:包括T0和T1(T2在8052系列才有),中断产生于MCU内部的定时/计数器的计数溢出。当定时/计数器工作于计数方式时,可以由T0、T1从外部输入计数脉冲等。
串口中断:对应RX、TX。具体对应的管脚参见图1-4及管脚说明。串口中断也是由内部电路产生的。当串口的缓冲区接收到数据或发送数据结束时,便产生中断,通知MCU进行下一步处理。
51系列单片机中断源的管理是通过中断入口地址(即中断矢量)来实现的。对应每一个中断源的中断请求,MCU响应后,都有一个唯一的16位地址送到程序计数器PC中。中断服务程序就是从这个地址开始执行的,所以称之为中断入口地址,也称为中断矢量。每一个中断入口都占有8个连续的字节,而且在程序存储器中的位置是固定的(见程序存储器结构,图2-3),被对应的中断源所指向。6.2.2中断请求标志(TCON、SCON)在中断请求被响应前,中断请求是由MCU锁存在特殊功能寄存器TCON和SCON的中断响应标志位中的。
1. TCON(88H)中断控制寄存器TCON的位定义格式如图6-3所示。下面分别介绍各位的定义:
TF1、TF0:定时/计数器Ti的溢出标志位。当Ti启动计数后,从初始值开始执行加1操作。当Ti计数溢出时,由硬件置位TFi,向CPU请求中断;响应后,由硬件自动清零。也可以由软件来查询该标志,并由软件清零。指令:CLRTF1(或CLRTF0等)。图6-3中断控制寄存器TCON
IE1、IE0:对应、的外部中断标志位。当外部触发中断后,置位相应的标志位,并且向CPU请求中断。响应后,由硬件自动清零(边沿触发方式)。
IT1、IT0:外部中断源触发方式控制位。以IT1为例,其控制方式为:
IT1 = 0,外部中断为电平触发。这是系统启动或者复位后的默认方式。当为低电平时,置位IE1。CPU在每个机器周期的S5P2采样的输入电平,当采样到低电平时,置位IE1。采用电平触发方式时,外部中断源必须保持低电平有效,直到该中断被CPU响应。采用电平触发方式时,CPU响应中断后,不能自动清除IE1标志位(软件也不可清零),因此,在该中断服务程序执行完之前,外部中断源必须被撤除,否则将产生另一次中断。
IT1 = 1,外部中断为边沿触发(下降沿)。CPU在每个机器周期的S5P2采样的输入电平。如果相邻的两次采样,前面为高电平,后面为低电平,则采集到有效的下降沿,置位IE1,表示外部中断向CPU申请中断,直到CPU响应中断时,才由硬件自动清零IE1。因为每个机器周期采样一次外部中断输入电平,所以,采用边沿触发方式时,外部中断源输入的高电平和低电平必须保持一个机器周期(12个振荡周期)以上,才能确保CPU检测到由高到低的下降沿触发。对于IT0,其对的影响同上,不再赘述。
2. SCON(98H)中断控制寄存器SCON的位定义格式如图6-4所示。这里只定义了与中断有关的两个位。图6-4中断控制寄存器SCON
TI:串口发送数据中断请求标志位。当单片机的串口发送完一个数据后,硬件置位TI,向CPU发出中断请求。但CPU响应中断时,并不自动清零TI,必须由软件清零。
RI:串口接收中断标志位。当单片机的串口接收完一个数据后,硬件置位RI,向CPU发出中断请求。但CPU响应中断后,并不自动清零RI,必须由软件清零。6.2.3中断允许控制(IE)如图6-2所示,IE是中断允许寄存器,对51系列单片机的每一个中断都有一个允许或者屏蔽的控制,分别对应IE寄存器里面的一位。中断允许寄存器IE的位定义格式如图6-5所示。图6-5中断允许寄存器IE
EA:中断允许总控制位。EA=0,CPU不响应任何中断,即所有中断被屏蔽,称为关中断。EA=1,允许中断,由每个中断源对应的控制位决定该中断是否允许。如CLREA,关中断;SETBEA,开中断。其他各位的使用方法相同。
ET2、ET1、ET0:定时/计数器Ti中断允许位。1则允许,0则禁止。如ET1=1,则T1中断允许;否则,中断被屏蔽。
EX1、EX0:对应外部中断、允许位。1则允许,0则禁止。如EX0=1,则允许管脚上的中断;否则,中断被屏蔽。
ES:串口中断允许位。ES=1,允许串行中断;否则,禁止串行中断。6.2.4中断优先级设定(IP)
MCS—51单片机具有两个中断优先级,由中断优先级寄存器IP控制,可以设定每个中断源为高优先级中断或者为低优先级中断,从而控制中断的嵌套。
1.中断优先级控制寄存器IP中断优先级控制寄存器IP的位定义格式如图6-6所示。
PS:串口中断优先级控制位。1为高优先级,0为低优先级。如SETBPS,则串口中断为高优先级。下面各位的使用方法相同。
PT2、PT1、PT0:对应T2、T1、T0中断优先级控制位。1为高优先级,0为低优先级。如PT1=1,则T1中断源为高优先级中断。
PX1、PX0:外部中断、中断优先级控制位。1为高优先级,0为低优先级。图6-6中断优先级控制寄存器IP
2.自然优先级多个中断源在同一个优先级上时中断源的内部查询顺序,称为自然优先级,先查询到的被优先响应。8051中断源的自然优先级如图6-7所示。
3.中断嵌套高优先级中断可以中断正在执行的低优先级的中断,除非这个高优先级中断被屏蔽。同级或者低级的中断源不能中断正在执行的中断服务程序,只能等到当前中断服务结束后,由CPU响应中断,执行中断。这一点编程者一定要注意,特别是初学者。在中断服务程序里要想到当前程序是否会被高优先级程序所嵌套中断,并且在嵌套中是否会改变当前使用的寄存器或者存储单元的值,是否允许嵌套等。这些都要认真考虑。图6-7自然优先级6.3中断过程上文从硬件的角度讲了与中断响应有关的控制寄存器的设置。下面从程序执行的角度(即软件的角度)分析中断的处理过程,整体分为三个过程:中断响应,中断处理(中断服务),中断返回。这三者之间的层次关系已在图6-1中进行了描述。6.3.1中断响应当中断源发出中断信号后,CPU不一定能够立即响应中断。除了上面讲的硬件中断响应条件外,程序当前指令的执行状态也会暂时阻断中断响应。下面系统介绍这两个响应条件。
1.响应条件
(1)硬件设置条件:
中断源有中断申请,如T0溢出。
中断允许总控制位允许,即EA=1。
与中断源对应的中断允许控制位允许,如ET0=1。
(2)指令执行状态条件:
CPU正在执行同级或者高一级的中断服务程序,则响应等待。
当前的机器周期不是正在执行的指令的最后一个周期,则响应等待。一条指令可能需要单周期、双周期或者4个机器周期,但是中断不能在一条指令的执行周期内响应中断,必须等到正在执行的指令执行完毕。
正在执行的指令是中断返回(RETI)指令或者是对专用寄存器IP、IE进行读写的指令,需要在该指令执行完后再执行一条其他指令,才有可能响应中断。如果上面的中断条件已经满足,阻断状态已经解除,那么CPU就可以响应中断。
2.响应过程
置位相应的优先级状态触发器(CPU内部使用,不对用户开放,不可寻址;该触发器指出CPU开始处理的中断的优先级别,会影响到是否允许再次中断,并且屏蔽较低优先级的中断请求等)。
执行一个由硬件自动完成的子程序长调用指令LCALL,去调用该中断源入口地址。因此,中断服务程序可以放在64KB的程序存储器空间内的任意位置。响应应完成以下工作:
硬件将当前的断点地址压入堆栈。
将该中断源对应的中断入口地址(中断矢量)装入程序计数器(PC)。
程序开始执行相应的中断服务(程序)。
有些中断会由硬件自动清除该中断的中断请求标志位(T0、T1、T2,还有、的边沿触发方式)。上述条件判断和执行步骤如图6-8所示。图6-8中断响应的条件与过程
3.响应时间
CPU对于中断的响应需要一定的时间,而且不同的中断源、不同的指令、不同的优先级等都会影响中断的响应时间。这个时间最短为3个机器周期,最长为无限。当然,优良的程序设计不允许出现中断响应时间为无限的情况。一般的程序设计不用考虑中断响应时间的问题。但是在精确定时或者实时控制要求较高的场合,就要认真考量程序的每一步执行和每一条指令的设计。详细描述如下。在每个机器周期的S5P2状态中,中断源的中断申请被锁存到中断标志位,在下一个机器周期CPU才会查询这些值。这里占用一个机器周期。如果满足中断响应条件,则由硬件执行长调用指令LCALL,使程序转入中断服务程序执行。这个调用需要两个机器周期。这是最快的响应时间,最少需要3个机器周期。下面看看如果有响应受阻的情况发生。如果中断源申请中断时,有一个优先级更高的中断正在发生(或执行),那么中断请求被搁置,进入等待状态,一直要等到这个高优先级的中断执行完毕以后,才有可能响应。那么,这个等待时间就决定于这个高优先级的中断服务程序了。所以,上面提到没有等待上限的问题。但是,如果真的没有上限,则是不良的程序设计,甚至会产生灾难。这里要特别提示,中断服务程序要短小高效,以免影响其他中断服务。6.3.2中断处理中断处理(中断服务)程序指的是,从中断响应后转到中断源对应的中断入口地址开始执行起,一直到执行RETI指令开始中断返回止的这一段。这一段是由用户来设计完成的,即软件执行部分。这部分主要有四个方面需要考虑。
1.程序跳转每个中断源的中断入口地址是由硬件确定的,但是对应的空间只有8个字节,处理中断服务有些困难。所以,一般在这里直接放置一个无条件跳转指令,转移到用户的中断服务程序去执行。这里实际上已经进入了中断服务,但是习惯上说的中断服务常常是指跳转后执行的那个程序。关于跳转,在存储单元结构中有详细的描述,见图2-3(程序存储器结构)。
2.现场保护与恢复在执行中断服务程序时,有可能会影响PSW或者其他操作过的单元,如果这些操作单元在主程序中也被使用,就会产生两种后果:
(1)传递结果或者参数。比如,在主程序中设置一个死循环:
CLRA
JZ$然后在中断服务中设置指令:
MOVA,#01H当中断服务执行后,上面的死循环结束。为什么?问题1:在死循环中还可以修改A中的值吗?这就是中断的特色和魅力。问题2:修改了A的值死循环就结束了吗?死循环是怎么形成的,如果A的值非零,就不是死循环了。这个例子是利用中断来跳出死循环的。
(2)造成混乱,甚至导致程序的崩溃。举个例子,在主程序中有:
MOVA,#02H MOVDPTR,#PROG_INDEX JMP@A+DPTR
PROG_INDEX: AJMPPROG1 AJMPPROG2 …中断服务程序中设置指令:
MOVA,#01H如果这个中断正好在主程序执行完MOVA,#02H之后响应中断并且执行中断服务,那么A中的值就会被修改为01H。AJMP指令是双字节指令,这样会有什么情况发生,程序跳转到了一条指令的第二个字节执行?!这就乱套了。(请查询指令代码,可以进一步分析。)所以,要在中断服务中对主程序中可能被影响的单元进行保护。常用的方法就是入栈保护和出栈恢复,这就是现场的保护和恢复。在进入中断服务程序后,首先将中断服务中可能要用到的存储器或者单元进行保护(入栈处理,例如PUSHA);在中断处理程序结束前,恢复这些单元的内容(出栈处理,例如POPA)。
3.开关中断问题
若在执行当前中断时不想被更高级的中断打断,则进入中断服务程序后,首先要关中断,或者屏蔽更高级中断源的中断。例如,执行CLREA。通常采用的方式就是进入中断服务后关中断,而在中断返回前开中断。
在进行现场的保护或操作时,不能被高优先级的中断打断,否则有可能会破坏现场数据或者造成混乱。通常采取的方法是保护现场前关中断,保护后再开中断;恢复现场前关中断,恢复结束后再开中断。这是一般意义的流程。如果在中断服务中不希望发生中断嵌套,则关中断后中间就不用再开了,直到返回前再开中断。一般意义的中断处理流程如图6-9所示。图6-9中断处理过程
4.处理中断源请求(处理任务)这是中断响应后程序要解决问题的核心程序段,处理中断任务,完成该中断的功能设计。比如,要对计数器的计数单元重新赋值,要处理外部的按键中断等,这就相当于一个子程序的设计。不再赘述。6.3.3中断返回中断返回是指从执行RETI指令到程序回到主程序断点处继续执行的这段过程。RETI是中断返回专用指令。执行这条指令后,可将主程序的断点地址从堆栈中弹出,送回到PC中,让程序回到主程序断点处继续向下执行;还要通知中断系统已经处理完毕当前中断,清除优先级状态触发器(也正是因为这样,不能使用RET代替RETI;否则导致的后果是,不能再次响应中断)。这个过程的处理如图6-10所示。图6-10中断返回示意图6.4中断的应用及扩展中断系统是单片机的精髓,只有学会了中断系统,你才算真正了解了单片机,并且可以尝试进行应用设计了。比如说,前面我们已经设计了按键系统,但是它的工作方式是查询,会消耗掉大量的CPU资源,在实践中很难应用,而实用的按键大多采用中断方式设计。下面,我们把中断应用到具体的系统中,在领略中断的魅力的同时,来分析设计中断服务的要领和注意事项。6.4.1键盘中断与识别图3-21(b)是独立式按键的中断设计方法,请读者自己尝试编程,完成中断服务设计。这里讲解比较实用的矩阵式按键设计。矩阵式按键中断工作方式接口的电路如图6-11所示。图6-11矩阵式键盘中断工作方式接口这个电路是在图5-10(b)所示的电路原理基础上增加了中断。这个设计方法比较常用,而且由于增加了中断,使该电路更为实用。对应的电路图如图6-12所示。
(1)把行线全输出0,而列线输入为:当无按键按下时,列线全部为高电平;当有按键按下时,该按键对应的列线为0。
(2)由图6-12可知,只要有列线出现低电平,则4与门74LS21就输出低电平,连接到CPU的,发出中断请求。
(3)为了可以响应按键中断,需要在程序初始化时设置相应的中断允许:
SETBEX0 ;开外部中断0
SETBEA ;开中断,注意这个设置的先后顺序(一般)或者直接执行一条指令:
ORLIE,#81H图6-12矩阵式键盘中断方式设计电路图
(4)响应键盘中断后,要在键盘中断服务程序中完成键盘消抖和键盘识别及编码工作,这个任务直接使用第5章讲述的线反转法。但需在这个功能程序段的前后做些工作,要保护在键盘识别和编码过程中用到的寄存器和其他存储单元(现场保护),以免回到主程序后影响运行,甚至导致程序崩溃。中断服务中用到的寄存器或存储单元有R0、P1、A;消抖使用的10ms延时程序里的寄存器也要考虑在内,比如R1、R2、R3。另外,运算会影响PSW相应的位。不一定要对中断服务中涉及到的所有寄存器或单元进行保护,保护的目的是不影响主程序的正确执行。如果中断服务中使用的寄存器或者单元在主程序的设计中没有使用,或者就是用来和中断服务程序进行数据沟通(如参数传递)等,就没有必要保护了。
(5)如果按照一般的设计方法,在键盘中断服务期间不允许其他的中断发生,则中断服务程序设计如下:
CLREA ;关中断
PUSHPSW ;保护程序状态字
PUSHA ;保护累加器A键盘线反转法扫描 ;就是第5章的线扫描法程序 ;建议不要采用调用方式
POPA ;恢复A
POPPSW ;恢复PSW
SETBEA ;开中断
RETI ;中断返回
(6)还要考虑按键的重键问题。当按键已经响应并且中断处理返回后,行线重新又恢复到输出全0,列线为输入的状态。这个时间是非常短的(约几十毫秒),但这个时候按键并没有撤除,4与门仍然是输出低电平,即端还是输入低电平,就会再次产生中断请求,CPU再次发生中断,又再次执行处理。这就产生了重键。实际上是一次按键,但程序把它当成几次按键动作进行处理。比如,你设计的是一个数字输入键盘,当输入一个1时,程序却连续输入了3个、4个或者更多个1,应该避免这种情况的发生。上面出现的问题是,因为按键按下后会持续一段时间(几百毫秒~几秒),而在这段时间里按键是稳定的(见图3-18),特别是在中断服务程序返回后,只要按键不重新抬起,就不会产生列线电平的变化。因此,可以把按键中断的响应条件改变为下降沿触发,这样一次按键只有一次触发(不稳定的触发已被消抖处理,而在反转扫描列线全部输出为0时,4输入与门仍然输出低电平,不会产生新的触发)。所以,在程序初始化时,要设置:
SETB IT0 ;或者执行:
ORL TCON,#01H ;
(7)完整的实例程序如下:
ORG0000H ;
LJMPSTART ;程序跳转
ORG0003H ;按键中断入口地址(中断0入口地址) LJMPKEY_TEST ;跳转到按键中断服务
ORG0100H
START: ;主程序
MOVSP,#60H ;要给SP足够的堆栈深度
MOVP1,#0F0H ;按键接口初始化,行输出,列输入
SETBIT0 ;中断设置初始化,下降沿触发
SETBEX0 ;开外部中断0 SETBEA ;开中断
MOVR0,#00H ;用R0作为按键键码传输单元,
;这里初始化为0
LOOP:
CJNER0,#00H,FUNC ;如果有按键,则处理
SJMPLOOP ;重复检测
FUNC: NOP ;这里的功能为空,请根据需要自己补充 MOVR0,#00H ;处理完毕后,重新设置R0为0 RET
DEL10: NOP ;这里的延时为空,请自己补充
RET
KEY_TEST: ;键盘检测子程序的入口地址
CLREA PUSHPSW PUSHA MOVR0,#00H ; R0存放按键编码,初始化为0,表示无按键
MOVA,P1 ;行输出,读入列的状态
ANLA,#0F0H ;屏蔽掉行线状态
CJNEA,#0F0H,RE_TEST ;判断列线状态是否全为“1”,如果不是,
;去抖动
SJMPRETU ;如果全部为“1”,则无按键,转去返回处理
RE_TEST: ;去抖动处理
LCALLDEL10 ;延时10ms MOVR0,A ;先保存刚才的列位置
MOVP1,#0FH ;交换,行输入,列输出
MOVA,P1 ;再读入按键行状态
ANLA,#0FH ;屏蔽掉列线状态
CJNEA,#0FH,KEY_CODE ;是否仍有按键,如有,转去得到键码
MOVR0,#00H ;清除R0 SJMPRETU ;否则,说明是抖动或者干扰
KEY_CODE: ;在这里得到键盘编码,确定按键
ORLA,R0 ;把行、列状态合并,得到键码
XCHA,R0 ;把键码交换到R0
RETU: MOVP1,#0F0H ;恢复行输出、列输入的状态
POPA POPPSW SETBEA RETI ;中断返回主程序
END ;程序结束伪指令进一步:
这个程序非常实用。
思考:R0的值是什么时候被改变的?主程序是怎样检测R0的值的变化的?
思考:延时去抖动后验证是否仍有按键时,不是采用原来的读法,而是更换行、列输出后再验证。这样做的道理是什么?
思考:中断响应的触发方式是什么?那么,中断服务中的CLREA必需吗?不使用会怎样?
思考:在中断返回前,为什么要有MOVP1,#0F0H这条指令?6.4.2编码器中断与识别在工程实践中,常常需要测量位移或者转速等,而编码器是一种比较有效而稳定的测量仪器。其测量原理就是把位移的变化转化为脉冲输出的个数进行测量,而把速度的变化转化为脉冲输出的频率来进行测量。其中光电式增量编码器是较常用的一种编码器。下面以EPC-755A光电式编码器为例,来讲解编码器如何与单片机接口,并给出测量实例。
1.编码器测量原理光电式编码器是目前应用较多的一种传感器,测量原理如图6-13所示。光电式编码器是由光栅盘和光电检测装置组成的。光栅盘是在一定直径的圆板上等分地开通若干个长方形孔。由于光电码盘与电动机同轴,电动机旋转时,光栅盘与电动机同速旋转,经发光二极管等电子元件组成的检测装置检测输出若干脉冲信号,通过计算每秒光电编码器输出脉冲的个数就能反映当前电动机的转速。为判断旋转方向,码盘提供相位相差90°的两路脉冲信号OUT_A、OUT_B;另外还提供一个同步信号OUT_Z,编码器每转一圈输出一个脉冲,可用于基准点定位。图6-13光电式编码器测量原理
2.编码器输出信号分析编码器提供的脉冲信号与方向的关系如图6-14所示。可以看出,两路信号总有90°的相位差,而且不同方向时相位差有正负区别。这个信号是集电极开路输出型,使用时需要接上拉电阻。如果选用OUT_A的下降沿作为脉冲的检测条件,那么只要在脉冲到来后判断OUT_B的电平信号就可以判断当前编码器的旋转方向。因为编码器是外部设备,而且它的引线常常会比较长,为了避免给单片机带来干扰,常采用光电耦合器件把编码器和单片机控制部分进行电磁隔离(见下面接口部分)。
3.编码器与51单片机的接口编码器与51单片机的接口电路如图6-15所示。把PULSE_INT连接到相应的中断口,比如连接到,在中断服务中需要判断方向。把PULSE_DIR连接到P1.0,则可依据P1.0的电平状态判断编码器的旋转方向。图6-14编码器输出信号与方向的关系图6-15编码器的接口电路
4.测量位移的例程按照图6-15所示的电路连接,设计一个测量位移的简短代码:
ORG0000H LJMPSTART ORG0003H LJMPENCODER ORG0100H
COUNTERDATA40H
START:
MOVSP,#60H SETBEX0 ;中断功能初始化
SETBIT0 SETBEA MOVCOUNTER,#00H ;初始化脉冲计数器为0 SJMP$ ;这个程序只用做编码器接口测试
ENCODER: CLREA PUSHPSW PUSHA JBP1.0,ADD1 ;判断中断发生时,如果P1.0是高电平,则是正向计数
DECCOUNTER ;否则,是反向计数
SJMPRETM
ADD1: INCCOUNTER
RETM: POPA ;恢复现场
POPPSW SETBEA RETI ;中断返回
END进一步:
如果这个程序只用于编码器,在中断服务中还用关中断吗?如果去掉SETBIT0,程序会怎样?
这里的脉冲计数器只使用了单个字节,尝试使用两个字节的计数器。6.4.3中断的扩展当使用的外部中断较多时,可以采用如图6-16所示的方法进行中断的扩展。当~任何一个有低电平时,经8输入与门输出低电平,向发出中断请求。当中断响应后,立刻查看P1口的各线状态。采取逐位查询的方式,先看P1.0,然后看P1.1,…,最后看P1.7,如果查询到有位为低,则找到外部中断扩展源。当然,在这个扩展电路中,可以采用软件设计的方式优先查询哪位或者哪几位扩展中断源的状态。这就是前面提到的中断源的优先级设置。比如,规定自然优先级的顺序是P1.0、P1.2、…、P1.7。在实际使用时会遇到元件选择的问题。这里使用的是8输入与门,市面上不常见,但是8输入与非门则比较常见。实际上,真有如此多的外部中断源需要扩展的时候,就应该考虑使用CPLD或FPGA等器件了。这里使用8输入与门的电路,如图3-21(b)所示,把按键S0~S7换成外部扩展中断源~,得到如图6-17所示的电路。(如果使用8输入与非门,则可以选择74LS30,然后加一级74LS04反相器。)图6-16中断的扩展原理图6-17中断扩展电路程序代码如下:
ORG0000H LJMPSTART ORG0003H ;扩展中断的入口地址
LJMPEX_INT0 ;跳转到比较大的中断空间中去
ORG0100H
START: MOVSP,#60H ;要给SP足够的堆栈空间
MOVP1,#0FFH ; P1输入口打开
SETBEX0 ;使能外部中断
SETBIT0 ;设置为下降沿触发
SETBEA ;中断开
SJMP$ ;主程序进入循环
EX_INT0: ; CLREA ;关中断
PUSHPSW ;程序状态字入栈
PUSHA ;累加器入栈
MOVA,P1 ;按照顺序依次判断
CJNEA,#0FEH,EXINT1 ;是否扩展中断0 LJMPFUNC0
EXINT1:
CJNEA,#0FDH,EXINT2 ;是否扩展中断1 LJMPFUNC1
EXINT2: CJNEA,#0FBH,EXINT3 ;是否扩展中断2 LJMPFUNC2
EXINT3: CJNEA,#0F7H,EXINT4 ;是否扩展中断3 LJMPFUNC3
EXINT4: JBACC.4,EXINT5 ;是否扩展中断4 LJMPFUNC4
EXINT5: JBACC.5,EXINT6 ;是否扩展中断5 LJMPFUNC5
EXINT6: JBACC.6,EXINT7 ;是否扩展中断6 LJMPFUNC6
EXINT7:LJMPFUNC7 ;是否扩展中断7
FUNC0: ;具体响应部分请自己补充
LJMPRET_M
FUNC1: ;具体响应部分请自己补充
LJMPRET_M
FUNC2: ;具体响应部分请自己补充
LJMPRET_M
FUNC3: ;具体响应部分请自己补充
LJMPRET_M
FUNC4: ;具体响应部分请自己补充
LJMPRET_M
FUNC5: ;具体响应部分请自己补充
LJMPRET_M
FUNC6: ;具体响应部分请自己补充
LJMPRET_M
FUNC7: ;具体响应部分请自己补充
RET_M: POPA POPPSW SETBEA RETI END6.5系统化程序设计中的概念和方法程序设计的概念和方法已经分散在前面各章学习指令和控制硬件的过程中了,这里集中总结一下,让读者对程序设计有一个系统的概念和印象。6.5.1汇编语言计算机的语言体系分为机器语言、汇编语言和高级语言。机器语言是能够被机器直接识别和执行的语言,是一系列的二进制数,就是前面讲的指令代码。对这些二进制代码进行分析、编程、修改等是非常麻烦的事情。为了方便,就采用人们习惯的符号来表示指令的操作码或操作数,这些符号就是第1章讲的助记符(如MOV、XOR等),这种符号语言就称为汇编语言。用汇编语言编制的程序叫汇编程序,也叫源程序。汇编语言实际上是机器语言的符号化,只是采用助记符来描述。汇编语言只有翻译成机器语言才可以被机器识别和执行,这个翻译过程称为编译。现在,一般的系统开发平台提供集成的开发环境:源程序的编辑和编译,还有的同时也提供仿真等功能。µV3系统就可以完成这些任务。无论机器语言还是汇编语言,都是面向机器的设计方案,设计目标直接针对硬件,离用户的层次比较远,所以把这种语言称之为低级语言。其优点是硬件控制能力强,代码执行效率高,对指令的执行时间控制能力高,特别适用于实时控制;缺点是没有通用性,程序对硬件依赖性强,移植能力太差,编程工作量大。高级语言是一种面向过程或者面向对象的语言,如C、VC、VB、PB等都是高级语言。在高级语言环境中,由系统来配置完成对不同硬件的支持,用户使用时主要精力是掌握该语言的语法规则和程序的结构设计等,这样就可以提高用户的编程效率。随着单片机的发展,存储器的价格非常便宜,空间已经足够,而且也具有足够的运行速度,所以程序设计的首要任务已不是节约空间和精简代码,而是提高编程效率,增加程序的可读性和可维护性。6.5.2程序结构程序的基本结构有三个:顺序、选择和循环。任何复杂的程序都可由这三种基本结构组合完成。6.5.3子程序与中断服务程序这里重点强调一下二者执行机制的不同。子程序是程序在固定的位置主动去调用执行的。而中断服务程序则是在不确定的位置,由硬件去调用执行的。在子程序中也有可能发生中断调用;而在中断服务中也可以安排子程序的调用。不过,堆栈的深度要足够,否则堆栈会溢出而导致程序崩溃。6.5.4查表、数据检索与排序查表、数据检索与排序是程序设计中比较重要的几个算法。
1.查表专门的查表指令有两条:MOVCA,@A+PC和MOVCA,@A+DPTR。二者的区别已在第2章介绍基址加变址指令时详细介绍过,请参阅。这里用第二条指令举例说明一下。
TABLE为首地址的表中依次存放了0~10的立方值,利用查表法求出R0中数的立方,结果放在R2R1中。程序如下:
ORG0000H LJMPSTART ORG0100H
START: MOVSP,#60H MOVR0,#08H ;给R0赋值
LCALLCUBE ;调用查找立方值
SJMP$ ;主程序循环
CUBE:
MOVDPTR,#TABLE ; DPTR指向立方表
MOVA,R0 ;读入R0里面的值
RLA ;双字节存放,所以要乘2 PUSHA ;把A中的数据保存
MOVCA,@A+DPTR ;取出立方值的高8位
MOVR2,A ;放入R2中
POPA ;恢复刚才A中的原始值
INCA ;增加1指向低8位
MOVCA,#A+DPTR ;取出立方值的低8位
MOVR1,A ;放入到R1中
RET ;子程序返回
TABLE: DW0,1,8,27,64,125
;一共存放了11个字,对应
DW216,343,512,648,1000; 0~10的立方值
END
2.检索数据检索是查找某个数据块中是否存在某目标值的程序。该目标值常称为检索关键字。常用的数据检索方法是顺序检索法,即将关键字与数据块中的数据按前后顺序依次比较是否相等,以此判断是否找到目标值。举例如下:从30H开始连续存放了10个数,查看其中是否存在某个目标值,如果存在,通过R0返回索引值,否则,返回0FFH。程序如下:
ORG0000H LJMPSTART ORG0100H
TARGET EQU 5AH ;定义目标值
START: MOVSP,#60H ;定义堆栈
LCALLRETRIEVE ;调用检索子程序
SJMP$ ;程序暂停(循环)
RETRIEVE:
MOVR0,#00H ; R0作为索引值
MOVR1,#30H ; R1作为查寻的起始地址
LOOP: CJNE@R1,#TARGET,NEXT ;比较是否找到目标值
SJMPRETU ;找到就返回索引值
NEXT: INCR0 ;修改索引值和地址
INCR1 CJNER0,#0AH,LOOP ;比较是否满10个数
MOVR0,#0FFH ;没有找到就返回0FFH
RETU: RET ;返回
END
3.排序在数据结构中,排序有很多种算法,比如冒泡法、选择法、插入法等。这里仅介绍冒泡法。冒泡法是一种常用的排序方法。在排序的比较过程中,总是让较小的数向上“浮”,而较大的数向下“沉”,像水中的气泡一样向上“冒”,所以称之为冒泡法(有时候也称为沉底法)。下面给出冒泡法排序的一个实例。在30H开始的存储单元中,存放了6个数据:1、5、2、8、6、9。现在要这些数据按照从小到大的顺序给出排序,最小的数据对应放在30H单元。分析操作过程如图6-18所示。首先从头开始由上至下,相邻的两个数据依次比较,总是把大数往下交换。当第一个轮次结束时,最大数放在了最下面。然后进行第二个轮次的比较,这个轮次结束的时候,次大数放到了倒数第二的位置上。因为第一个轮次找到的是最大数,所以,第二个轮次再比较的时候就不用再和这个最大数比较了(就是比较也没有交换发生,但是会浪费资源)。后面的依此类推。因为每一个轮次的循环都可以找出本轮次参与比较的最大数并放在本轮次的最下面,所以如果有n个数的话,只要进行n-1个轮次,就把数据全部按照既定的顺序(这样说的意思是排序可以由大到小,亦可由小到大)排列完毕。分析几个特殊的情况:如果这6个数的排序本来就是1、2、5、6、8、9,则第一个轮次循环比较结束后,发现没有任何数据发生交换,就说明全部数据已经排序完毕,不用再继续进行下一个轮次的比较了。如果这些数据本来是2、1、5、6、8、9呢?第一个轮次发生了数据2和1的交换,进行第二个轮次的比较时就没有数据发生交换了,这时就可以判断排序已经完成。由此得到是否继续循环的一个判断依据:当前轮次的比较中如果没有发生任何交换,就可以认为排序已经完成,排序可以提前结束。参与排序的数据个数为n,排序的轮次为i,每一轮次需要的比较次数为j,这些数据之间的关系在图6-18中已经注明。因为要有i轮次和每一轮当中的j次的比较,所以设计程序的时候要使用两层循环。数据存放的首地址用R0表示;R1表示辅助地址,用来进行比较和交换;数据个数用R2表示;轮次为外层循环,使用R3控制;每一轮次内相邻数据的两两比较为内层循环,使用R4控制;当前轮次是否有交换发生的标志放在位20H.0中,用FLAG表示。图6-18冒泡法排序程序设计如下:
ORG0000H LJMPSTART ORG0100H
FLAGBIT20H.0;定义一个是否发生交换标志位
START: MOVSP,#60H MOVR0,#30H ;数据块的起始地址
MOVR2,#06H ;数据块的长度
LCALLSORT ;调用排序子程序
SJMP$
SORT: MOVR3,#01H ;初始化R3,代表第几个轮次
LOOP1: MOVA,R2 ;计算每个轮次的比较次数
SUBBA,R3 ;即:
MOVR4,A ; R4=R2-R3(j=n-i) CLRFLAG ;清除交换标志
PUSHR0 ;保护数据块首地址
LOOP2: MOVA,@R0 ;开始进行一轮当中的两两比较
INCR0 SUBBA,@R0 ;比较相邻的两个数大小
JCNEXT ;如果前面的大,则进行交换
MOVA,@R0 ;把两个数据交换
DECR0 XCHA,@R0
INCR0
XCHA,@R0 SETBFLAG ;这里发生过交换,置位交换标志
NEXT: DJNZR4,LOOP2 ;判断内循环是否结束
INCR3 ;进入下一个轮次
POPR0 ;恢复数据块首地址
JBFLAG,LOOP1 ;不再发生交换时,外围的循环就结束
RET ;返回
END冒泡法排序子程序流程如图6-19所示。图6-19冒泡法排序流程6.5.5运算类程序设计
MCS—51的指令系统只提供单字节和无符号数的算术运算指令。但在实际的程序设计中,经常处理带符号数或者多字节数的运算,这时就需要自己编写程序。这里给出几个典型的运算类子程序。
1.多字节加法多字节加法的关键是,从低字节相加,然后到高字节相加,逐字节顺序操作,并且高字节相加时要考虑低字节的进位(使用ADDC指令)。举例:两个10字节的无符号数分别存放在BLOCK1和BLOCK2为起始地址的存储区中,求两个数的和并把结果存放在BLOCK1为起始地址的存储区中。分析:如果把第1个数据使用ADD指令对应相加,后面的9个数据使用ADDC指令对应相加,这就需要两种加法指令。实际上,可以把所有数据的加法都使用ADDC指令,但是第一条指令执行前应当清除进位标志位(即执行CLRC)。解析结构如图6-20所示。程序如下:
ORG0000H LJMPSTART ORG0100H
START: MOVSP,#60H MOVR0,#BLOCK1 ;数据块1首地址
MOVR1,#BLCOK2 ;数据块2首地址
MOVR2,#10 ;数据块长度,这里作为循环次数控制
CLRC ;一定要先清除C
LOOP: MOVA,@R0 ;取数据块1数据
ADDCA,@R1 ;加数据块2数据
MOV@R0,A ;存结果到数据块1对应位置
INCR0 ;同时修改两个数据块的数据指针
INCR1 DJNZR2,LOOP ;循环次数判断
CLRA ;把最后一个字节相加后的C保存
ADDCA,#00H ;采用的方法就是给累加器A加0 MOV@R0,A SJMP$
BLOCK1: DS10 ;这里放数据
BLOCK2: DS10 ;这里放数据
END思考:如果是要做BCD码的多字节加法运算呢?(提示:只要在加法指令后紧跟着DAA指令就可以了。)图6-20多字节加法
2.单字节带符号整数的乘法单字节带符号整数的乘法可按照下面三步进行操作:
(1)保存两个乘数的符号,计算乘积的符号。乘积符号与两个相乘数符号之间的关系是:乘积符号位 = 被乘数符号位乘积符号位但51指令系统里面的位操作没有异或指令,所以采用另一种形式:这样就可以计算出乘积的符号位。
(2)两个数取绝对值相乘。
(3)根据乘积符号位操作变换其绝对值乘积的结果。如果符号位为负,则转换为补码。例如:R1、R0中对应存放的是带符号的乘数和被乘数,求二者的乘积,并把结果存放在R3R2中。程序示例如下:
ORG0000H LJMPSTART ORG0100H
START: MOVSP,#60H MOVR1,#60H ;给R1赋值
MOVR0,#0B2H ;给R0赋值
LCALL PRODUCT ;调用乘积计算子程序
SJMP$
PRODUCT: MOVA,R1 ;取被乘数的符号位到00H位
RLCA MOV00H,C
MOVA,R0 ;取乘数的符号位到01H位
RLCA MOV01H,C ;开始执行求异或的运算
ANLC,/00H MOV02H,C MOVC,00H ANLC,/01H ORLC,02H MOV02H,C ;求到的乘积的符号位保存到02H MOVA,R0 ;取乘数,如果为负就求补码
JNBACC.7,NEXT1
CPLA ;方法就是取反加1
INCA
NEXT1: MOVB,A ;把乘数保存到B MOVA,R1 ;取被乘数,如果为负就求补码
JNBACC.7,NEXT2 CPLA ;方法还是取反加1 INCA
NEXT2: MULAB ;取乘积,这是绝对值乘积
JNB02H,NEXT3 ;把结果进行转换
CPLA ;如果为负,先把低8位取补码
ADDA,#01H ;想想为什么使用ADD而不是INC
NEXT3: MO
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 阿城市2025届三年级数学第二学期期末复习检测试题含解析
- 陕西中医药大学《经济林木病虫害防治》2023-2024学年第一学期期末试卷
- 陕西服装工程学院《儿童少年卫生学》2023-2024学年第一学期期末试卷
- 建筑图纸知识
- 陕西省咸阳市三原南郊中学2024-2025学年高三5月阶段检测试题历史试题试卷含解析
- 陕西省商洛重点中学2025年初三3月统一测试(一模)化学试题含解析
- 陕西省安康市镇坪县2025年三下数学期末经典模拟试题含解析
- 陕西省度西安中学2025届高考模拟(三诊)物理试题含解析
- 计算机病毒与防治
- 陕西省汉中市佛坪县2025年小升初数学高频考点模拟卷含解析
- 物理学简明教程马文蔚等高教出版社
- SY-T 6966-2023 输油气管道工程安全仪表系统设计规范
- 110KV变电站继电保护设计毕业设计论文
- 2024年广东东莞市公安局石排分局辅警招聘笔试参考题库附带答案详解
- 肥料、农药采购服务供货、制度保障及验收方案
- 2024情绪与健康睡眠白皮书
- (高清版)DZT 0203-2020 矿产地质勘查规范 稀有金属类
- 中小学必背飞花令诗词-(春、月、风、花、山、江、人、日、动物、颜色、数字)
- 轨检数据分析报告
- 2024年国家能源集团招聘笔试参考题库含答案解析
- 儿科重症肺炎个案护理查房
评论
0/150
提交评论