第六章 计数器 / 定时器
DESCRIPTION
第六章 计数器 / 定时器. 6-1 计数 / 定时器工作原理. 6-2 MCS-51 定时 / 计数器的应用. 6-3 应用举例. 6-1-1 基本概念. 一、计数概念的引入 生产线上产品计数 : 每个产品通过得到一个脉冲信号,计数器记录脉冲个数,当计数值与设定值相等,启动包装机器。 检测转速 : 电机转动一圈发出一个脉冲,计数器记录一秒时间内脉冲个数,显示转速。. 二、计数器的容量 - PowerPoint PPT PresentationTRANSCRIPT
第六章 第六章 计数器计数器 // 定时器定时器
6-16-1 计数计数 // 定时器工作原理定时器工作原理
6-26-2 MCS-51MCS-51 定时定时 // 计数器的应用计数器的应用
6-36-3 应用举例应用举例
一、计数概念的引入一、计数概念的引入生产线上产品计数 : 每个产品通过得到一个脉冲信号,计数器记录脉冲个数,当计数值与设定值相等,启动包装机器。检测转速 : 电机转动一圈发出一个脉冲,计数器记录一秒时间内脉冲个数,显示转速。 二、计数器的容量二、计数器的容量从一个生活中的例子看起:一个水盆在水龙头下,水龙没关紧,水一滴滴地滴入盆中。水滴不断落下,盆的容量是有限的,过一段时间之后,水就会逐渐变满。那么单片机中的计数器有多大的容量呢? 8031 单片机中有两个计数器,分别称之为 T0 和 T1 ,这两个计数器分别是由两个 8 位的 RAM 单元组成的,即每个计数器都是 16 位的计数器,最大的计数量是 65536 。
6-1-16-1-1 基本概念基本概念
三、定时三、定时8031 中的计数器除了可以作为计数之用外,还可以用作时钟,那么计数器是如何作为定时器来用的呢?一个闹钟,我将它定时在 1 个小时后闹响,换言之,也可以说是秒针走了( 3600 )次,所以时间就转化为秒针走的次数的,也就是计数的次数了,可见,计数的次数和时间之间的确十分相关。那么它们的关系是什么呢?那就是秒针每一次走动的时间正好是 1 秒。结论:只要计数脉冲的间隔相等,则计数值就代表了时间的流逝。由此,单片机中的定时器和计数器是一个东西,只不过计数器是记录的外界发生的事情,而定时器则是由单片机提供一个非常稳定的计数源。
四、溢出四、溢出让我们再来看水滴的例子,当水不断落下,盆中的水不断变满,最终有一滴水使得盆中的水满了。这时如果再有一滴水落下,水会漫出来,用个术语来讲就是“溢出”。 水溢出是流到地上,而计数器溢出后将使得 TF0 变为“ 1” 。至于 TF0 是什么我们稍后再谈。一旦 TF0 由 0 变成 1 ,就是产生了变化,产生了变化就会引发事件,就象定时的时间一到,闹钟就会响一样。现在我们来研究另一个问题:要有多少个计数脉冲才会使 TF0 由 0 变为 1 。五、任意定时及计数的方法五、任意定时及计数的方法刚才已研究过,计数器的容量是 16 位,也就是最大的计数值到 65536 ,因此计数计到 65536 就会产生溢出。这个没有问题,问题是我们现实生活中,经常会有少于 65536 个计数值的要求,如包装线上,一打为 12 瓶,一瓶药片为 100 粒,怎么样来满足这个要求呢?提示:如果是一个空的盆要 1 万滴水滴进去才会满,我在开始滴水之前就先放入一勺水,还需要 10000 滴嘛?我们采用预置数的方法,要计 100 ,就先放进 65436 ,再来 100 个脉冲,就到 65536 了。定时也是如此,每个脉冲是 1 微秒,则计满 65536 个脉冲需时 65.536 毫秒,但现在只要 10 毫秒就可以了,怎么办?10 个毫秒为 10000 个微秒,所以,只要在计数器里面放进 55536 就可以了。
6-1-2 定时 / 计数器的工作原理定时 / 计数器中的核心部件为可预置初值计数器。预置初值后开始计数,直
至计数值归 0 或产生溢出,可申请中断。计数器有加 1 计数或减 1 计数两种形式。
K1 K2
可预置初值计数器 中断请求
功能选择
启动控制
内部时钟脉冲(定时)
外部输入脉冲(计数)
溢出信号计数脉冲
计数初值
例:设 8 位加 1 计数器。按要求选择功能和初值。1. 要求检测到 100 个脉冲,发中断请求,通知 CPU 。选计数功能,计数初值为 156 。2. 要求定时每隔 100s 时间,发一次中断请求。设内部时钟周期 1s选定时功能,计数初值为 156 。
看图思考提供定时器的是计数源是什么呢?
6-2-1 MCS-51 定时 / 计数器2 个可独立控制的 16 位定时器 / 计数器: T0 、 T1
一 . 定时器控制、状态寄存器1.TMOD 定时器方式寄存器( 89H )
1 )功能选择位 C/T :=0 ,定时功能,计数内部机器周期脉冲;=1 ,计数功能,计数引脚 T0(T1) 输入的负脉冲。
GATE C/T M1 M0 GATE C/T M1 M0
T1 T0
定时器初始化编程:1. 功能选择(定时 / 计数)2. 位数选择( 8/13/16 位)3. 启动方式选择(内部启动 / 外部启动)4. 启动控制(启动 / 停止)5. 恢复初值方式(自动重装 / 软件重装)
2 )方式选择位 M1 、 M0 : 4 种工作方式: 13/16/8 位
3 )门控方式选择位 GATE : =0 ,非门控方式 ( 内部启动 ) :
TRx=1 ,启动定时器工作;TRx=0 ,停止定时器工作。
=1 ,门控方式 ( 外部启动 ) : TRx=1 且引脚 INTx=1 才启动。
确定定时器工作方式指令: MOV TMOD , # 方式字例:设 T0 用方式 2 非门控定时, T1 用方式 1 门控计数。
MOV TMOD , #
M1 M0 方式 功能描述0 0 0 13 位0 1 1 16 位1 0 2 8 位自动重装1 1 3 T0 为两个 8 位
GATE C/T M1 M0 GATE C/T M1 M0
2.TCON 定时器控制 / 状态寄存器1 )启动控制位 TR0 、 TR1=0 ,停止定时器工作=1 ,启动定时器工作例:启动 T0 : SETB TR0
2 )溢出中断标志位 TF0 、 TF1定时器溢出使 TFx=1 ,引起中断请求, CPU 响应 Tx 中断后,
自动清 0 TFx 。
3 .可预置初值的 16 位加 1 计数器 TH0 、 TL0 、 TH1 、 TL1预置 T0 初值指令: MOV TH0 , #XH
MOV TL0 , #XL
可用软件检测 TFx ,必须软件清 0 。WAIT : JBC TF0 , NEXT ;检测 T0 是否溢出
SJMP WAIT ;未溢出,继续检测NEXT : … ;溢出, TF0 清 0 ,处理溢出
位地址 8F 8E 8D 8C 8B 8A 89 88位符号 TF
1TR
1TF
0TR
0IE
1IT
1IE0 IT
0
二 . 定时器工作方式由方式选择位 M1 、 M0 设定
1. 方式 013 位定时 / 计数器。 THx 8 位和 TLx 低 5 位组成 13 位加 1 计数器
计数外部脉冲个数: 1 ~ 8192(213)定时时间 (T=1s) : 1s ~ 8.19ms
2. 方式 116 位定时 / 计数器。 THx8 位和 TLx8 位组成 16 位加 1 计数器
计数外部脉冲个数: 1 ~ 65536(216)定时时间 (T=1s) : 1s ~ 65536×T= 65.54ms
以下假定以下假定 12M12M晶晶振振
3. 方式 2自动恢复初值 8 位定时 / 计数器。 TLx 为 8 位
加 1 计数器, THx 为 8 位初值暂存器。
用于需要重复定时和计数的场合。最大计数值: 256 (28)最大定时时间 (T=1s) : 256s
4. 方式 3T0 分成 2 个 8 位定时器: TL0 定时 / 计数器和 TH0 定时器TL0占用 T0 控制位: C/T , TR0 , GATE ;TH0占用 T1 控制位: TR1 。T1 不能使用方式 3 工作
5. 计算时间常数 X( 计算初值 )计数功能: X= 2n - 计数值 n: 8/13/16 定时功能: X= 2n - t/T t:定时时间、 T :机器周期
6-3-1 MCS-51 定时器的应用1 、定时器初始化编程:
MOV TMOD , # 方式字;选择方式MOV THx , #XH ;装入 Tx 时间常数MOV TLx , #XL
(SETB EA ) ;开 Tx 中断(SETB ETx ) SETB TRx ;启动 Tx 定时器1. 按实际需要选择定时 / 计数功能2. 按时间或计数长度选择方式3. 计算时间常数
6-3 6-3 计数计数 // 定时器应用举例定时器应用举例
定时器初始化编程:1. 功能选择(定时 / 计数)2. 位数选择( 8/13/16 位)3. 启动方式选择(内部启动 / 外部启动)4. 启动控制(启动 / 停止)5. 恢复初值方式(自动重装 / 软件重装)
初始化编程格式:
使用定时器工作之前,先写入控制寄存器,确定好定时器工作方式
位序 B7 B6 B5 B4 B3 B2 B1 B0
位符号 GATE C/ T M1 M0 GATE C/ T M1 M0
2. 溢出处理编程格式:
1 )查询方式:先查询定时器溢出标志,再进行溢出处理。… ;定时器初始化
WAIT : JBC TFx , PT ;检测溢出标志SJMP WAIT
PT : MOV THx , #XH ;重装时间常数MOV TLx , #XL
… ;溢出处理SJMP WAIT
2 )中断方式:初始化后执行其他任务,中断服务程序处理溢出。ORG 0000HLJMP MAINORG 000BH(001BH) ; Tx 中断入口LJMP PTS
MAIN : … ;初始化后执行其他程序PTS : … ;溢出中断服务程序
MOV THx , #XH ;重装时间常数MOV TLx , #XLRETI
位地址 8F 8E 8D 8C 8B 8A 89 88
位符号 TF1
TR1
TF0
TR0IE1 IT1 IE0 IT0
6-3-2. 应用举例例:由 P1.0 输出方波信号,周期为 2ms ,设 fosc=12MHz。
2ms
解:每隔 1ms改变一次 P1.0 的输出状态。用 T0 非门控方式 1 定时。计算时间常数: X = 216 - t/T = 216 -1000/1 = FC18H( 1 )查询方式:
START : MOV TMOD , #01hMOV TL0 , #18hMOV TH0 , #0fchSETB TR0
LOOP : JBC TF0 , PTF0SJMP LOOP
PTF0 : CPL P1.0MOV TL0 , #18hMOV TH0 , #0fchSJMP LOOP
位序 B7 B6 B5 B4 B3 B2 B1 B0
位符号 GATE
C/T
M1
M0
GATE
C/T
M1
M0
( 2 )中断方式 ORG 0000H
AJMP MAINORG 000BHAJMP PT0INTORG 0100H
MAIN : MOV SP , #60HMOV TMOD , #MOV TL0 , #MOV TH0 , #SETB EASETB ET0SETB TR0
HERE : SJMP HERE PT0INT : CPL P1.0
MOV TL0 , #MOV TH0 , #RETI
例 P1.7 驱动 LED亮 1秒灭 1秒地闪烁,设时钟频率为 6MHz。长定时方法:增加一个软件计数器或一个硬件计数器。硬件方式: T0 定时, T1 计数 T0 的定时跳变信号 P1.0 的负跳
变次数,计满 5 个跳变为 1秒。START : MOV TMOD , #61H
MOV TL1 , #0FBH MOV TH1 , #0FBH CLR P1.0 SETB TR1
LOOP1 : CPL P1.7LOOP2 : MOV TL0 , #3CH
MOV TH0 , #0B0H SETB TR0
LOOP3: JBC TF0 , LOOP4SJMP LOOP3
LOOP4 : CPL P1.0JBC TF1 , LOOP1SJMP LOOP2
例定时器外部引脚 T0(T1) 用作外部中断信号输入端。外部负脉冲引起中断请求,选计数方式,时间常数为 FFH 。
例:门控方式测量正脉冲宽度解: INT1 引脚输入被检测信号,记录在正脉冲的时间内
包含机器脉冲个数。1 )设脉宽小于 65.5ms等待查询 INT0 ,正脉冲过后,读出 TH1TL1 。
START : MOV TMOD , #90H MOV TL1 , #0H MOV TH1 , #0H
WAIT1 : JB P3.3 , WAIT1 SETB TR1
WAIT2 : JNB P3.3 , WAIT2 WAIT3 : JB P3.3 , WAIT3
CLR TR1MOV R2 , TL1MOV R3 , TH1
…
TR1=1 T1 启动 TR1=0 T1 停止
INT1
2 )设脉宽大于 65.5ms ,中断方式记录 TH1TL1 溢出中断次数。 SETB TR1
SETB ET1 ;开 T1 中断SETB EA
WAIT2 : JNB P3.3 , WAIT2 ;等待正脉冲到来WAIT3 : JB P3.3 , WAIT3 ;等待正脉冲结束
CLR TR1 ;关闭 T1MOV IE , #00 ;关闭中断MOV R2 , TL1 ;读出 T1MOV R3 , TH1LCALL PPS ;计算脉宽
HERE : SJMP HERE ;其他任务PRIC : INC R4 ;记录溢出次数
RETIPPS : … ;计算脉宽子程序
计算脉宽的子程序的计算式如下:脉宽 t = ( R4 ×216 + R3 R2 ) ×T ( T 为机器周期)
定时、中断练习一定时、中断练习一1 、利用定时器实现灯的闪烁我们可以用定时器来实现灯的闪烁的功能。例 1 :查询方式
ORG 0000HAJMP STARTORG 30HSTART:MOV P1,#0FFH ; 关所 灯MOV TMOD,#00000001B ;定时 / 计数器 0 工作于方式 1MOV TH0,#15H MOV TL0,#0A0H ;即数 5536SETB TR0 ;定时 / 计数器 0 开始运行LOOP:JBC TF0,NEXT ; 如果 TF0 等于 1 ,则清 TF0并转 NEXT 处AJMP LOOP ;否则跳转到 LOOP 处运行NEXT:CPL P1.0MOV TH0,#15HMOV TL0,#9FH; 重置定时 / 计数器的初值AJMP LOOPEND AJMP LOOPEND
以上程序是可以实现灯的闪烁了,主程序除了让灯闪烁外,还做其他的事啊!我们可以在 LOOP :……和 AJMP LOOP 指令之间插入一些指令来做其他的事情,只要保证执行这些指令的时间少于定时时间就行了。那我们在用软件延时程序的时候不是也可以用一些指令来替代 DJNZ吗?是的,但是那就要求你精确计算所用指令的时间,然后再减去相应的 DJNZ循环次数,很不方便,而现在只要求所用指令的时间少于定时时间就行,显然要求低了。当然,这样的方法还是不好,所以我们常用以下的方法来实现。
键入程序,灯在闪烁了,这是用定时器做的,不再是主程序的循环了。简单地分析一下程序,为什么用 JBC 呢? TF0 是定时 / 计数器 0 的溢出标记位,当定时器产生溢出后,该位由 0 变 1 ,所以查询该位就可知定时时间是否已到。该位为 1后,要用软件将标记位清 0 ,以便下一次定时是间到时该位由 0 变 1 ,所以用了JBC 指令,该指位在判 1转移的同时,还将该位清 0 。
程序程序 22 :用中断实现 :用中断实现 ORG 0000HAJMP STARTORG 000BH ;定时器 0 的中断向量地址AJMP TIME0 ; 跳转到真正的定时器程序处ORG 30HSTART:MOV P1,#0FFH ; 关所 灯MOV TMOD,#00000001B ;定时 / 计数器 0 工作于方式 1MOV TH0,#15H MOV TL0,#0A0H ;即数 5536SETB EA ;开总中断允许SETB ET0 ;开定时 / 计数器 0允许SETB TR0 ;定时 / 计数器 0 开始运行LOOP: AJMP LOOP ; 真正工作时 ,这里可写任意程序TIME0: ;定时器 0 的中断处理程序PUSH ACCPUSH PSW ;将 PSW 和 ACC推入堆栈保护CPL P1.0 MOV TH0,#15HMOV TL0,#0A0H ;重置定时常数POP PSWPOP ACCRETIEND
例子中,定时时间一到, TF0 由 0 变1 ,就会引发中断, CPU 将自动转至000B 处寻找程序并执行,由于留给定时器中断的空间只有 8 个字节,显然不足以写下所有有中断处理程序,所以在 000B 处安排一条跳转指令,转到实际处理中断的程序处,这样,中断程序可以写在任意地方,也可以写任意长度了。进入定时中断后,首先要保存当前的一些状态,程序中只演示了保存存 ACC 和 PSW ,实际工作中应该根据需要将可能会改变的单元的值都推入堆栈进行保护(本程序中实际不需保存护任何值,这里只作个演示)。
上面的两个程序运行后,我们发现灯的闪烁非常快,根本分辨不出来,只是视觉上感到灯有些晃动而已,为什么呢?我们可以计算一下,定时器中预置的数是 5536 ,所以每计 60000 个脉冲就是定时时间到,这 60000 个脉冲的时间是多少呢?我们的晶振是 12M ,所以就是 60000微秒,即 60毫秒,因此速度是非常快的。如果想实现一个 1S 的定时,该怎么办呢?在该晶振濒率下,最长的定时也就是 65 。 536 个毫秒啊!给出一个例子。
START:MOV P1,#0FFH ; 关所 灯MOV 30H,#00H ;软件计数器预清 0MOV TMOD,#00000001B ;定时 / 计数器 0 工作于方式 1MOV TH0,#3CH MOV TL0,#0B0H ;即数 15536SETB EA ;开总中断允许SETB ET0 ;开定时 / 计数器 0允许SETB TR0 ;定时 / 计数器 0 开始运行LOOP: AJMP LOOP ; 真正工作时 ,这里可写任意程序TIME0: ;定时器 0 的中断处理程序PUSH ACCPUSH PSW ;将 PSW 和 ACC推入堆栈保护INC 30HMOV A,30HCJNE A,#20,T_RET ;30H 单元中的值到了 20 了吗 ?T_L1: CPL P1.0 ;到了 , 取反 P10MOV 30H,#0 ;清软件计数器T_RET:MOV TH0,#15HMOV TL0,#9FH ;重置定时常数POP PSWPOP ACCRETIEND
先自己分析一下,看看是怎么实现的?这里采用了软件计数器的概念,思路是这样的,先用定时 / 计数器 0做一个 50毫秒的定时器,定时是间到了以后并不是立即取反 P10 ,而是将软件计数器中的值加 1 ,如果软件计数器计到了 20 ,就取反 P10 ,并清掉软件计数器中的值,否则直接返回,这样,就变成了 20 次定时中断才取反一次 P10 ,因此定时时间就延长了成了 20*50 即 1000毫秒了。
ORG 0000HAJMP STARTORG 000BH ;定时器 0 的中断向量地址AJMP TIME0 ; 跳转到真正的定时器程序处ORG 30H
这个思路在工程中是非常有用的,有的时候我们需要若干个定时器,可 51 中总共才有 2 个,怎么办呢?其实,只要这几个定时的时间有一定的公约数,我们就可以用软件定时器加以实现,如我要实现P10口所接灯按 1S 每次,而 P11口所接灯按 2S 每次闪烁,怎么实现呢?对了我们用两个计数器,一个在它计到 20 时,取反 P10 ,并清零,就如上面所示,另一个计到 40取反 P11 ,然后清 0 ,不就行了吗?这部份的程序如下
ORG 0000HAJMP STARTORG 000BH ;定时器 0 的中断向量地址AJMP TIME0 ; 跳转到真正的定时器程序处ORG 30HSTART:MOV P1,#0FFH ; 关所 灯MOV 30H,#00H ;软件计数器预清 0MOV TMOD,#00000001B ;定时 / 计数器 0 工作于方式 1MOV TH0,#3CH MOV TL0,#0B0H ;即数 15536SETB EA ;开总中断允许SETB ET0 ;开定时 / 计数器 0允许SETB TR0 ;定时 / 计数器 0 开始运行
LOOP: AJMP LOOP ;工作时 ,这里可写任意程序TIME0: ;定时器 0 的中断处理程序PUSH ACCPUSH PSW ;将 PSW 和 ACC推入堆栈保护INC 30HINC 31H ;两个计数器都加 1MOV A,30HCJNE A,#20,T_NEXT ;30H 单元中的值到了 20吗 ?T_L1: CPL P1.0 ;到了 , 取反 P10MOV 30H,#0 ;清软件计数器T_NEXT:MOV A,31HCJNE A,#40,T_RET ;31h单元中的值到 40 了吗 ?T_L2:CPL P1.1MOV 31H,#0 ;到了 , 取反 P11,清计数器 , 返回T_RET:MOV TH0,#15HMOV TL0,#9FH ;重置定时常数POP PSWPOP ACCRETIEND
定时 / 计数器实验 2 前面我们做了定时器的实验,现在来看一看计数实验,在工作中计数通常会有两种要求:第一、将计数的值显示出来,第二、计数值到一定程度即中断报警。第一种如各种计数器、里程表,第二种如前面例中讲到的生产线上的计数。先看第一种吧。我们的硬件中是这样连线的: 324构成的振荡器连到定时 / 计数器 1 的外部引脚 T1上面,我们就利用这个来做一个计数实验,要将计数的值显示出来,当然最好用数码管了,可我们还没讲到这一部份,为了避免把问题复杂化,我们用 P1口的 8 个 LED来显示计到的数据。
程序如下:ORG 0000H AJMP START ORG 30H START: MOV SP,#5FH MOV TMOD,#01000000B ;定时 / 计数器 1 作计数用 ,0 不用全置 0 SETB TR1 ;启动计数器 1 开始运行 . LOOP: MOV A,TL0 MOV P1,A AJMP LOOPEND
在硬件上用线将 324 的输出与 T1连通 (印板上有焊盘 )运行这种程序,注意将板按正确的位置放置( LM324放在左手边, LED排列是按从高位到低们排列)看到什么?随着 324 后接的 LED 的闪烁,单片机的 8 只 LED也在不断变化,注意观察,是不是按二进制:00000000000000010000001000000011。这样的顺序在变呢?这就对了,这就是 TL0 中的数据。
程序二:ORG 0000H AJMP START ORG 001BH AJMP TIMER1 ;定时器 1 的中断处理ORG 30H START: MOV SP,#5FH MOV TMOD,#01010000B ;定时 / 计数器 1 作计数用 , 模式 1,0 不用全置 0 MOV TH1,#0FFH MOV TL1,#0FAH ;预置值 ,要求每计到 6 个脉冲即为一个事件 SETB EASETB ET1 ;开总中断和定时器 1 中断允许 SETB TR1 ;启动计数器 1 开始运行 . AJMP $ TIMER1: PUSH ACC PUSH PSW CPL P1.0 ;计数值到 ,即取反 P1.0 MOV TH1,#0FFH MOV TL1,#0FAH ;重置计数初值POP PSW POP ACC RETI END 上面这个程序完成的工作很简单,就是在每 6 个脉冲到来后取反一次 P1 。 0 ,因此实验的结果应当是: LM324 后接的 LED亮、灭 6 次,则 P1 。 0口所接 LED亮或灭一次。这实际就是我们上面讲的计数器的第二种应用。
程序三:外部中断实验ORG 0000H AJMP START ORG 0003H ;外部中断地直入口 AJMP INT0 ORG 30H START: MOV SP,#5FH MOV P1,#0FFH ; 灯全灭 MOV P3,#0FFH ;P3口置高电平 SETB EA SETB EX0 AJMP $ INT0: PUSH ACC PUSH PSW CPL P1.0 POP PSW POP ACC RETI END 本程序的功能很简单,按一次按键 1 (接在 12 引脚上的)就引发一次中断 0 ,取反一次P1 。 0 ,因此理论上按一下灯亮,按一下灯灭,但在实际做实验时,可能会发觉有时不“灵”,按了它没反应,但在大部份时候是对的,这是怎么回事呢?我们在讲解键盘时再作解释,这个程序本身是没有问题的。