微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 单片机学习之十二:按键控制跑马灯(中断)

单片机学习之十二:按键控制跑马灯(中断)

时间:11-18 来源:互联网 点击:
一、实验现象:

二极管作左右跑马灯,当按下外部按键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,#0c8h ;延时100ms子程序

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top