你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

51单片机各个定时器的用法

[复制链接]
gaosmile 发布时间:2020-7-10 14:04
一、原理/ p* i+ e9 _: B5 n) f$ _2 [

% E+ W. B- c% N7 o0 B) n* e0 Q9 h51单片机,拥有两个定时器,用来中断计数,分别是T0和T1。而52单片机和51单片机的定时器是一样的,只是52比51多了一个定时器/计数器T2,它们的设置都大同小异,下面我来总结各个定时器的用法。
6 Y. S/ Z) [' e+ z% g定时器T0与T1不同之处在于它们的工作方式3不同,方式0、1、2相同。8 V% \9 a; Z0 L" \, M
微信图片_20200710135825.png
% X  K! h7 c) u- z# F首先我们看要使用定时器T0应该设置的东西:
% p6 l: W1 `4 N; C2 w3 _1、对中断寄存器和定时器进行初始化:+ E- x9 u2 U6 {+ ^
微信图片_20200710135829.png
. P" P0 R$ `6 Q9 F2 }9 r初始化函数里的内容也可以写在头文件里,但是为了美观和好查阅,就把它单独写出来,后面在头文件里直接调用就行。那么应该要进行初始化的设置:! S7 `" T5 V& @$ Y, G. p
①设置定时器的工作方式
5 [) Q" M1 Z7 Z/ i5 N2 E$ b, V单片机内,有其中一个特殊寄存器叫TMOD,这是用来设置定时器工作方式的寄存器,通过软件,将其寄存器内的D0~D7位置0或1,从而达成对定时器的操作。
( k8 X2 D: C3 I8 F/ b! }/ |# Y寄存器TMOD9 D2 e& w7 b; R1 h
微信图片_20200710135833.png
' I* S2 r8 a* {. R  d: C2 l如表格,这是定时器的工作方式寄存器TMOD,要更改定时器的工作方式,我们只用到M1、M2所以其他位一般置0,又因为我们使用的是T0的定时器,所以就有:
* y0 G. |& r$ [4 ^1 n; [ 微信图片_20200710135836.png
) X" l" v, Q7 ^: S% D8 ?1 A- |控制M1、M0将它们置1或0,即可达成操作控制方式的目的,然后转换成16进制即方便查阅。3 F; h3 s3 I9 Q1 B/ @1 m' {
同理,使用定时器1时也是这么设置。注意,有时候也有使用两个定时器T0、T1的时候,那么就是0001 0001两个都是工作方式1。请大家举一反三。
7 A, `5 u1 H% \" {, Q# `8 J/ f7 l% T8 @
②设定初值' a3 C0 p# h, ]$ _; J& T3 ]
先说说总值:以方式1为例(之后会介绍其他方式):+ N; }0 V2 L: o# p/ u! K) _
微信图片_20200710135839.png " k0 _: c# u0 V3 j
方式1为16位的定时器/计数器,对定时器T0来说是分成两个寄存器(可以形象地比作容器吧,网上有比我更形象的比喻,我就不多写了,请自行查阅):TH0为高八位,TL0为低八位,组成了16位的定时器,当低位TL0计满就向高位TH0移一个数,然后清零。
! k/ D/ ]$ U" e% n8 b! v以12Mhz的晶振来说,机器周期是1us,计满TH0、TL0就需要216-1个数,再来一个数就“溢出”产生中断,一次溢出也就是65536us,约等于65.5ms,如果要定时50ms的话就要给他们装一个预装值(初值),总值-需要值=预装值,也就是65536-50000=15536,预装后,定时器从预装值开始加值,定时器溢出中断后,会重新从预装值开始加值加到50ms就再产生中断,从而达到了定时的目的。如果要定时1s就可以让定时器中断1000ms/50ms=20次。
' R9 Z+ b# k0 g8 x另外一点,TH0和TL0中应该装入的总数是15536,然后把15536对256求模:15536/256=60装入TH0中,把15536对256求余:15536%256=176装入TL0中,因为这是两个八位28*28的容器。
, M( q7 X* n  k: G' n' v/ I所以就有了TH0=(65535-50000)/256TL0=(65535-50000)%256
$ |; J2 z3 V- I; e0 D2 [: T9 b③开启中断和定时器
, y, k4 o2 B2 x. ?关于中断,需要用到中断允许寄存器:
6 T7 [+ E& n9 G4 o 微信图片_20200710135842.png : ?8 D) E/ T4 \) g
定时器中断需要的是:总中断EA:用来开启全局中断。ET0、1、2:各个定时器中断位。使用中断位只用将其置1就行,例如EA=1;ET0=1;打开了中断开关只是完成了一半,还需要定时器控制寄存器:TCON9 t) D+ G+ t3 a! F" Y8 r' K7 o

