一、实验现象:
二极管作左右跑马灯,当按下外部按键K0时,8个二极管悉数闪耀5次后从K0按下之前的方位持续作跑马灯。
二、实验意图
把握仓库在中止程序中的效果
把握让程序维护现场的办法
三、实验任务分析:
有了曾经各个实验的经历,信任这个实验对咱们来说,难度不是很大。咱们仅有接触到的新的知识点是:让程序从回来中止之前的方位持续履行跑马灯,那么怎么能够让程序在进入中止之前记住其时所在的方位,在履行中止之后,能够回来这个当地持续往下履行呢?
咱们能够这样作:在进入中止之前,把该时间的程序信息放到一个当地保存下来,在回来中止之前,再到这个当地把咱们寄存的程序信息取出来。这样不就能够从进入中止的方位开端从头履行程序了吗?那么,这个暂存数据的当地在哪里呢?
单片机给咱们考虑的很周到,答应咱们从内部RAM中指定一个空间专门来作这个作业,这个空间便是仓库。而且单片机还专门给了咱们一个8位的仓库指针,让咱们用它来拓荒仓库空间。(为什么是8位呢?因为内部RAM的地址空间是256字节,所以8位就满足拉。)
例如:假设咱们给仓库指针赋值:mov sp,#70h,就表明咱们把内部数据RAM的地址为70h开端的单元设为仓库啦。
那么,咱们一般把内部数据RAM的那些当地作为仓库呢?让咱们来温习一下内部RAM的结构吧。
前面咱们现已说过,内部RAM共有256字节,分为两组。还记得它们各自的功用吗?高128字节是特别功用寄存器区,咱们没有办法运用,那就打低128字节的主见吧。咱们再来看看低128字节的RAM空间分配。
咱们发现在低128字节中,作业寄存器区和位寻址区的地址现已分配好了,咱们能够运用的只要30h~7fh的数据缓冲区了。所以咱们的仓库指针只能设在这个区域,从30h今后的规模为宜。在该程序中,咱们把仓库设在70h的方位。
好啦,知道仓库设在哪里,下面咱们就要考虑怎么把程序运转的相关信息放入仓库拉。那么,程序运转的相关信息在哪里呢?
因为在主程序中,咱们让程序作左右跑马灯。还记得实验三吗,咱们的左右跑马灯是经过把寄存器a中的数,经过进位标志CY(程序状态字PSW的最高位),进行左右环移来完结的。一起,因为寄存器a是单片机中最最常用的寄存器,咱们在中止程序中也要用到它。为了防止中止程序改动寄存器a的值,所以咱们在中止服务程序开端之前,把a的值放到仓库中保存起来。相同咱们也要把psw的值也保存起来。在回来主程序之前,再把它们取出来,这样就能够使得程序从进入中止之前的方位开端,持续作跑马灯。
把数据存入仓库和从仓库中取出,是经过仓库操作指令完结的。
例如:假如想把a中的数据存入仓库,就:push acc;假如想把a的内容从仓库中取出,就:pop acc。(一般称之为:压入,弹出)。
还需要阐明一点的是:仓库中的数据是选用“后进先出”的结构方法处理的。就像咱们摞盘子相同,最终摞进去的盘子,获得时分是最早取出的。所以咱们压入数据后,再弹出的时分要特别留意次序,后压入的要先弹出,不要弄错啦。
现在来看看这个实验的程序吧。
四、实验程序如下:
org 0000h
ljmp start
org 0013h
ljmp ext1
org 0020h
start: clr p1.5 ;防止蜂鸣器响
setb ea ;CPU开中止
setb ex1 ;答应外部中止1请求中止
setb it1 ;设置外部中止1跳变方法触发
mov sp,#70h ;设置仓库进口
loop1: lcall light1 ;调用左右跑马灯子程序
ljmp loop1
;以下是中止服务程序
ext1: clr ea ;封闭CPU中止
push acc ;把寄存器a的内容压入仓库
push psw ;把程序状态字压入仓库
lcall keyreader ;调用键辨认子程序
pass: pop psw ;康复现场,留意次序,要先弹出程序状态字
pop acc ;弹出寄存器a的内容,
setb ea ;CPU开中止
reti ;中止回来
light1: mov a,#0ffh ;light1是左右跑马灯子程序,咱们能够参阅实验三的内容
clr c
mov r7,#08h
lloop: rlc a
mov p0,a
lcall del100ms
djnz r7,lloop
mov r6,#06h
rloop: rrc a
mov p0,a
lcall del100ms
djnz r6,rloop
ret
keyreader: mov a,p1 ;keyreader是键辨认子程序,咱们能够参阅实验7
anl a,#0fh
cjne a,#0dh,pass
lcall del10ms
mov a,p1
anl a,#0fh
cjne a,#0dh,pass
lcall light2 ;假如确认K0按键按下,调用灯火闪耀子程序
ret
light2: mov a,#00h ;light2是让灯火闪耀5次的子程序
mov r5,#10
loop2: mov p0,a
call del10ms
cpl a ;把a寄存器中的数据取反
djnz r5,loop2;
ret
del10ms: mov r4,#15h ;延时10ms子程序
del1: mov r3,#0ffh
del2: djnz r3,del3
djnz r4,del1
ret;
del100ms:mov r2,#
del3: mov r1,#0ffh
del4: djnz r1,del4
djnz r2,del3
ret
end
咱们把这个程序下载到学习板上看看,会发现每次按下按键的时分,程序进入中止后,在回来的时分,会回到那个方位持续开端左右循环。这便是因为咱们在进入中止的时分维护了现场的原因。
五、几点阐明
主程序是左右跑马灯,其间用到了r7,r6寄存器,还调用了100ms延时,所以也用到了r2,r1寄存器。所以咱们要特别留意,在中止服务程序中,要防止运用这几个寄存器。不然,就会导致在中止程序中,修改了r寄存器的内容,导致回来主程序的时分出现问题。
在中止服务程序中,用到了10ms延时程序,这个延时程序运用的寄存器是r4,r3。别的,还调用了light2子程序,其间用到了r5寄存器。所以。主程序和中止服务程序用到的寄存器r就没有抵触。
那么假如因为条件的约束,使得主程序和中止程序的寄存器的数量较多,一组8个寄存器不行,该怎么办呢?
咱们也能够象维护a寄存器相同,在进入中止之后,首先把某一个在中止服务程序中也要用到的r寄存器的内容压入仓库,在退出中止之前再弹出来。
或许咱们就从头挑选寄存器区吧,因为咱们缺省运用的是0区的寄存器组,所以咱们就改动psw程序状态字中的rs1和rs0,就能够换别的的一组寄存器区了。例如,咱们在进入中止服务程序之后,写这样的两条指令:
clr rs1
setb rs0
这样,咱们就用了1区的8个寄存器,这样就没有问题啦。