找回密码
 注册
关于网站域名变更的通知
查看: 213|回复: 3
打印 上一主题 下一主题

单片机教程19单片机定时器、中断试验

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2022-8-3 11:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
  我们在学单片机时我们第一个例程就是灯的闪烁,那是用延时程序做的,现在回想起来,这样做不很恰当,为什么呢?我们的主程序做了灯的闪烁,就不能再干其它的事了,难道单片机只能这样工作吗?当然不是,我们能用定时器来实现灯的闪烁的功能。例1:查询方式3 w$ [2 ~! G, _* I: U; G. F6 ~
ORG 0000H
' m/ m2 c( A6 T5 L; ^! VAJMP START& o; t0 E2 U" t& ]1 }: u
ORG 30H# R" `( a; v  o2 y
START:
3 O: p- U* D8 V4 k7 cMOV P1,#0FFH ;关所 灯8 ^; \# S. f* o3 O- t
MOV TMOD,#00000001B ;定时/计数器0工作于方式1* i; E+ @4 k; R- n! ?  Y
MOV TH0,#15H9 W& z5 v7 C% P$ |& ^& ]4 f0 X
MOV TL0,#0A0H ;即数55367 Z# C* Q: E/ }  |* J" ?1 i% i
SETB TR0 ;定时/计数器0开始运行
- l# K, _! J# n' Y( ^LOOP:JBC TF0,NEXT ;如果TF0等于1,则清TF0并转NEXT处- q$ I2 L! Z+ F# R! v
AJMP LOOP ;不然跳转到LOOP处运行
0 C- b* q2 ?9 o3 mNEXT:CPL P1.0- j& }5 u1 Z! W( y0 J8 F8 w
MOV TH0,#15H
+ u, P! `4 @. @. `* rMOV TL0,#9FH;重置定时/计数器的初值
  i9 N% r+ |4 f" N$ U. O) dAJMP LOOP
- _' D1 t% E# `( D) k' FEND AJMP LOOP
7 ?. m% }) J' W0 ZEND* ~4 s1 ?9 |; U9 z5 i
   键入程序,看到了什么?灯在闪烁了,这可是用定时器做的,不再是主程序的循环了。简单地分析一下程序,为什么用JBC呢?TF0是定时/计数器0的溢出标记位,当定时器产生溢出后,该位由0变1,所以查询该位就可知宇时时间是否已到。该位为1后,要用软件将标记位清0,以便下一次定时是间到时该位由0变1,所以用了JBC指令,该指位在判1转移的同时,还将该位清0。
