实验参考: 笨笨工作室-实验九、流水灯花样变换(中断)。(查看)实验板: 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 0020hstart: 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 passk2_check: cjne a, #0dh, k3_check ; 不是k2, 判断是不是k3 mov r0, #02h ; 是k2, 置标志为02 ajmp passk3_check: cjne a, #0bh, k4_check ; 不是k3, 判断是不是k4 mov r0, #03h ; 是k3, 置标志为03 ajmp passk4_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, #0fehl_loop: mov r1, a ; r1保存现在亮点位置,做样式变换时从该处开始 mov p0, a lcall del100ms rl a djnz r7, l_loop mov a, #0bfhr_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, #20temp1: mov r4, #248 djnz r4, $ djnz r5, temp1 ret del100ms: mov r3, #0c3h ;100.036mstemp2: mov r2, #0ffh ;511us djnz r2, $ djnz r3, temp2 ret end 用Proteus仿真通过,原理图如下: 实验结果: 下载到板上测试, 结果与预计相符。

评论