7 p. @% E% ]" }$ H6 `+ R3 b 微信图片_20200710135845.png # M8 w* v2 d0 v  M: a9 J) a: |
使用方法也是和中断寄存器一样,定时器0运行控制位TR0:用来开启定时器0.把TR0置1,TR0=1;就开启了定时器。* j  j( H0 e2 n$ ]% X! ]
2、设置中断服务程序:
8 B/ s( N+ t( e" ~9 E 微信图片_20200710135848.png & ?0 N' A) u3 r; ~* e, \# v9 n; c7 z
中断服务程序:就是当计满TH0、TL0时溢出申请中断,然后单片机允许中断时,所要发生的事情。允许后就自动跳转到中断服务程序,并执行。, l& \1 A% _" {, c1 Y2 ^; v
在服务程序中,如果不装入初值,那定时器中断服务完成后,就会从0开始重新计时,所以要在中断程序中重新计算并装入初值。
6 O" S% m1 Y0 H6 W/ l. d" U2 k0 y1 _然后给一个变量(变量的意义为中断次数),变量+1,当中断次数达到20次的时候(50ms*20次=1000ms=1s),次数清零,并且让产生指令(例如让二极管亮呀,让I/O口发生什么事呀)。! D! R0 A7 T+ S! \" k2 N
3、主函数:+ B, P/ B/ V& u) @9 _, m& ?
微信图片_20200710135851.png 0 a, y# p& w7 r
由于有了初始化函数,所以直接调用即可(不然主函数很混乱)。
0 x5 l. X3 K4 d! c% P: h7 H7 a2 b4 bWhile(1);这段是为了等待函数发生,挺含糊的。
' y/ s: `, x1 K9 S/ m2 j8 f另外:一般中断服务程序中不要写过多的处理语句,否则程序会来不及执行代码,下一次中断又来袭,结果程序久而久之就乱套了。5 H9 N, H9 e8 D( ~) x) L  z5 C& ^# t
所以while处可以改成:把if处理语句写到while处。( g/ ~7 G) p* L+ _6 B% S0 r' X
微信图片_20200710135855.png
$ l  o- G  B6 H附上完整程序:8 x2 M$ w% v) G' ?0 B- H
微信图片_20200710135858.png
; [( o) |; k% k二、各个定时器和工作方式
; @5 s7 X, m: f/ e3 M8 Q7 x0 L先来看看工作方式:& b+ ^! m9 ?8 D" j
微信图片_20200710135902.png # U9 N' }  u$ M2 i) w+ j* x
方式3,仅适用于T0,分成两个8位计数器,当设置成T1时停止计数; F- V. K0 v# @5 Z
工作方式有四种:0、1、2、3。我们之前已经学习了方式1的工作方式,那么接下来就先来看看其他的工作方式:) n/ O. P: D4 t9 }9 Z" v" b
方式0
5 G; M7 Y" a2 r; k方式0,的用法和方式1的用法一样,但是值得注意的是:
% t1 q0 s4 w- H8 i+ }$ C1 V8 ~7 P4 e 微信图片_20200710135906.png + K' ?  ~- a8 M6 |( f
方式0是13位的定时器,它的低位TL0是五位的,所以它的总值是28*25=8192。它能装的值也不能那么多了,于是就装入5ms:0 f% I0 C/ W. L: |2 d# ]
TH0(8192-5000)/32;TL0(8192-5000)%32;32是5位寄存器的容量。所以要中断200次才能达到1s。这个方式0可以用来做短时间中断。
2 d4 S+ Q9 E/ k3 E) E+ t' Y$ C
方式22 [& }/ t( |2 B( f% b% d
方式0和方式1,当计数溢出后,计数器变为0,所以要反复重新装填初值,这会影响定时精度。但是方式2可以解决这个问题。/ \6 @5 v/ X4 |  g) `) W' C
微信图片_20200710135910.png ( o3 A5 k! f+ r% a  r* T5 c- |
如图,其中低位TL0是8位定时器,而TH0是常数缓冲器,当低位TL0溢出时,在溢出标志位TF0置1的同时,自动将高位TH0的常数重新装入TL0中,让TL0从初值开始重新计数,这样就不用人为软件重新装入初值带来的误差,从而提高精度。: w& n. d+ W# m4 q4 B2 R. l
由于两个是分开的,所以计算初值可以不用求余取模:TL0=总值-要计数的个数;TH0=总值-要计数的个数;
! n, k7 F0 T& L+ R7 A以11.0592MHz为晶振,那么机械周期为12x(1/11059200)≈1.085us,以计时1s为例,当要计250个数时耗时1.0851x250=271.275us,再来算计时1s要用多少次,即1000000/271.275≈3686次。
- K0 v- Q1 g$ T2 ?6 {  p& ^那么就是:& B2 t) N& p+ B* w- L6 y  n$ ^
微信图片_20200710135913.png
. q% N9 W! X  ^+ f0 ATL0=256-250=6;TH0=256=250=6;由于方式2是自动装填,已经不用人为装填了,所以:
+ B' b) {1 a' }4 n5 J% V; X( D 微信图片_20200710135917.png
: [3 ?: ]& d  ^6 y+ X中断服务程序中只有一句num++整个过程就是:
; \* X: Z3 d0 ^3 k+ K& u 微信图片_20200710135921.png
2 Y  Q  f5 Q* D% r; l' v方式3
. s8 H6 H) k" ~/ M, O* A接下来介绍方式3,方式3不同于其他三个方式,它只能用于T0,也就是定时器0,和方式2差不多,也是把TL0、TH0分成两个独立的寄存器,但是TH0也参与计数,也就是两个独立的8位定时器/计数器。5 }& |! Y& l, u( i+ M8 F
普通的使用一样,TL0计数溢出后置位TF0,并申请中断,之后重装。但是由于TL0占用了TR0和TF0,所以TH0只能占用定时器 T1的TR1和TF1。所以定时器T1一定不要用在有中断的场合,当然,T1同样可以正常工作在方式0、1、2下。通常这种情况,T1都被用来当做串行口的波特率发生器。' @4 O7 K) x6 Q$ u0 U9 Y. J
首先把T0、T1的中断位和控制位打开:, k* g. U2 t# x% D& L1 q: E
微信图片_20200710135925.png
5 l/ g' o" w4 y' o  k0 P9 I& O然后分别给低位TL0和高位TH0设置中断服务程序:
  {/ q/ `* R5 A7 v: q1 y3 e 微信图片_20200710135928.png
, Z% m+ E/ X( {9 t' T7 h8 ?* e1 d( }可以注意到interrupt后面的数值,这个是编译器识别不同中断的唯一符号:52单片机的中断级别# A& w% C+ y9 x+ N  h. u" G% R
微信图片_20200710135931.png 6 K0 n) r" w6 S
然后到主函数:调用init();  x' D6 L6 E' ?& @  n
微信图片_20200710135934.png 5 d6 C, W1 ?4 S! C5 |8 i
可以看到if语句里面的符号是>=,为什么呢?因为当if语句的值到了时,主程序停止下来判断num1==3686是否为真,当它还在判断的时候,num2是还在走的,于是当主程序判断好num1的时候再去判断num2,为时已晚,num2这时可能已经是1844或者1845或者更高的数了,所以要变成>=。
收藏 1 评论0 发布时间:2020-7-10 14:04

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版