四、定时/计数器(流水灯延时、定时)
下面讲复习提纲第四部分:四、定时/计数器。这一部分常考定时器功能、工作方式、TMOD/TCON、方式1和方式2、初值计算、定时器中断程序,也是流水灯延时、秒表、交通灯倒计时的核心。
1. 定时器/计数器是干什么的
Section titled “1. 定时器/计数器是干什么的”复习提纲中写:
定时功能:对系统机器周期计数,实现精准延时、定时计数功能:对外部引脚脉冲计数,用于测速、计数这句话可以拆成两层。
第一层:定时器功能
Section titled “第一层:定时器功能”定时器对单片机内部的机器周期脉冲计数。
比如 12MHz 晶振下,标准 51 单片机:
1个机器周期 = 1us如果定时器每 1us 加 1,那么:
计数1000次 ≈ 1ms计数50000次 ≈ 50ms计数1000000次 ≈ 1s当然 16 位定时器一次最多只能计 65536 次,所以长时间定时通常要多次中断累加。
定时器常用于:
LED定时闪烁流水灯定时切换秒表电子钟交通灯倒计时按键扫描定时采样传感器第二层:计数器功能
Section titled “第二层:计数器功能”计数器对外部引脚输入的脉冲计数。
T0 和 T1 的外部输入引脚是:
T0:P3.4T1:P3.5例如传送带上每经过一个物体,传感器输出一个脉冲,计数器加 1,就能统计产品数量。
计数器常用于:
外部事件计数产品计数转速测量频率测量脉冲计数考试答法:
定时器/计数器既可对内部机器周期脉冲计数实现定时,也可对外部引脚输入脉冲计数实现事件计数。2. 定时器和计数器本质上是同一个东西
Section titled “2. 定时器和计数器本质上是同一个东西”很多同学会以为“定时器”和“计数器”是两个完全不同的硬件。其实在 51 单片机里,它们本质上都是加 1 计数器,只是计数脉冲来源不同。
定时器模式:计内部脉冲计数器模式:计外部脉冲可以这样理解:
定时器:数时间的脉冲计数器:数外部事件的脉冲模式选择由 TMOD 中的 C/T 位决定:
C/T = 0:定时器模式C/T = 1:计数器模式3. TMOD 工作方式控制寄存器
Section titled “3. TMOD 工作方式控制寄存器”TMOD 用来设置 T0、T1 的工作方式和工作模式。
它的特点:
字节地址89H不可位寻址高4位控制T1低4位控制T0结构可以理解为:
高4位:GATE C/T M1 M0 -> 控制T1低4位:GATE C/T M1 M0 -> 控制T03.1 GATE:门控位
Section titled “3.1 GATE:门控位”GATE=0:只由TRx控制启动和停止GATE=1:由TRx和INTx引脚电平共同控制一般初学程序都用:
GATE=0也就是只靠程序中的 TR0=1 或 TR1=1 启动。
3.2 C/T:定时器/计数器选择
Section titled “3.2 C/T:定时器/计数器选择”C/T=0:定时器模式,对内部机器周期计数C/T=1:计数器模式,对外部输入脉冲计数定时器程序里通常是 C/T=0。
3.3 M1、M0:工作方式选择
Section titled “3.3 M1、M0:工作方式选择”| M1 M0 | 工作方式 | 特点 |
|---|---|---|
| 00 | 方式0 | 13位计数器,较少使用 |
| 01 | 方式1 | 16位计数器,最常用 |
| 10 | 方式2 | 8位自动重装,考试常考 |
| 11 | 方式3 | T0拆成两个8位计数器 |
如果 T0 设置为方式1定时器模式:
GATE=0, C/T=0, M1=0, M0=1低4位 = 0001B = 1TMOD = 0x01所以常见代码:
TMOD = 0x01; // T0方式1定时如果 T1 设置为方式2定时器模式:
高4位 = 0010BTMOD = 0x20常见于串口波特率:
TMOD = 0x20; // T1方式24. TCON 定时器控制寄存器
Section titled “4. TCON 定时器控制寄存器”TCON 中既有定时器控制位,也有外部中断控制位。这里重点看高 4 位:
| 位 | 名称 | 作用 |
|---|---|---|
| TF1 | T1溢出标志 | T1溢出后硬件置1 |
| TR1 | T1运行控制 | 1启动T1,0停止T1 |
| TF0 | T0溢出标志 | T0溢出后硬件置1 |
| TR0 | T0运行控制 | 1启动T0,0停止T0 |
启动 T0:
TR0 = 1;停止 T0:
TR0 = 0;查询 T0 是否溢出:
if (TF0 == 1){ TF0 = 0; // 溢出处理}如果用中断方式,进入 T0 中断后,TF0 通常由硬件自动清零。
5. 四种工作方式
Section titled “5. 四种工作方式”5.1 方式0:13位计数器
Section titled “5.1 方式0:13位计数器”方式0 是 13 位计数器,由 THx 的 8 位和 TLx 的低 5 位组成。
它主要是为了兼容早期 MCS-48 系列,实际使用较少。考试通常只要求知道:
方式0是13位定时/计数方式。一般程序题不会优先让你用方式0。
5.2 方式1:16位计数器,最常用
Section titled “5.2 方式1:16位计数器,最常用”方式1由 THx 和 TLx 组成 16 位计数器。
THx:高8位TLx:低8位最大计数范围:
0000H -> FFFFH共65536个状态从装入初值开始加 1,一直加到溢出。
公式:
定时时间 = (65536 - 初值) × 机器周期初值 = 65536 - 定时时间 / 机器周期例题:12MHz 晶振,T0方式1定时1ms
Section titled “例题:12MHz 晶振,T0方式1定时1ms”已知:
晶振 = 12MHz机器周期 = 12 / 12MHz = 1us定时时间 = 1ms = 1000us需要计数:
N = 1000us / 1us = 1000初值:
初值 = 65536 - 1000 = 64536转十六进制:
64536 = FC18H所以:
TH0 = 0xFC;TL0 = 0x18;方式1注意点
Section titled “方式1注意点”方式1溢出后,计数器会回到 0。如果你想每 1ms 都中断一次,就要在中断服务程序中重新装初值:
void timer0_isr(void) interrupt 1{ TH0 = 0xFC; TL0 = 0x18;}5.3 方式2:8位自动重装,考试最爱
Section titled “5.3 方式2:8位自动重装,考试最爱”复习提纲说:
方式2优点:自动重装初值,无需程序手动赋值,定时精准、适合做波特率发生器。方式2中:
TLx:真正计数THx:保存重装初值当 TLx 溢出时,硬件自动把 THx 的值重新装入 TLx。
可以理解为:
THx = 备份初值TLx = 正在跑的计数器方式2是 8 位计数,最大计数值是 256。
定时时间 = (256 - 初值) × 机器周期初值 = 256 - 定时时间 / 机器周期例如 12MHz 晶振下,想让 T0 每 100us 溢出:
机器周期 = 1us计数次数 = 100初值 = 256 - 100 = 156 = 9CH所以:
TMOD = 0x02; // T0方式2TH0 = 0x9C;TL0 = 0x9C;TR0 = 1;方式2为什么适合波特率
Section titled “方式2为什么适合波特率”串口通信需要稳定周期产生发送/接收节拍。方式2自动重装,减少了中断重装初值造成的误差,所以常用 T1 方式2做波特率发生器。
例如 11.0592MHz 晶振,9600bps 常见设置:
TMOD = 0x20; // T1方式2TH1 = 0xFD;TL1 = 0xFD;TR1 = 1;5.4 方式3:T0拆分方式
Section titled “5.4 方式3:T0拆分方式”方式3只适用于 T0。它把 T0 拆成两个独立的 8 位计数器:
TL0:一个8位计数器TH0:另一个8位计数器这种方式较特殊,T1 的某些控制资源会被占用。考试一般只要求知道:
方式3把T0分成两个8位定时/计数器,T1通常不作为普通中断定时器使用,可作为串口波特率发生器。6. 定时器中断应用
Section titled “6. 定时器中断应用”定时器最常见的应用不是单纯查询 TF0,而是使用中断。
典型结构:
初始化定时器装初值开定时器中断开总中断启动定时器主程序循环定时器溢出时自动进入中断T0 方式1,1ms中断一次
Section titled “T0 方式1,1ms中断一次”#include <reg51.h>
unsigned int ms_count = 0;sbit LED = P1^0;
void main(void){ TMOD = 0x01; // T0方式1,定时器模式 TH0 = 0xFC; // 12MHz下1ms初值 TL0 = 0x18; ET0 = 1; // 开T0中断 EA = 1; // 开总中断 TR0 = 1; // 启动T0
while (1) { // 主程序可以做其他事情 }}
void timer0_isr(void) interrupt 1{ TH0 = 0xFC; // 重装初值 TL0 = 0x18;
ms_count++; if (ms_count >= 500) { ms_count = 0; LED = !LED; // 约500ms翻转一次 }}这个程序可以理解为:
每1ms进一次中断累计500次就是500ms每500ms翻转一次LED7. 流水灯延时:软件延时和定时器延时
Section titled “7. 流水灯延时:软件延时和定时器延时”7.1 软件延时
Section titled “7.1 软件延时”前面 I/O 口中流水灯常用软件延时:
void delay(unsigned int x){ unsigned int i, j; for (i = 0; i < x; i++) for (j = 0; j < 120; j++);}优点:
简单容易写适合初学演示缺点:
不精确CPU一直空转延时时不能及时处理其他任务受晶振和编译器影响7.2 定时器延时
Section titled “7.2 定时器延时”定时器延时用硬件计数,CPU 不必一直空转。
例如流水灯每 200ms 移动一次:
#include <reg51.h>#include <intrins.h>
unsigned int tick = 0;
void main(void){ P1 = 0xFE; TMOD = 0x01; TH0 = 0xFC; TL0 = 0x18; ET0 = 1; EA = 1; TR0 = 1;
while (1) { // 等待定时器中断改变P1 }}
void timer0_isr(void) interrupt 1{ TH0 = 0xFC; TL0 = 0x18;
tick++; if (tick >= 200) { tick = 0; P1 = _crol_(P1, 1); }}这样主程序不会被长延时卡住,更适合复杂系统。
8. 初值计算通用方法
Section titled “8. 初值计算通用方法”这是定时器最重要的计算题。
第一步:算机器周期
Section titled “第一步:算机器周期”机器周期 = 12 / 晶振频率如果晶振是 12MHz:
机器周期 = 1us如果晶振是 6MHz:
机器周期 = 2us第二步:算需要计数次数 N
Section titled “第二步:算需要计数次数 N”N = 定时时间 / 机器周期例如 12MHz 下定时 10ms:
N = 10000us / 1us = 10000第三步:算初值
Section titled “第三步:算初值”方式1:
初值 = 65536 - N方式2:
初值 = 256 - N第四步:拆成 TH 和 TL
Section titled “第四步:拆成 TH 和 TL”方式1得到 16 位初值后:
THx = 初值高8位TLx = 初值低8位例:12MHz,方式1,定时 10ms:
初值 = 65536 - 10000 = 55536 = D8F0HTH0 = D8HTL0 = F0H9. 常见考法
Section titled “9. 常见考法”考法1:问定时器和计数器区别
Section titled “考法1:问定时器和计数器区别”答案:
定时器模式对内部机器周期脉冲计数,用于产生定时;计数器模式对外部引脚输入脉冲计数,用于统计外部事件。两者本质都是加1计数器,只是计数脉冲来源不同。考法2:问工作方式
Section titled “考法2:问工作方式”答案:
方式0为13位计数器,方式1为16位计数器,方式2为8位自动重装计数器,方式3为T0拆分成两个8位计数器。考法3:问方式2优点
Section titled “考法3:问方式2优点”答案:
方式2具有自动重装初值功能,溢出后硬件自动把THx中的初值装入TLx,减少软件重装时间,提高定时精度,常用于周期定时和串口波特率发生器。考法4:计算初值
Section titled “考法4:计算初值”题目:
12MHz晶振,T0方式1定时1ms,求初值。答案:
机器周期=1us,1ms需计数1000次,初值=65536-1000=64536=FC18H,所以TH0=FCH,TL0=18H。考法5:写定时器中断初始化
Section titled “考法5:写定时器中断初始化”答案示例:
TMOD = 0x01;TH0 = 0xFC;TL0 = 0x18;ET0 = 1;EA = 1;TR0 = 1;10. 易混点
Section titled “10. 易混点”1. TMOD 和 TCON 不要混
Section titled “1. TMOD 和 TCON 不要混”TMOD:选择工作方式和定时/计数模式TCON:控制启动停止,保存溢出标志2. TR0 和 TF0 不要混
Section titled “2. TR0 和 TF0 不要混”TR0:启动/停止T0TF0:T0溢出标志3. 方式1和方式2不要混
Section titled “3. 方式1和方式2不要混”方式1:16位,范围大,但溢出后需重装初值方式2:8位,范围小,但自动重装4. 定时器中断开关要同时开 EA 和 ET0
Section titled “4. 定时器中断开关要同时开 EA 和 ET0”只写:
ET0 = 1;不够,还要:
EA = 1;5. 12MHz下机器周期不是 1/12us,而是 1us
Section titled “5. 12MHz下机器周期不是 1/12us,而是 1us”因为:
时钟周期 = 1/12MHz机器周期 = 12个时钟周期 = 1us第四部分背诵版
Section titled “第四部分背诵版”51单片机的定时器/计数器本质上是加1计数器。定时器模式对内部机器周期脉冲计数,用于实现延时和定时;计数器模式对外部T0、T1引脚输入脉冲计数,用于外部事件计数。T0外部输入引脚为P3.4,T1外部输入引脚为P3.5。
TMOD用于设置定时器/计数器的工作模式和工作方式,高4位控制T1,低4位控制T0;TCON中的TR0、TR1用于启动或停止定时器,TF0、TF1为溢出标志。定时器有方式0、方式1、方式2、方式3,其中方式1为16位计数器,最常用;方式2为8位自动重装计数器,溢出后自动重装初值,适合周期定时和串口波特率发生器。
定时器初值计算公式为:定时时间=(最大计数值-初值)×机器周期。方式1最大计数值为65536,方式2最大计数值为256。12MHz晶振下,标准51单片机1个机器周期为1us。