2 R# P% u) Y8 a8 j8 C/ ]   以上程序是能实现灯的闪烁了,可是主程序除了让灯闪烁外,还是不能做其他的事啊!不,不对,我们能在LOOP:……和AJMP LOOP指令之间插入一些指令来做其他的事情,只要保证执行这些指令的时间少于定时时间就行了。那我们在用软件延时程序的时候不是也能用一些指令来替代DJNZ吗?是的,但是那就要求你精确计算所用指令的时间,然后再减去对应的DJNZ循环次数,很不方便,而现在只要求所用指令的时间少于定时时间就行,显然要求低了。当然,这样的办法还是不好,所以我们常用以下的办法来实现。; S7 n" ~) u: e7 r  [3 w1 I4 r
程序2:用中断实现
9 a5 e& l- u3 M' W- d7 F  y9 BORG 0000H   ,http://www.51hei.com8 k2 @4 p, n: S# E0 D2 h
AJMP START
7 X$ {6 P: o$ d: mORG 000BH ;定时器0的中断向量地址
5 j7 p) R9 @' n. J& G/ s) HAJMP TIME0 ;跳转到真正的定时器程序处; C& a5 C  P! M/ \
ORG 30H
) m+ C7 b! p1 x7 ^$ c# U( RSTART:
, ^5 o( l" N( S; F$ e- T4 YMOV P1,#0FFH ;关所 灯
) t% U6 s$ E( p. b' ?9 mMOV TMOD,#00000001B ;定时/计数器0工作于方式1
) v4 x9 x# b6 {# oMOV TH0,#15H3 p5 o8 ~: I' S2 k! H5 B
MOV TL0,#0A0H ;即数5536
& U0 e2 g7 u# I. i3 b+ ]SETB EA ;开总中断允许
. r' N* b/ S1 F1 c" M9 W2 RSETB ET0 ;开定时/计数器0允许
9 x  p! f! I3 f! w, SSETB TR0 ;定时/计数器0开始运行$ d4 e# N) w& E( v6 n
LOOP: AJMP LOOP ;真正工作时,这里可写任意程序) V8 {1 K- d2 ]5 o4 b
TIME0: ;定时器0的中断处理程序
8 E1 i4 o8 ^0 \: `+ Z9 H4 BPUSH ACC
& ~* I4 c, j' O% X$ i; FPUSH PSW ;将PSW和ACC推入堆栈保护
+ c. J/ m9 G! B3 ~5 ^* H# CCPL P1.0- Y+ @) L7 h' B  G/ ?9 ]: T
MOV TH0,#15H# u$ l6 U* G  s6 i; m# X4 R  E" [
MOV TL0,#0A0H ;重置定时常数
4 {7 C! O8 j/ DPOP PSW* Z0 |: o& s0 _) Q) C) x7 F5 J
POP ACC+ f# ]1 U% h6 w  z
RETI# R% W9 g' u; ^2 X
END; y5 W- J+ v' j8 s! K7 K( k
    上面的例程中,定时时间一到,TF0由0变1,就会引发中断,CPU将自动转至000B处寻找程序并执行,由于留给定时器中断的空间只有8个字节,显然不足以写下所有有中断处理程序,所以在000B处安排一条跳转指令,转到实际处理中断的程序处,这样,中断程序能写在任意地方,也能写任意长度了。进入定时中断后,首先要保存当前的一些状态,程序中只演示了保存存ACC和PSW,实际工作中应该根据需要将可能会改变的单元的值都推入堆栈进行保护(本程序中实际不需保存护任何值,这里只作个演示)。
- ?& n$ D. H8 K' I" ^2 ~   上面的两个单片机程序运行后,我们发现灯的闪烁非常快,根本分辨不出来,只是视觉上感到灯有些晃动而已,为什么呢?我们能计算一下,定时器中预置的数是5536,所以每计60000个脉冲就是定时时间到,这60000个脉冲的时间是多少呢?我们的晶体震荡器是12M,所以就是60000微秒,即60毫秒,因此速度是非常快的。如果我想实现一个1S的定时,该怎么办呢?在该晶体震荡器濒率下,最长的定时也就是65。536个毫秒啊!上面给出一个例程。) d0 y. n( r0 h6 O* l4 k2 Y' r, B
ORG 0000H- j4 ~& P( v' m. d; \2 K
AJMP START
* r1 |  \& ?, X/ L4 HORG 000BH ;定时器0的中断向量地址
% J) f  g1 |- ^9 s& K' V4 dAJMP TIME0 ;跳转到真正的定时器程序处
1 I- v: J4 O" w5 CORG 30H
. m0 k/ ]7 I% O0 t" `START:% J0 b- y. F( }3 \' }0 I
MOV P1,#0FFH ;关所 灯- d  @/ M$ t0 w' y3 V8 Z. X
MOV 30H,#00H ;软件计数器预清05 q/ R% v" |, l) O( Q1 w5 A( ]9 q
MOV TMOD,#00000001B ;定时/计数器0工作于方式1
& e% ?% O- N0 D/ w$ l% UMOV TH0,#3CH
/ U4 U* m6 p* p9 D" c4 @MOV TL0,#0B0H ;即数15536* Z& K7 o  y. b) @
SETB EA ;开总中断允许
% s( V0 b; d- |) c( JSETB ET0 ;开定时/计数器0允许) e2 x0 K# l5 Z$ j7 C$ D. X  e
SETB TR0 ;定时/计数器0开始运行! C9 K5 x7 O3 Q; d' H
LOOP: AJMP LOOP ;真正工作时,这里可写任意程序
% i+ u7 C7 g/ E7 X* |TIME0: ;定时器0的中断处理程序
6 M: F0 ~- h4 Z- v0 c8 {" D, TPUSH ACC
) L9 B# _0 p9 HPUSH PSW ;将PSW和ACC推入堆栈保护
1 a2 p; V8 F, g8 j" e; ~# @8 a' _INC 30H: G4 N- |) @: c# B2 \( C
MOV A,30H
. G2 M; m' ^( a5 O+ R7 FCJNE A,#20,T_RET ;30H单元中的值到了20了吗?
! w3 c5 A, ^+ @8 m5 [" ^* Y$ |T_L1: CPL P1.0 ;到了,取反P10
0 o/ y, C& q' [! s7 z- j7 [9 TMOV 30H,#0 ;清软件计数器3 l* V- w6 Z* a  J7 M) e
T_RET:% }: V6 p% O5 h& l. [4 w* M
MOV TH0,#15H
' d! l; m0 T0 x! v5 qMOV TL0,#9FH ;重置定时常数' U, O; e) Q+ {
POP PSW1 N7 Z4 Z( y" x, s
POP ACC
2 K5 Y8 j1 D7 YRETI
& P) y8 l2 P2 J+ KEND" ~3 x3 H6 }& T' x9 j9 t* @  I
  先自己分析一下,看看是怎么实现的?这里采用了软件计数器的概念,思路是这样的,先用定时/计数器0做一个50毫秒的定时器,定时是间到了以后并不是立即取反P10,而是将软件计数器中的值加1,如果软件计数器计到了20,就取反P10,并清掉软件计数器中的值,不然直接返回,这样,就变成了20次定时中断才取反一次P10,因此定时时间就延长了成了20*50即1000毫秒了。( `3 {) M  n4 U. ?
   这个思路在工程中是非常有用的,有的时候我们需要若干个定时器,可51中总共才有2个,怎么办呢?其实,只要这几个定时的时间有一定的公约数,我们就能用软件定时器加以实现,如我要实现P10口所接灯按1S每次,而P11口所接灯按2S每次闪烁,怎么实现呢?对了我们用两个计数器,一个在它计到20时,取反P10,并清零,就如上面所示,另一个计到40取反P11,然后清0,不就行了吗?这部份的程序如下
: l1 [7 l- T# `! CORG 0000H
9 j3 G: ], G- A6 M7 `AJMP START
* K$ x& n3 j, ^7 B0 p* j: {6 _ORG 000BH ;定时器0的中断向量地址
5 [- N2 P: `) Y% SAJMP TIME0 ;跳转到真正的定时器程序处4 R* n/ c$ p2 l
ORG 30H5 u7 j0 J8 F* b. m% D$ {0 u( q5 H8 S
START:# I( N% H' S% X) ?
MOV P1,#0FFH ;关所 灯; X) L1 [- m: p7 P! \2 y; e
MOV 30H,#00H ;软件计数器预清0
. Y5 y' R: V: P. ]9 y) s5 IMOV TMOD,#00000001B ;定时/计数器0工作于方式1
) b( k) I3 F9 {+ v2 k! \MOV TH0,#3CH
3 a. E1 J& g: i* u" Z8 o# zMOV TL0,#0B0H ;即数15536  m% ]- b; m5 @; T0 B0 _% a
SETB EA ;开总中断允许9 }% a! l9 f. A" _2 V( V. U& {
SETB ET0 ;开定时/计数器0允许
8 Q+ W+ c# I  ^SETB TR0 ;定时/计数器0开始运行* `& w/ R1 ~( i( F, p
LOOP: AJMP LOOP ;真正工作时,这里可写任意程序
- s, D$ Q" `% D, f: E. a, ATIME0: ;定时器0的中断处理程序
& E0 h) P( N& A2 wPUSH ACC
# N# A; Q& F. a7 |PUSH PSW ;将PSW和ACC推入堆栈保护! K6 Q5 I9 h$ s& a3 i7 Y  H7 E* y4 t
INC 30H
# u* S1 o! n9 k3 d/ mINC 31H ;两个计数器都加1
; ?' ?: r3 |; A! A* X3 T+ H6 P" uMOV A,30H
+ y( C) s0 s6 @: B/ D- X8 {6 jCJNE A,#20,T_NEXT ;30H单元中的值到了20了吗?; |4 t: s; e. T* A  ?" y9 K( X0 E
T_L1: CPL P1.0 ;到了,取反P10% e3 h6 W, p, z. D; P) F; k
MOV 30H,#0 ;清软件计数器
2 [+ U" C* X1 h4 i1 e& C/ CT_NEXT:6 |7 L$ Y+ w! r" L2 o
MOV A,31H
) T5 x+ N+ K$ O3 l) H+ K8 ]CJNE A,#40,T_RET ;31h单元中的值到40了吗?
8 m' K4 h8 Z1 S  f2 n9 A8 a) sT_L2:0 B$ w7 c4 D0 p. j; e% L
CPL P1.1
' H. v  R( T( Q# Q6 s& B$ B0 v8 u# v! CMOV 31H,#0 ;到了,取反P11,清计数器,返回6 F6 g0 v* G/ a  C
T_RET:
' \! W1 ]& C  p( yMOV TH0,#15H7 W6 [" ^" _: O, B
MOV TL0,#9FH ;重置定时常数
' F8 N2 G6 z# L1 k) c7 G0 e7 [) \POP PSW
6 d6 R  a9 `& n3 DPOP ACC0 M+ z5 P. ~1 g# V" j' j: @) h: i
RETI2 e! m9 ]& Q# K
END' v5 D; U  l+ r0 X# l$ ~
您能用定时器的办法实现前面讲的流水灯吗?试试看。- h3 S7 r! l$ R$ \. ~
- W5 r" m- q: f( V2 m& M

该用户从未签到

2#
 楼主| 发表于 2022-8-3 13:18 | 只看该作者
本帖最后由 Terran 于 2022-8-3 13:29 编辑
, k8 ~  D. V; T" B* x- r: a/ [8 S! E7 z5 D5 ?$ n; V- }
都来看看吧!学习一下

该用户从未签到

3#
发表于 2022-8-3 13:29 | 只看该作者
一个良好的学习氛围,太棒了。

该用户从未签到

4#
发表于 2022-8-3 15:05 | 只看该作者
多多说一些自己的实际经验,相关知识,分享一些好的制作例子
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-10-8 14:17 , Processed in 0.156250 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表