(单片机有两个主程序)为什么一般在主程序的开始要安排一条跳转指令?中断过程中为什么要保护现场及如何保护..

当前位置: >
PIC中档单片机的中断总结
&&&与51或者其他系列的单片机相比,PIC&单片机的中断机制有其特殊之处,针对我们一些初学者存在的一些问题和疑惑,我在此做一个个人总结,不当的地方,请站友们指正。 &&先摘引三个对PIC中断理解的回帖,然后我再对中断活动的过程、应该注意的事项、及一个疑惑进行较详细的总结和解释。 --------------- john&frank&:关于pic中断有些不明白的地方& 借用大虾的程序; ;********************&中断服务代码 &&&&btfss&&&&INTCON,T0IE&&&&&&;&判断是否为T0中断 &&&&goto&&&&other_int &&&&btfss&&&&INTCON,T0IF&&&&&&;&it&’s&the&time&of&T0&int &&&&goto&&&&other_int &&&&bcf&&&&INTCON,T0IF&&&&&&;&是T0中断,清除中断标志 &&&&movlw&&&&0x10&&&&&&&&&&;&微秒的高位字节加上定时时间&256x16分频=0的高位(0x10) &&&&addwf&&&&us+1 &&&&goto&&&&end_int&&&&&&&&&& other_int&&&&&&&&&&&&&&;&可添加其他中断服务代码 &&&&nop&&&&&&&&&&&&&&;&other&isr&code&can&be&added ;********************************** end_int&&&&&&&&&&&&&&&&&&;&恢复现场 ================= 假如又有新的中断正好在这段程序中间产生 btfss&&&&INTCON,T0IF&&&&&&&&& goto&&&&other_int bcf&&&&INTCON,T0IF&&&&& 程序岂不是要出错跑飞了 john&frank:谢谢你的关注。 我讲一下自己的理解,权做回答,不当之处,还请站友们指点。 &&&&pic中档单片机系列没有“硬件中断优先级别”(请允许我这样说),含义是指:当内核正在处理当前的中断服务A时,在这个期间里,其他任何中断的产生,只能使其标志位xxIF置1,不能剥夺当前中断服务对CPU的占用权(反应在PC指针不能被新的中断改变指向),必须等到当前中断服务处理A完毕,然后,根据goto&other_int语句的转向,依次判断。若新发生的中断处理代码在中断服务A之后(前、后指代码在ROM中地址顺序,越大越后),则进行新发生的中断处理;若恰好新发生的中断服务代码在刚被处理完毕的中断服务A代码之前,则将不予理会,(即程序指针PC不会在中断处理代码空间中又返回到0004H的入口),等到执行到retfie&后返回主程序,然后再次进入中断入口0004H... &&&之所以说其无“硬件中断优先级别”是与“软件中断优先级别”对应的,通过中断服务代码对中断标志和IE的检测的先后,可设立优先级。 &&&当然,准确地说,这是一种顺序,而非级别,呵呵。 &&&如果了解一下51的中断系统,相信你能更好地理解PIC的中断的级别: 将会出现你说的情况,当优先级更高的中断来临时,内核将暂时停止当前中断服务,保存当前中断服务的现场,执行优先级更高的中断服务,处理完成后,恢复现场,执行未处理完成的中断服务....,最后,返回主程序。 &&& &&&小弟讲得有点烦琐,并不形象,可能还有纰漏和谬误之处,请大家指正,相信john&frank在仔细看书之后,应该可以形成自己的正确看法。 zdtdl&:小弟说两句~~& 简单地说,当系统响应一个中断时,GIE位将被自动清零以禁止其他的中断,在执行中断返回指令RETFIE后系统再自动置GIE位1开放中断。只要不在中断程序中对GIE置1,就不会产生反复进入中断的现象,靠查询方式决定响应谁。PIC也有中断嵌套,可以形成多级嵌套,甚至自身嵌套,不过嵌套的级数绝对不能超过硬件堆栈的深度。 ------------------------- &&&PIC中档单片机的中断总结正文 一、中断活动的过程 &&对于PIC单片机来说,一次中断的过程大致有下列阶段: 为了使得说明形象和直观,本文采用一些诙谐的语句来比喻说明: 中断请求---------比喻成申请买经济适用房的请求 中断标志-------一份申请书 本中断使能xxIE-----本单位领导 PEIE-------------户口办公室主任 GIE--------------银行的管理信贷的科长 &&1.&中断请求:房子太少,儿子要结婚了,得买房了,可资源和财力有限,不能卖商品房,&只好按特殊情况处理,写一份申请书(中断标志位IF置1); &&2.&本单位领导xxIE看了之后,&如果给你盖了一个戳:(即该中断使能位IE=1),那么恭喜你,这份申请书可以提交到更高一级的部门;如果没盖(xxIE=0),那么对不起,先放我这里吧,等我们研究研究好后再说。如果你不开心,要拿回申请书撕掉,呵呵,那么IF=0;你的购房请求之梦破灭; &&3.&xxIE领导将根据户口,将这些请求书给分类,一类是外地迁来的户口,提交给户口办公室PEIE主任审查,PEIE主任如果给你盖了个戳(PEIE=1),那么,他将会把申请书提交给银行的GIE科长批准,否则就是放在这里再研究研究或者你要回来撕毁;一类是本地户口,可直接提交给银行的GIE科长批准,然后你将申请书带到GIE科长的办公室。 &&4.&GIE科长盖了章之后(GIE=1),然后,你就可以拿着申请书去找房地产商要房子了(此时PC指针=0004H),因为GIE科长有很多事情要做,所以他每盖了一次戳之后(注意是一次不是一个,因为也许有多个中断同时发生,也就是说有其他地方的人来请GIE盖戳),就在办公室门外挂了个牌子:请勿打扰。他自己则休息去了,直到接到RETFIE的电话或者有人打他的手机。 &&5.&房地产商准备给房子了,不过你最好得先把各项手续给填好,叫5w押金,另外协议阿,合同阿,都得自己搞定,这叫“保护现场”。 &&6.&房地产商开始上班了,于是挨个查“申请书”是谁提交的,以便给你安排你预定的房子。这个叫“中断查询”。 &&7.&查到是你的后,然后打电话让你过来,带你去看房子,把钥匙给你。这个交“中断处理”。 &&8.&钥匙交给你之后,房子你是到手了,不过这份申请书就失效了,房地产商将该申请书销毁。这个叫“清除中断标志”。 &&9.&好啦,现在你可以去房地产商自己去要回以前交的押金,身份证啊等等。这个叫“恢复现场”。 &&10.&最后,房地产商办完了,让RETFIE小姐打个电话给GIE科长(执行RETFIE指令),GIE科长才起来,把“请勿打扰”的牌子取下,让其他的带着申请书的人进来。当然,如果你的事情还没搞定,GIE科长的关系户打了他的手机(你在办事时-处理中断时,若有GIE被置1),他也会开门取下“请勿打扰”的牌子,让关系户进来,给他盖好章。这下就对不起了,人家有关系,所以你的事情要马上停下来,先等关系户办完他的事情之后,再给你办你的事情。这个叫“中断嵌套”,要注意GIE科长有8个关系户(硬件堆栈的深度为8级)哦。 二、需要注意的问题: 1.&中断现场的保护(可以参考以前的帖子,在xieyubing版主的指点下,有恰当的例子); 2.&初次上电复位、电源跌落复位和其他情况下的复位,均使得全局中断位GIE和其他中断使能位xxIE=0; 3.&中断标志位的状态与该中断源是否被屏蔽无关,与全局中断使能位GIE也无关。 4.&当开放某一中断源时,该中断源就是通过中断标志向CPU申请中断的,无论什么原因,只要标志位IF置1(可以用软件强行置1),均会产生中断请求。 5.&当中断标志位为1,如果该中断被屏蔽或者被禁止了,只要不清除标志位,那么该中断请求会被潜伏下来,一旦屏蔽解除,立即产生中断响应。反之,如果在屏蔽/禁止条件解除之前清除了该标志位,那么则无中断请求。 6.&当CPU响应任一中断时,全局中断使能位GIE会自动清零;当中断返回时,它有自动置1。如果在中断处理期间,用软件将已经清零的GIE位又重新置位,这个时候若再出现中断请求,就可以形成了中断嵌套。即:在处理某一中断期间又响应了其他中断请求,就形成了中断嵌套,此时,前一中断处理过程会被暂停而进入新的中断处理,当新中断处理完毕后,才会继续处理前一个被搁置的中断。此方式可以形成多级嵌套,但不能超过硬件堆栈的深度8级,以免造成堆栈溢出而不能正常返回。 7.&如果同时发生多个中断请求,则中断处理的顺序取决于中断程序中的检查中断源的顺序。 8.&若要防止中断请求被丢失:则要注意下面两种情况:如果同一中断源的中断发生间隔时间大于该中断服务的处理时间,则可能出现中断事件被忽略(体现在中断服务的过程中,标志位被连续发生来两次置位),例如:中断事件发生的时间间隔为30ms,中断服务处理加上跳转判断的时间为50ms,则情况将会如下所示: &&&[中断次数----------1][中断次数----------2][中断次数----------3][中断次数----------4] &&&[处理次数------------------------1][处理次数------------------------2][处理次数------------------------4] 如果在中断处理一开始就清除IF,那么如上图所示,中断事件3、4&在处理次数2的过程中发生来两次,那么即使IF清除发生在中断次数3发生之前,也将丢失第三次中断。 另外,即使中断出现的时间间隔大于中断服务的时间间隔,如果清除中断标志位的指令安排在中断服务子程序的尾部,就有可能造成丢失该中断请求(即两次中断标志置位的事件只对应一条清除指令和一次中断处理。 9.&在进行查表操作时必须禁止CPU响应中断,以避免中断返回时跳转到不希望的地址上去。 三、一个疑惑 一个疑问:一些书上提到:如果对寄存器INTCON进行“读-改-写”操作的时候,要事先将GIE清0,再对INTCON进行操作,然后将GIE恢复为1 即BCF&INTCON,GIE &&BSF&INTCON,XX &&BSF&INTCON,GIE 所提到的理由是:当CPU正在执行一条对INTCON寄存器进行“读-改-写”操作的指令时,如果恰好发生了中断请求,则中断服务程序会被执行两次。这是因为当中断请求发生后INTCON寄存器的GIE寄存器会被硬件自动清零(屏蔽所有中断),并且程序转入中断例程入口(0004h)。当GIE被清零后,这时如果CPU正在执行一条对INTCON“读-改-写”的指令时,则GIE位还会被写会操作重新置1,这样就会造成CPU两次进入中断服务程序。 该段解释晦涩难懂,根据中断发生过程的时序(PICmicro中档单片机系列参考手册的第8-2页):在第n个指令周期里,CPU检测到IF标志位为1,则在n+1个周期内将自动使得GIE=0,该周期内既不取指也不执行指令,然后在n+2个指令周期里,0004h指针装入PC指针,该周期也不运行其他指令,只完成0004H-&(PC)的取指过程,第n+3个指令周期里,CPU执行0004h地址的指令码,并同时取0005h的指令码。 显然,作者提到的“当GIE被清零后,这时如果CPU正在执行一条对INTCON“读-改-写”的指令时,则GIE位还会被写会操作重新置1,这样就会造成CPU两次进入中断服务程序。”的解释存在下面的问题:GIE被硬件自动清零时的那个周期,是一个空运行周期,CPU并不执行指令,下一个周期也是空运行周期,不过是完成将0004h地址中的代码取指操作。然后就开始了0004h地址的代码的执行操作和0005h地址代码的取指过程。那么GIE在被硬件自动清零后要想置会1,只有两种方法:RETFIE指令使GIE自动置1;通过软件指令对GIE人为置1。显然,如果对GIE人为置1的指令执行在对该标志位清零前,那么会出现前文所述的中断嵌套(设该中断为A),如果没有其他中断发生且执行顺序先于中断A且对中断A的标志清零的话,那么中断A的嵌套是一个死循环。就不是执行两次的问题了----因为同一个中断嵌套时,GIE在自动清零被软件置一永远都发生在清除IF之前,那么IF一直得不到清除,而GIE又几乎一直都是1。 作者所说的情况似乎是这样的:读改写INTCON指令按如下过程分解:读INTCON的时候,GIE先是为1的,此时发生了中断,GIE被硬件清零,开始执行中断服务程序,然后再IF标志没有清除之前,执行INTCON的其他位的修改和写回操作,也将中断发生前的GIE读为1的信息写回GIE,这样,CPU被迫发生了第二次中断。显然,这样是将BSF&&INTCON,&XX指令分解得支离破碎---本来一个指令周期可以完成的指令被跨了多个指令周期;而且一个指令周期的指令被CPU在不同地址处分解执行读改写过程。 如果不是这样的话,那么作者的解释就自相矛盾:“当CPU正在执行一条对INTCON寄存器的‘读-改-写’操作的指令时,如果恰好发生了中断请求&&”与“当GIE被清零后,这是如果CPU正在执行一条对INTCON‘读-改-写’的指令时”相互矛盾。 总之,我对这里的理解存在一些疑惑,请斑竹及各位前辈指点。 *&-&本贴最后修改时间:&17:21:09&修改者:碧水长天&
?上一文章:
?下一文章:
& &评论摘要(共 0 条,得分 0 分,平均 0 分)
Copyright &
. All Rights Reserved .
页面执行时间:20,777.34000 毫秒51单片机自学教程(6)
我的图书馆
51单片机自学教程(6)
51单片机自学教程(6)
[日期: ]&[来源:net 作者:佚名]&[字体:
有关中断的概念
&& 什么是中断,在上一课中TCON的控制字低4位,我们没有讲,我们现在打个比方:你休息在家和几个朋友在打牌就“斗地主”吧,这时-----有人按了门铃了,电话铃响了,你烧的水开了….等等诸如此类的事件发生了,你咋办??哎!麻烦呐,开门、接电话、----,而打牌就暂时“中断”一下啦,而引起这次“中断”的事件我们把可以称之为中断源,中更有一些可以引起中断的事件了如:上一课讲到的定时器/计数器、单片机外接的设备向单片机请求如打印、显示等都能引起“中断”的发生,在MCS-51中一共有5个:两个外部中断、两个计数/定时器中断、一个串行口中断。
&&& 中断的嵌套与优先级处理:设想一下,我们正在“斗地主”,电话铃响了,同时又有人按了门铃,你该先做那样呢?如果你正是在等一个很重要的电话,你一般不会去理会门铃的,而反之,你正在等一个重要的客人,则可能就先去开门了。如果不是这两者(即不等电话,也不是等人上门),你可能会按你通常的习惯去处理。总之这里存在一个优先级的问题,中也是如此,也有优先级的问题。优先级的问题不仅仅发生在两个中断同时产生的情况,也发生在一个中断已产生,又有一个中断产生的情况,比如你正接电话,有人按门铃的情况,或你正开门与人交谈,又有电话响了情况。考虑一下?CPU也一样,所以MCS-51对此设置了中断优先级别控制寄存器IP,我们只要按设计要求设定每一个中断次序即可。
&& 中断的响应过程:我们正在“斗地主”,电话铃响了,在接电话之前我们必须先记住现在的出牌情况,然后去接电话(因为接完了,我们还要继续斗呢):电话铃响我们要到放电话的地方去,门铃响我们要到门那边去,也就是不同的中断,我们要在不同的地点处理,而这个地点通常事先是固定的。计算机中也是采用的这种方法,五个中断源,每个中断产生后都到一个固定的地方去找处理这个中断的程序(这就是在学习指令时编写程序时都要这样写“ORG 0000H,& AJMP MAIN;& ORG 0030H;00-30H之间就是中断的固定入口地址MAIN:。。。&&&& 。。。
&&& 当然在去之前首先要保存产生中断时程序正执行的地址”就是打牌时去接电话后该谁出牌“,以便处理完中断后回到原来的地方继续往下执行程序。而要中断返回只要一句指令”RETI“,具体地说,中断响应可以分为以下几个方面:
&对于的CPU 来说,其每一个机器周期都顺序地检查其自身的5个中断源,如有中断发生则激活相应的中断请求,但要让CPU响应中断还要做如下工作:
1。现行中断是否为最高级别的中断或CPU正在处理同级别的中断;
2。现行的机器周期不是所执行指令的最后一个机器周期;
3。如果CPU正在执行RETI(中断返回指令)、或执行访问中断控制寄存器IE、IP的指令,则CPU至少需要再执行一条指令,才能响应新的中断,这是规定。
CPU响应中断后将自动做如下工作:&1、保护断点,即保存下一要执行的指令的地址,就是把这个地址送入堆栈。& 2、寻找中断入口,根据5个不同的中断源所产生的中断,查找5个不同的入口地址。在这5个入口地址处存放有中断处理程序(这是程序编写时放在那儿的,如果没把中断程序放在那儿,就错了,中断程序就不能被执行到,即00H-30H之间)。
3、执行中断处理程序(如中断处理程序较长,大于七个语句即大于7条指令则要在相应的中断入口处用跳转指令如LJMP,执行完中断程序后,还要有”中断返回“就是从中断处返回到主程序,继续执行,指令为RETI语句。
究竟是怎么样找到中断程序所在位置,又怎么返回的呢?我们稍后再谈。
MCS-51中断系统的结构:
&&&& 与中断有关的特殊功能寄存器、中断入口、包括5个中断请求源,4个用于中断控制的寄存器IE、IP、TCON和SCON来控制中断的开、关和各种中断源的优先级确定。
中断请求源:
8031提供5个中断请求源,两个由/INT0、/INT1(P3.2和P3.3引脚)输入的外部中断请求,两个由片内的定时器/计数器溢出中断请求TF0、TF1,第五个为片内的串行口中断请求TI、RI所组成。
(1)外部中断请求源:即外中断INT0和INT1,经由外部引脚引入的,在上有两个引脚,名称为INT0、INT1,分别对应P3.2、P3.3这两个引脚。在内部的特殊功能寄存器TCON中的低四位是与外中断有关的,低4位 的4个中断标志的使用为MCS-51系列规定,方法如下:
IT0:为INT0外部引脚触发方式控制位,可由软件进行置位和清0,IT0=0时INT0为低电平触发方式,IT0=1,INT0为边沿触发方式,指INT0引脚上的电平发生由高到低的负跳变时CPU将产生中断。这两种方式的差异将在以后再谈。
IE0:外部INT0中断请求标志位。当有外部的中断请求时即INT0引脚电平发生突变时,这位就会置1(这由硬件来完成),在CPU响应中断后,由硬件将IE0清0。
IT1、IE1的用途和IT0、IE0相同。
(2)内部中断请求源
TF0:定时器计数器T0的溢出中断标记,当T0计数高位产生溢出时,由硬件置位TF0。当CPU响应中断后,再由硬件将TF0清0。
TF1:与TF0类似。
TI、RI:串行口发送、接收中断,特殊功能寄存器为SCON,在串口中再讲解。
2、中断允许寄存器IE
在MCS-51中断系统中,中断的允许或禁止是由片内可进行位寻址的8位中断允许特殊功能寄存器IE来控制的。见下表
其中EA是总开关,如果它等于0,则所有中断都不允许。
ES-串行口中断允许;ES=1,允许串行口中断,ES=0,禁止中断;
ET1-定时器1中断允许;ET1=1,允许中断
EX1-外中断1中断允许;EX1=1,允许中断
ET0-定时器0中断允许;ET0=1,允许中断
EX0-外中断0中断允许;EX0=1,允许中断
如:我们要设置允许外中断1,定时器1中断允许,其它不允许,则IE可如下表:
即8CH,如:用一句汇编语句MOV IE,#8CH;即可将设定完成。
当然,我们也可以用位操作指令
SETB EASETB ET1
来实现它。
3、五个中断源的默认优先级与中断服务入口地址(编程时不对特殊功能寄存器IP作任何设定时)
外中断0:0003H;
定时器0:000BH
外中断1:0013H
定时器1:001BH
串口 :0023H
它们的默认优先级由高外中断0到低(串口)的方式排列。
写到这里,大家应当明白,为什么前面有一些程序一始我们这样写:
LJMP& MAIN
这样写的目的,就是为了让出中断源所占用的入口地址。当然,在程序中没用中断时,直接从0000H开始写程序,在原理上并没有错,但在实际工作中最好不这样做。
优先级:初默认优先级外还可以在你需要时人工设置高、低优先级,即可以由程序员设定那些中断是高优先级、哪些中断是低优先级,由于只有两级,必有一些中断处于同一级别,处于同一级别的,就由单片机默认的优先级确定。
我们可以用指令对优先级进行设置。看表2
中断优先级中由中断优先级寄存器IP来设置的,IP中某位设为1,相应的中断就是高优先级,否则就是低优先级。
 PS---串行口中断优先级控制& PT1---定时器1中断优先级控制& PX1---外中断1优先级控制& PT0---定时0中断优先级控制& PX0---外中断0优先级控制
例:设有如下要求,将T0、外中断1设为高优先级,其它为低优先级,求IP的值。
IP的首3位没用,可任意取值,设为000,后面根据要求写就可以了
因此,最终,IP的值就是06H,(06H是如何得到的呢,这就有编码方式的问题,在二进制中,每4个二进制数为一组,8421方式,如:有二进制1010,第一位是1则它的值就是8,第二位是0,则她的值就是0,第三位是1,则就是2,第四位是0,则是0;网友可以发现和8421是对应的,则二进制数1010对应的16进制数为8+2=10,而在16进制数中A就表示10,所以1010转换为16进制为OAH;网友可读数制与编码)
例:在上例中,如果5个中断请求同时发生,求中断响应的次序。
响应次序为:定时器0->外中断1->外中断0->实时器1->串行中断。
2、中断响应过程
CPU响应中断时,首先把当前指令的下一条指令(就是中断返回后将要执行的指令)的地址送入堆栈,然后根据中断标记,将相应的中断入口地址送入PC,PC是程序指针,CPU取指令就根据PC中的值,PC中是什么值,就会到什么地方去取指令,所以程序就会转到中断入口处继续执行。这些工作都是由硬件自己来完成的,不必我们去考虑。这里还有个问题,大家是否注意到,每个中断向量地址只间隔了8个单元,如0003-000B,在如此少的空间中如何完成中断程序呢?很简单,你在中断处安排一个LJMP指令,不就可以把中断程序跳转到任何地方了吗?这在上面以讲到过。
下面给出完整的主程序供参考:
LJMP& MAIN;跳转到主程序MAIN
LJMP INT0 ;转外中断0处理子程序
RETI ;没有用定时器0中断,在此放一条RETI返回指令,万一 “不小心“产生了中断,则马上返回主程序。
AJMP INT1;转外中断1处理子程序
MAIN:MOV SP,#70H;设置堆栈栈顶,因CPU上电复位后SP 初始地址为07H,落在了工作寄存器区,易造成程序不稳定,所以要养成习惯重置SP的地址。。。。。
INT0:&& ;外中断0处理子程序段
PUSH ACC;保存累加器A中的数据PUSH PSW;保存程序状态字PSW中的各标志
POP ACC;还原ACC中的数据
RETI;外中断0处理子程序段,别的中断子程序同样添加即可。
END;END为程序结束语句,不可缺少。
&&& 从上例中可以发现中断程序完成后,有一条RETI返回指令,执行这条指令后,CPU将会把堆栈中保存着的地址取出,送回程序计数器PC,那么程序就会从主程序的中断处继续往下执行了。注意:CPU所做的保护工作是很有限的,只保护了一个地址,而其它的所有东西都不保护,所以如果你在主程序中用到了如A、PSW等,在中断程序中又要用它们的值,还要保证回到主程序后这里面的数据还是没执行中断以前的数据,就得自己保护起来,如上例INT0:子程序段。
利用定时器实现灯的闪烁
在学时我们第一个例子就是灯的闪烁,那是用延时程序做的,现在回想起来,这样做不很恰当,为什么呢?延时的时候CPU就不能再干其它的事了,这在实时性要求高的设备中是绝对不允许的,这时就必须用定时器来达到延时的目的,我们可以用定时器来实现LED的闪烁功能,让网友体会一下定时中断的作用。
例1:查询方式
MAIN:MOV SP,#70H;设置堆栈栈顶,因CPU上电复位后SP 初始地址为07H,落在了工作寄存器区,易造成程序不稳定,所以要养成习惯重置SP的地址。
MOV P1,#0FFH ;关所有 LED
MOV TMOD,#B ;定时/计数器0工作于方式1
MOV TH0,#15H
MOV TL0,#0A0H ;即数5536,初值的取得可参考“定时器一课”
SETB TR0 ;定时/计数器0开始运行
LOOP:&&& ;标号
JBC TF0,NEXT ;如果TF0等于1,则清TF0并转NEXT处
AJMP LOOP ;否则跳转到LOOP处运行
CPL P1.0;取反
MOV TH0,#15H
MOV TL0,#9FH;重置定时/计数器的初值
AJMP LOOP;返回、循环
 可以下载本站提供的全中文的编译软件MEDWIN,进入后单击文件菜单----新建----如ABC.asm(注意一定将文件的类型ASM写上(汇编的),后保存即可,键入程序,编译后生成.hex文件(烧写文件烧写到实验板看到了什么?灯在闪烁了,这可是用定时器做的,不再是主程序的循环了。简单地分析一下程序,为什么用JBC呢?TF0是定时/计数器0的溢出标记位,当定时器产生溢出后,该位由0变1,所以查询该位就可知定时时间是否已到。该位为1后,要用软件将标记位清0,以便下一次定时是间到时该位由0变1,所以用了JBC指令,该指位在判1转移的同时,还将该位清0。
&&& 以上程序是可以实现灯的闪烁了,可是主程序除了让灯闪烁外,还是不能做其他的事啊!不,不对,我们可以在LOOP:……和AJMP LOOP指令之间插入一些指令来做其他的事情,只要保证执行这些指令的时间少于定时时间就行了。那我们在用软件延时程序的时候不是也可以用一些指令来替代DJNZ吗?是的,但是那就要求你精确计算所用指令的时间,然后再减去相应的DJNZ循环次数,很不方便,而现在只要求所用指令的时间少于定时时间就行,显然要求低了。当然,这样的方法还是不好,所以我们常用以下的方法来实现。
程序2:用中断实现
ORG 000BH ;定时器0的中断向量地址
AJMP TIME0 ;跳转到真正的定时器程序处
MAIN:MOV SP,#70H;设置堆栈栈顶,因CPU上电复位后SP 初始地址为07H,落在了工作寄存器区,易造成程序不稳定,所以要养成习惯重置SP的地址。
MOV P1,#0FFH ;关所 灯
MOV TMOD,#B ;定时/计数器0工作于方式1
MOV TH0,#15H
MOV TL0,#0A0H ;即数5536
SETB EA ;开总中断允许
SETB ET0 ;开定时/计数器0允许
SETB TR0 ;定时/计数器0开始运行
AJMP LOOP ;循环等待定时中断的产生,真正工作时,这里可写任意程序
TIME0: ;定时器0的中断处理程序
PUSH PSW ;将PSW和ACC推入堆栈保护
MOV TH0,#15H
MOV TL0,#0A0H ;重置定时常数
上面的例子中,定时时间一到,TF0由0变1,就会引发中断,CPU将自动转至000B处寻找程序并执行,由于留给定时器中断的空间只有8个字节,显然不足以写下所有有中断处理程序,所以在000B处安排一条跳转指令,转到实际处理中断的程序处,这样,中断程序可以写在任意地方,也可以写任意长度了。进入定时中断后,首先要保存当前的一些状态,程序中只演示了保存存ACC和PSW,实际工作中应该根据需要将可能会改变的单元的值都推入堆栈进行保护(本程序中实际不需保存护任何值,这里只作个演示)。
上面的两个程序运行后,我们发现灯的闪烁非常快,根本分辨不出来,只是视觉上感到灯有些晃动而已,为什么呢?我们可以计算一下,定时器中预置的数是5536,所以每计60000个脉冲就是定时时间到,这60000个脉冲的时间是多少呢?我们的晶振是12M,所以就是60000微秒,即60毫秒,因此速度是非常快的。如果我想实现一个1S的定时,该怎么办呢?在该晶振濒率下,最长的定时也就是65.536个毫秒.咋办?很简单,只要对中断的次数进行计数即可,1秒18次就够了,请看下面给出一个例子。
ORG 000BH ;定时器0的中断向量地址
AJMP TIME0 ;跳转到真正的定时器程序处
ORG& 0030H
MAIN:MOV SP,#70H;设置堆栈栈顶,因CPU上电复位后SP 初始地址为07H,落在了工作寄存器区,易造成程序不稳定,所以要养成习惯重置SP的地址。
MOV P1,#0FFH ;关所 灯
MOV 30H,#00H ;假设用30H单元作中断计次的存储,先计数器预清0
MOV TMOD,#B ;定时/计数器0工作于方式1
MOV TH0,#3CH
MOV TL0,#0B0H ;即数15536
SETB EA ;开总中断允许
SETB ET0 ;开定时/计数器0允许
SETB TR0 ;定时/计数器0开始运行
LOOP: AJMP LOOP ;循环等待定时中断的产生,真正工作时,这里可写任意程序
TIME0: ;定时器0的中断处理程序
PUSH PSW ;将PSW和ACC推入堆栈保护
INC 30H& ;每中断一次计数器加1
CJNE A,#20,T_RET ;30H单元中的值到了20了吗?
CPL P1.0 ;到了,取反P10
MOV 30H,#0 ;清计数器
T_RET:& 计数未到20
MOV TH0,#15H
MOV TL0,#9FH ;重置定时常数50Ms
&&& 上例中先用定时/计数器0做一个50毫秒的定时器,定时是间到了以后并不是立即取反P10,而是将计数器中的值加1,如果计数器计到了20,就取反P1.0,并清掉计数器中的值重新计数,否则直接返回,这样,就变成了20次定时中断才取反一次P10,因此定时时间就延长了成了20*50即1000毫秒了-----1秒了吗。
这个思路在工程中是非常有用的,有的时候我们需要若干个定时器,可51中总共才有2个,怎么办呢?其实,只要这几个定时的时间有一定的公约数,我们就可以用软件计数加以实现,如我要实现P10口所接灯按1S每次,而P11口所接灯按2S每次闪烁,怎么实现呢?对了我们用两个计数器,一个在它计到20时,取反P10,并清零,就如上面所示,另一个计到40取反P11,然后清0,不就行了吗?这部份的程序如下
ORG 000BH ;定时器0的中断向量地址
AJMP TIME0 ;跳转到真正的定时器程序处
MAIN:MOV SP,#70H;设置堆栈栈顶,因CPU上电复位后SP 初始地址为07H,落在了工作寄存器区,易造成程序不稳定,所以要养成习惯重置SP的地址。
MOV P1,#0FFH ;关 LED
MOV 30H,#00H ;软件计数器预清0MOV 31H,#00H;
MOV TMOD,#B ;定时/计数器0工作于方式1
MOV TH0,#3CH
MOV TL0,#0B0H ;即数15536/ 50MS
SETB EA ;开总中断允许
SETB ET0 ;开定时/计数器0允许
SETB TR0 ;定时/计数器0开始运行
LOOP: AJMP LOOP ;真正工作时,这里可写任意程序
TIME0: ;定时器0的中断处理程序
PUSH PSW ;将PSW和ACC推入堆栈保护
INC 31H ;两个计数器都加1
CJNE A,#20,T_NEXT ;30H单元中的值到了20了吗?
&CPL P1.0 ;到了,取反P10
MOV 30H,#0 ;清软件计数器
CJNE A,#40,T_RET ;31h单元中的值到40了吗?
MOV 31H,#0 ;到了,取反P11,清计数器,返回
MOV TH0,#15H
MOV TL0,#9FH ;重置定时常数
TA的最新馆藏[转]&[转]&[转]&[转]&[转]&[转]&
喜欢该文的人也喜欢

我要回帖

更多关于 凯立德主程序 的文章

 

随机推荐