电工电子实验教学中心 艾庆生
“中断”是计算机技术里一个非常重要的内容,可以说,没有中断就没有计算机;也可以说,没有中断,计算机就不能“同时”做多件事情。关于中断的概念及原理等,请参见教科书。
下面简单地对51单片机的中断系统作一个归纳总结。
一、51单片机的中断系统 1.中断系统框图
可归纳为“五个中断源、六个中断标志、两级中断开关、两级中断优先权”。 2.中断矢量
工程师们在设计51单片机的5个中断源时,也为这5个中断源确定了各自的矢量位置。见下表。
中断源 外部0 定时/计数器0 外部1
1
中断矢量 0003H 000BH 0013H 定时/计数器1 串口 3.与中断有关的SFR 专用寄存器名称 定时/计数器控制 TCON 88H 符号 地址 D7 D6 D5 D4 001BH 0023H 位地址与位名称 D3 IE1 8BH D2 IT1 8AH D1 IE0 89H D0 IT0 88H TF1 TR1 TF0 TR0 8FH 8EH 8DH 8CH 串行控制 SCON 中断允许控制 中断优先级控制
二、中断实验
IP IE 98H SM0 SM1 SM2 REN TB8 9FH 9EH 9DH 9CH 9BH RB8 9AH TI 99H RI 98H A8H EA AFH - - ES ACH ET1 ABH EX1 ET0 EX0 AAH A9H A8H B8H - - - PS BCH PT1 BBH PX1 BAH PT0 PX0 B9H B8H 1.定时/计数器中断实验1 实验一:定时实验。
P0口发光管交叉闪亮(闪亮速率由定时器定时并通过中断实现)。 分析:主程序只需做好初始化的工作即可,在周期性执行的中断子程序里改变P0口的发光管状态,实现交叉闪亮。
;*********************************************************** Org 0000H Ljmp main Org 000BH Ljmp T0_int ;主程序
Org 0030H
Main: Mov tmod,#00000001B ;选用T0,定时,方式1 Setb et0 ;开T0单级中断
2
Setb ea ;开总中断 Setb tr0 ;启动T0
Mov p0,#01010101B ;P0口发光管交叉亮
NextStep: sjmp NextStep ;此处代表主程序去忙其它事了。 ;定时器中断子程序
T0_int: mov a,p0 ;读入P0口内容 Cpl a ;将各位取反
Mov p0,a ;再送回P0口,实现交叉点亮 Reti End ;思考题:
;1)。此实验发光管闪亮间隔约为65.5ms,若定闪亮间隔为30ms,应怎样修改? ;2)。若想实现长延时,如1S、10S、1分、1小时等,应如何编程? ;参考定时器中断子程序(1S) T0_int: Mov th0,#3ch
Mov tl0,#0b0h ;预置常数15536,实现50ms定时 Inc r7
Cjne r7,#20,T0_end ;不够1秒退出
Mov r7,#0 ;够1秒将r7清0,为下一秒做准备
Mov a,p0 ;读入P0口内容
Cpl a ;将各位取反
Mov p0,a ;再送回P0口,实现交叉点亮 T0_end: Reti End
;**************************************************************** 2.定时/计数器中断实验2 实验二:计数实验
T0的计数脚P3.4接有一开关模拟计数输入,单片机应随时将输入情况通过P0口显示出来,当输入满100个数时,单片机声音提示。同时继续下一次的计
3
数,循环往复。
分析:由于只计100个数,可选方式2,自动重新装载方式,预置常数156;在主程序里做完初始化工作后,可以不断地读取TL0的值并送P0口显示;而在中断子程序里启动声音提示(最好2秒后关闭声音提示)。
;**************************************************************** Org 0000H Ljmp main
Org 000BH ;T0的中断矢量 Ljmp T0_int Org 001BH
Ljmp T1_int ;T1的中断矢量 ;主程序
Org 0030H
Main: Mov tmod,#00010110B ;选用T0,计数,方式2
;选用T1,定时,方式1
Mov th0,#156
Mov tl0,#156 ;为T0预置初始值156 Mov th1,#3cH
Mov tl1,#0b0H ;为T1预置初始值15536 Setb et0 ;开启T0中断 Setb ea ;开总中断 Setb tr0 ;启动T0计数
Loop: Mov a,tl0 ;读取T0的计数值,送A寄存器 Mov P0,a ;再送P0口显示 Sjmp Loop
;**************************************************************** ;T0中断子程序,完成声音提示,开T1中断启动2秒定时 T0_int: Setb et1 ;开启T1中断 Setb tr1 ;启动T1定时器
4
Clr p1.4 ;开启声音提示 Mov r7,#0 ;设置2秒定时的计数器 Reti
;**************************************************************** ;T1中断子程序,完成2秒钟声音的短促发声后关闭T1中断 T1_int: Mov th1,#3cH
Mov tl1,#0b0H ;为T1预置初始值15536 Cpl p1.4 ;使声音短促发声,周期100ms Inc r7
Cjne r7,#40,T1_end ;够2秒了吗?(40次中断是2秒) Setb p1.4 ;停止声音 Clr et1 ;关闭T1中断 T1_end: Reti
;**************************************************************** 3.外部中断扩展实验
如图可知,在我们的实验板上有4个简单按键,当把短路帽短路JMP1的1-2脚时,可做外部中断1的扩展实验。
设这4个按键为4个不同地方的防盗装置,按下按键模拟盗情发生。编程序
5
当盗情发生时,用P0口指示哪个地方发生了盗情,并声音报警。
分析:当任意地方的盗情发生时,都会通过D1-D4拉低P3.3脚,申请外部1中断。在外部1的中断子程序里,识别盗情发生地送P0口显示。 ;**************************************************************** ;外部中断1扩展实验 Org 0000H Ljmp main Org 0013H Ljmp X1_int ;主程序
Org 0030H
Main: Mov P0,#0 ;关P0口所有发光管 Mov P3,#0ffH
Setb it1 ;设置外部1中断为下降沿触发 Setb ex1 ;开外部1中断 Setb ea ;开总中断
Sjmp $ ;此处代表主程序去做其它事情了。 ;外部1中断子程序
X1_int: Mov a,P3 ;获取防盗装置的情况
Cpl a ;为送P0口做准备(反相的缘故) Mov P0,a
Clr P1.4 ;声音报警 Reti
;注:以上程序未考虑盗情的解除问题,在做实验时可按复位键重新开始,注意观察P0口的灯亮情况,表示不同的盗情地点。
;思考题:1。若用数码管显示不同的盗情地点,如何编程?
; 2。若声光报警信号只需30秒,然后自动解除,如何编程? ;****************************************************************
6
三、中断的应用
1. 简易方波发生器和数字频率计
;********************************************************* ; ******************* 数字频率计程序 ****************
;任务:利用定时器T0定时,产生2KHz方波,从P3.6脚输出; ;此方波还送P3.5脚(T1的计数脚),以便T1进行计数; ; T0还产生1秒定时,不断地打开和关闭T1计数器, ;并将读取到的频率值送数码管显示。
;分析:2KHz方波,设占空比为50%,则高低电平的时间各为250uS, ;可用T0定时,选方式2,自动重新装载初始值。T1计数,方式1。
;硬件上,将P3.6脚与P3.5脚相连(注意从排针上相连,用短路帽)即可。
org 0000h ljmp main
;********************************************************* org 000bh
ljmp t0_int
;********************************************************* ;主程序
org 0030h main: mov p0,#0 mov p1,#0ffh
mov p3,#0ffh mov r3,#0 mov r4,#0
;r3-r4组成1秒计数器
;初始化,关闭所有发光管
mov tmod,#01010010B ;T1计数,方式1;
7
;T0定时,方式2。 mov th0,#6 mov tl0,#6 mov th1,#0 mov tl1,#0 setb et0 setb ea setb tr0
;开T0中断 ;启动定时器T0
;预置初始值6,准备计数250
main_disp: lcall smg_disp ajmp main_disp
;********************************************************* ;数码管显示4位子程序
smg_disp: mov dptr,#disp_tab ;指向显示代码表 mov r0,#78h
;指向数据显示区
mov r7,#0feh ;显示模式(即“位选码”) disp_loop: mov a,@r0
;取一个数据
movc a,@a+dptr mov p0,a
mov a,r7 mov p2,a inc r0 rl a
;转换成显示代码 ;送P0口(“段选码”) ;取显示模式
;送P2口(“位选码”)
;指向下一数据
;移向下一位
mov r7,a lcall ys1ms lcall ys1ms
;并保存
cjne a,#0efh,disp_loop ;扫描4位了吗? mov p2,#0ffh ret
;确保扫描完后数码管都灭
;*********************************************************
8
;延时1ms子程序
ys1ms: mov r6,#2 ys0: mov r5,#250 djnz r5,$
djnz r6,ys0 ret
;********************************************************* ;T0中断子程序
t0_int: push acc
cpl p3.6 inc r3 cjne r3,#0,next inc r4
;输出方波
t0_end: pop acc reti
next: cjne r3,#0a0h,t0_end cjne r4,#0fh,t0_end
;判断够4000次计数吗?
;因为中断4000次为1秒。 mov r3,#0 mov r4,#0 cpl tr1
;1秒计数器清0 ;启动或关闭T1计数器
jb tr1,t0_end ;若T1启动则返回 mov a,tl1 anl a,#0fh mov 78h,a mov a,tl1 swap a anl a,#0fh
mov 79h,a ;送低8位频率值到数据区 mov a,th1
9
anl a,#0fh mov 7ah,a mov a,th1 swap a anl a,#0fh mov 7bh,a mov tl1,#0 mov th1,#0 ljmp t0_end
;T1计数器清0
;送高8位频率值到数据区
;注:以上送显示区的数据为16进制。经实验,得到的16进制值为07H、0D0H。 ;思考题:若用10进制显示,如何编程?
;********************************************************* ;数据区数据显示代码表
disp_tab: db 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh db 6fh,77h,7ch,39h,5eh,79h,71h end
;*********************************************************
2. 带按键调整的数字钟
;任务:用单片机最小系统实现数字钟显示;用4个简单按键(P3.4---P3.7)实现 ;小时和分钟的调整。
;********************************************************* ;************* 带按键调整的数字钟 *************** ;********************************************************* ;定义:K34为“小时+”键,K35为“小时-”键; ; K36为“分钟+”键,K37为“分钟-”键。 ; 78H-7FH为时钟数据存放区:
; (78H放“秒”值,79H放“十秒”值)
10
; (7BH放“分”值,7CH放“十分”值) ; (7EH放“时”值,7FH放“十时”值) ; (7AH放“-”,7DH放“-” )
; 75H-77H放压缩式BCD码的“秒、分、时”的值 ; 74H为T0中断次数计数器,计够20次为1秒。
Org 0000H Ljmp main Org 000BH Ljmp T0_int ;主程序
Org 0030H Main:
Mov sp,#30H ;调整堆栈指针
Mov 74H,#0 ;清中断次数计数器 Mov 75H,#0 ;“十秒和秒”清0 Mov 76H,#0 ;“十分和分”清0 Mov 77H,#0 ;“十时和时”清0 Mov 7ah,#10 ; “-” Mov 7dh,#10 ; “-”
Mov tmod,#01H ;定义T0为定时、方式1 Mov th0,#3cH
Mov tl0,#0b0H ;预置常数15536 Setb et0 ;开T0中断 Setb ea ;开总中断 Setb tr0 ;启动定时器T0 Loop: Lcall smg_disp ;调数码管显示一遍 Lcall Key_Check ;调时钟按键调整 Sjmp Loop
;*********************************************************
11
;T0中断子程序
T0_int: Push acc ;断点保护
Mov th0,#3cH
Mov tl0,#0b0H
Inc 74H ;中断次数加1(每次50ms) Mov a,74H
Cjne a,#20,T0_end ;中断次数够20次(1秒)吗? Mov 74H,#0 ; ;够20次(1秒)清0 Mov a,75H ;取“十秒、秒值” Add a,#1
Da a ;十进制调整(调整成压缩式BCD码) Mov 75H,a
Cjne a,#60H,fenjie ;秒处理 Mov 75H,#0 ;够60秒清0 Mov a,76H ;取“十分、分值” Add a,#1 Da a Mov 76H,a
Cjne a,#60H,fenjie ;分处理 Mov 76H,#0 ;够60分清0 Mov a,77H ;取“十时、时值” Add a,#1 Da a Mov 77H,a
Cjne a,#24H,fenjie ;时处理 Mov 77H,#0 ;够24时清0 Fenjie: Lcall FJ_data T0_end: Pop acc Reti
;*********************************************************
12
;分解压缩式BCD码数据子程序
FJ_data: Mov r1,#78H ;指向显示区“秒”的位置 Mov a,75H ;取压缩式BCD码的“秒” Xchd a,@r1 ;分解保存 Inc r1 Swap a
Xchd a,@r1 ;分解保存
Mov r1,#7bH ;指向显示区“分”的位置 Mov a,76H ;取压缩式BCD码的“分” Xchd a,@r1 ;分解保存 Inc r1 Swap a
Xchd a,@r1 ;分解保存
Mov r1,#7eH ;指向显示区“时”的位置 Mov a,77H ;取压缩式BCD码的“时” Xchd a,@r1 ;分解保存 Inc r1 Swap a
Xchd a,@r1 ;分解保存 Ret
;********************************************************* ;时钟调整子程序
Key_check: Mov p3,#0ffh ;为读入P3口内容做准备
Mov a,p3 ;读入P3口内容到A Cpl a
Jnz add_sub ;有键按下跳去处理 Key_end: Ret
Add_sub: lcall smg_disp
lcall smg_disp ;数码管显示两遍,延时若干ms抗干扰
13
Mov a,p3 ;再次读入P3口内容到A Cpl a
Jz key_end ;无键按下返回
Jb acc.4,hour_add ;判是P3.4脚接的按键吗? Jb acc.5,hour_sub ;判是P3.5脚接的按键吗? Jb acc.6,min_add ;判是P3.6脚接的按键吗? Jb acc.7,min_sub ; Sjmp key_end
hour_add: hour_sub: jz next_23 ; anl a,#0fH
jz sub_7 ; dec 77H ; Sjmp key_wait
Next_23: Mov 77H,#23H ; Sjmp key_wait Sub_7: Mov a,77H Subb a,#7 ; Mov 77H,a Sjmp key_wait
min_add:
判是P3.7脚接的按键吗? Mov a,77H ;取“小时” Add a,#1 ;加1 Da a Mov 77H,a
Cjne a,#24H,key_wait
Mov 77H,#0 ;为24点则清0
Sjmp key_wait
Mov a,77H ;取“小时”
为0点则跳转 为10点或20点则跳转 不为以上值时直接减1 赋值23点 减7 Mov a,76H ;取“分” Add a,#1 ;加1 Da a
14
Mov 76H,a
Cjne a,#60H,key_wait
Mov 76H,#0 ;够60分清0 Sjmp key_wait
min_sub: Mov a,76H ;取“分”
jz next_59 ;“十分和分”都为0则跳转 anl a,#0fh
jz jian_7 ;“分”为0则跳转 dec 76H ; “分”不为0则直接减1
Sjmp key_wait
Next_59: Mov 76H,#59H
Sjmp key_wait
Jian_7: Mov a,76H Subb a,#7 Mov 76H,a Key_wait: Lcall FJ_data
Wait: lcall smg_disp ;等候按键释放并保持数码管的显示不
;断续
mov p3,#0ffh
Mov a,p3 ;再次读入P3口内容到A Cpl a
Jnz wait ;等候按键释放 Ret
;*********************************************************
思考题:以上的实验里,每按一下按键,只能加1或减1;若想按下按键1秒后,能自动连续加1或减1,一直到松开按键为至,如何编程?
以上的程序为新增的学习内容,要做完整的该实验,还需将过去学过的部分程序
15
添加进去,如以下部分:
;************************************************************ ;数码管显示一遍子程序
smg_disp: mov dptr,#disp_tab ;指向显示代码表 mov r0,#78h mov r7,#0feh disp_loop: mov a,@r0 movc a,@a+dptr mov p0,a
mov a,r7 mov p2,a inc r0 rl a
;指向数据显示区 ;显示模式(即“位选码”)
;取一个数据 ;转换成显示代码
;送P0口(“段选码”) ;取显示模式
;送P2口(“位选码”)
;指向下一数据
;移向下一位 ;并保存
mov r7,a lcall ys1ms
cjne a,#0feh,disp_loop ;扫描一遍了吗?
Ret
;************************************************************ ;延时1ms子程序
ys1ms: mov r6,#2 ys0: mov r5,#250 djnz r5,$
djnz r6,ys0 ret
;************************************************************ ;数据区数据显示代码表
disp_tab: db 3fh,06h,5bh,4fh,66h,6dh db 7dh,07h,7fh,6fh, 40h
;************************************************************ end
16
;************************************************************
17
因篇幅问题不能全部显示,请点此查看更多更全内容