实验参考: 笨笨工作室-实验七、中断方式按键。(查看)
实验板: FB51A。(查看)
实验目的: <1> 掌握中断方式响应按键的原理。
<2> 掌握中断服务程序的具体编写:如何进行键的识别,如何去抖动。
实验现象: 最右面的数码管初始显示0,每次按下外部按键K1执行加一,计数到9时重新回0。
单片机响应外部按键的方式有两种,一种是查询方式,一种是中断方式。
查询方式:单片机不断的查询是否有按键按下,如果有按键按下的话,就执行相应的程序,否则继续查询。
中断方式:单片机处理自己的工作,如果有按键按下,向单片机发出中断请求。单片机停下现在正在处理的工作,转去执行中断程序,执行之后回来继续刚才的工作。
关于查询方式实现上述过程参见【013】查询方式按键。当单片机工作于查询方式的时,要不间断的对外部按键进行查询,其间单片机不能干其他的任何工作,CPU的大量时间可能会浪费在原地踏步的查询操作上。为进一步提高单片机的工作效率,这里采用中断方式。其过程为:单片机执行主体程序,如果有按键按下,向单片机发出中断请求,单片机就会停下现在正在处理的工作,转去执行中断处理程序,执行完后回来继续刚才的工作;如果没有按键按下,单片机就作自己的工作,不理睬外部键盘。
这里又涉及到了中断源的概念,中断源用于发出中断请求。MCS-51单片机的中断系统有5个中断请求源:2个外部中断请求INT0和INT1,2个片内定时/计数器T0和T1的计满溢出中断,还有一个是片内串行口中断请求TI或者RI。在本试验中,用外部中断INT1。
显示部分电路图:
键盘部分电路:
由图可以看到, 当任何一个按键按下的时候,P3.3引脚,即INT1上就会出现一个低电平,向单片机发出中断申请。如果单片机开放了外部中断,就响应中断请求,进入中断服务程序。单片机中断是否开放由特殊功能寄存器IE控制。在单片机内部256字节的数据RAM的高128字节(80h~ffh)是特殊功能寄存器区。PSW在这个区域,IE也在这个区域,叫做“中断允许寄存器”,专门负责程序是否响应中断的,IE的字节地址为A8H,可进行位寻址。各位功能说明如下:
D7 D6 D5 D4 D3 D2 D1 D0
┌────┬──┬─┬─┬──┬──┬──┬──┬──┐
ㄧ IE ㄧEA ㄧ ㄧ ㄧES ㄧET1 ㄧEX1 ㄧET0 ㄧEX0 ㄧ A8H
├────┼──┼─┼─┼──┼──┼──┼──┼──┤
ㄧ 位地址 ㄧAFH ㄧ ㄧ ㄧACH ㄧABH ㄧAAH ㄧA9H ㄧA8H ㄧ
└────┴──┴─┴─┴──┴──┴──┴──┴──┘
(1) EA : 中断允许总控制位
EA=0, CPU屏蔽所有的中断请求(CPU关中断);
EA=1, CPU开放所有中断(CPU开中断)。
(2) ES : 串行口中断允许位
ES=0, 禁止串行口中断;
ES=1, 允许串行口中断。
(3) ET1 : 定时器/计数器T1的溢出中断允许位
ET1=0, 禁止T1溢出中断;
ET1=1, 允许T1溢出中断。
(4) EX1 : 外部中断1允许位
EX1=0, 禁止外部中断1中断;
EX1=1, 允许外部中断1中断。
(5) ET0 : 定时器/计数器T0的溢出中断允许位
ET0=0, 禁止T0溢出中断;
ET0=1, 允许T0溢出中断。
(6) EX0 : 外部中断0中断溢出允许位
EX0=0, 禁止外部中断0中断;
EX0=1, 允许外部中断0中断。
MCS-51复位后,IE被清0,所有的中断请求被禁止。
四个按键中任何一个按下,都会发出中断请求。而如何判断中断请求是由那个按键发出的就是中断服务程序的工作了。在中断服务程序中,需要完成的工作:键识别、去抖动、和键功能处理。
键识别的思路:
(1)、先把P1口的状态读入a寄存器,然后把高四位屏蔽掉。
(2)、判断是否k1按键按下,(即判断a中的数是否00001101),如果是就调用延时程序去抖,否则,表示不是K1按下,退出中断返回主程序。
(3)、调用延时程序后,重复上面的(1)(2)步。如果确定k1按下,转中断服务程序,否则就是抖动,退出中断返回主程序。
另外,在进入中断服务程序之后,首先应该关闭中断。在中断服务程序返回主程序之前,再把中断打开,否刚可能会引起混乱。
程序如下:
org 0000h
ljmp start
org 0013h
ljmp ext1
org 0030h
start: ; 主程序开始
mov r7,#0ffh
setb ea ; cpu开中断
setb ex1 ; 允许外部中断1
setb it1 ; 设置外部中断1触发方式为跳变触发
lcall dis_0 ; 调用初始状态显示子程序
ajmp $ ; 等待按键发出中断申请
ext1: clr ea ; 进入中断,先关闭中断
lcall key_reader ; 调用键识别子程序
pass: setb ea ; 返回主程序之前先开中断
reti ; 中断返回指令,
key_reader:
mov a,p1 ; 读入P1口的状态
anl a,#0fh ; 屏蔽高四位
cjne a,#0dh,pass ; 如果a的内容不是00001101(不是k1按下),就退出中断
lcall del10ms ; 否则,表示k1按下,调用10ms延时去抖
mov a,p1 ; 再次读入p1口的内容
anl a,#0fh ; 屏蔽高四位
cjne a,#0dh,pass ; 如果a的内容不是00001101,就是抖动,退出中断
lcall dis_key ; 否则,确定按键按下,转数码显示程序
ret
dis_0: mov a,#48h ; 让最右面的数码管显示0的子程序
mov p0,a
mov p2,#01h;
ret
dis_key: inc r7 ; 查表求段码,然后送到P0口的子程序
mov a,r7
mov dptr,#tab
movc a,@a+dptr
mov p0,a
mov p2,#01h
cjne a,#48h,next ; 如果没有显示到最后一个数字0,就继续查表显示
mov r7,#0ffh ; 否则,重新从表头开始显示
next: ret
del10ms: ; 10ms延时子程序(12M)
mov r6, #20 ; 2机器周期
temp: mov r5, #248 ; 2机器周期
djnz r5, $ ; 2机器周期 2+2×248=498
djnz r6, temp ; 2机器周期 2×20=40
ret ; 2+20×498+40=10002 即10ms
tab: db 0ebh,52h,62h,0e1h,64h,44h,0eah,40h,60h,48h ;存放0~9的段码表
end
主程序之所以从0030H开始,是因为不同类型的中断,具有不同的中断入口地址,CPU在响应中断的时候,会根据中断源的类别,转到相应的入口去执行中断服务程序。外部中断1的入口地址是0013h,cpu在响应了外部中断1后,会自动的到这个地址来,从这个地址开始往下执行程序。所以我们要把前面的一段空出来,以免覆盖这个地址。51单片机的5种中断源的中断入口地址如下:
┌─────────┬──────┐
ㄧ 中断源 ㄧ 入口地址 ㄧ
├─────────┼──────┤
ㄧ 外部中断0(INT0_) ㄧ 0003H ㄧ
├─────────┼──────┤
ㄧ 定时器0(T0) ㄧ 000BH ㄧ
├─────────┼──────┤
ㄧ 外部中断1(INT1_) ㄧ 0013H ㄧ
├─────────┼──────┤
ㄧ 定时器1(T1) ㄧ 001BH ㄧ
├─────────┼──────┤
ㄧ 串行口 ㄧ 0023H ㄧ
└─────────┴──────┘
每两个中断入口间隔8个单元,装不下中断服务子程序,通常在这些中断入口地址处都放一条绝对跳转指令指向中断服务子程序。
程序中的it1是外部中断触发方式控制位,为1的时候选择跳变方式触发,为0的时候选择电平方式触发。it1是tcon寄存器其中的一位,tcon和psw,ie一样,也是一个特殊功能寄存器。TCON是定时器/计数器(T0,T1)的控制寄存器,它的各位的功能说明如下:
D7 D6 D5 D4 D3 D2 D1 D0
┌────┬──┬──┬──┬──┬──┬──┬──┬──┐
ㄧ TCON ㄧTF1 ㄧTR1 ㄧTF0 ㄧTR0 ㄧIE1 ㄧIT1 ㄧIE0 ㄧIT0 ㄧ 88H
├────┼──┼──┼──┼──┼──┼──┼──┼──┤
ㄧ 位地址 ㄧ8FH ㄧ ㄧ8DH ㄧ ㄧ8BH ㄧ8AH ㄧ89H ㄧ88H ㄧ
└────┴──┴──┴──┴──┴──┴──┴──┴──┘
<l> TF1:定时器/计数器(T1)的溢出中断标志,当T1产生溢出试,由硬件置1,CPU响应中断后,由硬件置0;功能和TF0类似。
<2> TR1:置1时启动定时/计数器,置0时停止定时/计数器;和TR0类似。
<3> IE1:外部中断1请求标志。当它置1的时候,请求中断。
<4> IT1:外部中断1触发方式控制位。如果IT1是1,则外部中断为跳变方式触发,否则,为电平方式触发。
<5> IE0:外部中断0请求标志,含义同IE1。
<6> IT0:外部中断0触发方式控制位,含义同IT1。
下载到板上实测,得到预测结果。Proteus仿真时却与实测不一致,实没如果按住K1不放,数码管显示不变,而仿真时按住K1数码管显示是不断循环变化的,不知为何。下面是用Proteus做的演示(注:由于此Blog空间图片上传要求在100K以内,所以只模拟了0到3的循环,而实际上是从0到9循环的。在此仅作为模拟演示):
评论