实验参考: 笨笨工作室-实验九、流水灯花样变换(中断)。(查看)
实验板: FB51A。(查看)
实验目的: 掌握在中断程序中处理多个按键动作的响应方法。
实验现象: 进入程序后,程序作双向流水灯;按下k1键,程序作左向流水灯; 按下k2按键程序作右向流水灯; 按下k3键两个亮点从两边向中间移动; 按下k3键两个亮点从中间向两边移动。
在上个实验(016中断的应用中对断点的保护)中,只用了一个按键触发中断, 而本次实验中断程序要对多个按键动作进行响应, 灯光变换的花样有4种,用4个按键k1,k2,k3,k4切换。
显示部分电路:
键盘部分电路(图中K0对应程序中K1……K3对应K4):
思路:主程序中执行左右流水灯,在中断服务程序中,首先读取按键状态,然后延时10ms,再次读取按键状态。把两次获得的按键状态比较,如果不同,就表示是抖动,退出中断;否则,就去判断是哪个按键按下。如果是k1,就执行左跑马灯;如果是k2,就执行右跑马灯;如果是k3,就执行亮点向中间移动;如果是k4,就执行亮点向两边移动。
值得注意的是: 在中断服务程序中,应该尽量的使得任务简化,不要让中断服务程序作过多复杂的任务,而要尽量把这些复杂的任务放到主程序中间去完成。
本着这一原则, 可以采用置标志位的方法。即在主程序中设定一个标志位,不断的对这个标志进行查询:如果是标志为状态1,就执行双向跑马灯;如果是状态2,就执行左向跑马灯;如果是状态3,就执行右向跑马灯,依次类推。而在中断服务程序中,只需要进行如下工作:去抖动,键识别,改变标志位。
这里我们用寄存器r0的内容作为标志,当它里面的内容是0ffh时,执行左右跑马灯程序;为01h时,执行左跑马灯;02h时执行右跑马灯;03h时执行两个亮点向中间移动;04h时执行两个亮点象两边移动。
下面是主程序和中断程序的流程图
程序如下:
org 0000h
ljmp start
org 0003h
ljmp ext1
org 0020h
start: mov r0, #0ffh ; 对r0赋值,r0为所设标志位
setb ea ; 开中断
setb ex0 ; 允许外部中断0申请中断
setb it0 ; 外部中断0为跳变方式触发
mov sp, #70h ; 设置中断
loop0: cjne r0, #0ffh, loop1 ; r0不为ff, 转到loop1
ajmp main_light ; 否则执行左右流水灯
loop1: cjne r0, #01h, loop2 ; r0不为01, 转到loop2
ajmp k1_light ; 否则执行左向流水灯
loop2: cjne r0, #02h, loop3 ; r0不为02, 转到loop3
ajmp K2_light ; 否则执行右向流水灯
loop3: cjne r0, #03h, loop4 ; r0不为03, 转到loop4
ajmp k3_light ; 否则执行双亮点向中间移动
loop4: cjne r0, #04h, loop5 ; r0不为04, 转到loop5
ajmp k4_light ; 否则执行双亮点向两边移动
loop5: ajmp loop0 ; 返回重新查询
;===========================中断服务程序===========================
ext1: clr ea ; 关中断
push acc
push psw
mov a, p1 ; 读入键值
anl a, #0fh ; 屏蔽高四位
mov 30h, a ; 键状态存入30h
lcall del10ms
mov a, p1 ; 再次读入键值
anl a, #0fh
cjne a, 30h, pass ; 两次键值不同,是抖动,退出中断
ajmp k1_check ; 如果相等,进行键识别
; 键识别部分
k1_check: cjne a, #0eh, k2_check ; 不是k1, 判断是不是k2
mov r0, #01h ; 是k1, 置标志为01
ajmp pass
k2_check: cjne a, #0dh, k3_check ; 不是k2, 判断是不是k3
mov r0, #02h ; 是k2, 置标志为02
ajmp pass
k3_check: cjne a, #0bh, k4_check ; 不是k3, 判断是不是k4
mov r0, #03h ; 是k3, 置标志为03
ajmp pass
k4_check: cjne a, #07h, pass ; 不是k4, 退出中断
mov r0, #04h ; 是k4, 置标志为04
ajmp pass
pass: pop psw ; 现场恢复
pop acc
setb ea ; 开中断
reti ; 中断返回
;======================================================================
main_light: mov r7, #08h ; 左右流水灯程序
mov r6, #06h
mov a, #0feh
l_loop: mov r1, a ; r1保存现在亮点位置,做样式变换时从该处开始
mov p0, a
lcall del100ms
rl a
djnz r7, l_loop
mov a, #0bfh
r_loop: mov r1, a
mov p0, a
lcall del100ms
rr a
djnz r6, r_loop
ajmp loop0
k1_light: mov r1, a ; 左向流水灯
mov p0, a
lcall del100ms
rl a
mov r1, a
ajmp loop0
k2_light: mov r1, a ; 右向流水灯
mov p0, a
lcall del100ms
rr a
mov r1, a
ajmp loop0
k3_light: mov p0, #07eh ; 双亮点向中间移
lcall del100ms
mov p0, #0bdh
lcall del100ms
mov p0, #0dbh
lcall del100ms
mov p0, #0e7h
lcall del100ms
ajmp loop0
k4_light: mov p0, #0e7h ; 双亮点向两边移
lcall del100ms
mov p0, #0dbh
lcall del100ms
mov p0, #0bdh
lcall del100ms
mov p0, #07eh
lcall del100ms
ajmp loop0
del10ms: ; 10ms延时子程序(12M)
mov r5, #20
temp1: mov r4, #248
djnz r4, $
djnz r5, temp1
ret
del100ms: mov r3, #0c3h ;100.036ms
temp2: mov r2, #0ffh ;511us
djnz r2, $
djnz r3, temp2
ret
end
用Proteus仿真通过,原理图如下:
实验结果: 下载到板上测试, 结果与预计相符。
评论