STC89C52RC 的定时/计数器是单片机内部非常重要的可编程资源。它的核心是一个 16位加1计数器,通过选择不同的计数脉冲来源,可以分别实现"定时"和"计数"两种看似相反、但原理相通的功能。
1.TMOD

TMOD 是工作方式寄存器,地址为 89H,不可位寻址,需要整体赋值。TMOD 的高 4 位控制 T1,低 4 位控制 T0。其中 TMOD.7 和 TMOD.3 是 GATE 门控位:当 GATE=0 时,软件置 TRx=1 即可启动定时/计数器;当 GATE=1 时,除了 TRx=1 外,还需要 INTx 引脚为高电平才能启动,常用于测量脉宽。TMOD.6 和 TMOD.2 是 C/T 位:C/T=0 为定时模式,C/T=1 为计数模式。

TMOD.5 和 TMOD.4 以及 TMOD.1 和 TMOD.0 分别是 T1 和 T0 的 M1、M0 位,用来选择工作方式 0 到 3。

定时器和计数器共用同一套硬件,区别仅在于计数脉冲的来源:

2.TCON

TCON 是控制寄存器,地址为 88H,可位寻址,与定时器直接相关的有 4 位。TCON.7 和 TCON.5 分别是 TF1 和 TF0,即溢出标志位;计满溢出时硬件自动置 1,**进入中断后硬件自动清零,也可以由软件清零。**TCON.6 和 TCON.4 分别是 TR1 和 TR0,即运行控制位;软件置 TRx=1 启动计数,清 0 停止计数。
3.案例实现
STC89C52RC 的定时器有两种计数速率,在烧录程序时通过 STC-ISP 软件选择。12T 模式是默认模式,每 12 个时钟周期计数一次,与传统 8051 一致;6T 模式每 6 个时钟周期计数一次,计数速度是 12T 模式的两倍。以常见的 11.0592 MHz 晶振、12T 模式为例,机器周期等于 12 除以 11 059 200,约为 1.085 微秒,即每经过约 1.085 微秒,定时器加 1。

方式 1 的初值计算公式为:初值等于 65536 减去目标时间秒数乘以晶振频率再除以 12。例如,11.0592 MHz 晶振、12T 模式、定时 20 毫秒时,计数值等于 0.02 乘以 11 059 200 再除以 12,结果为 18432;初值等于 65536 减去 18432,得到 47104,即十六进制 0xB800,所以 TH0 写 0xB8,TL0 写 0x00。标准配置流程是:先写 TMOD,设定工作方式、定时或计数、门控;再写 THx 和 TLx,装入初值;然后置位 TRx,启动计数;最后处理溢出,可以查询 TFx 或使能中断。
下面给出一个完整示例:定时器 0 方式 1 查询方式在 P1.0 上产生 40 毫秒周期的方波,每 20 毫秒翻转一次电平。
cs
#include <reg52.h>
void main(void)
{
TMOD = 0x01; // T0 方式1,定时模式,GATE=0
TH0 = 0xB8; // 20 ms 初值 @11.0592MHz, 12T
TL0 = 0x00;
TR0 = 1; // 启动 T0
while (1)
{
if (TF0) // 查询溢出标志
{
TF0 = 0; // 软件清零
TH0 = 0xB8; // 方式1必须软件重装初值
TL0 = 0x00;
P1_0 = ~P1_0; // 翻转 P1.0,形成方波
}
}
}
如果改用中断方式,则需要在初始化中使能 ET0=1 和 EA=1,溢出后硬件自动清零 TF0,在中断服务函数中重装初值并执行翻转操作。
cs
#include <reg52.h>
void Timer0_ISR(void) interrupt 1 // 1 对应定时器0
{
// 清除标志位(定时器0硬件通常自动清除,此处为逻辑严谨可手动处理)
TH0 = 0xB8; // 方式1必须软件重装初值
TL0 = 0x00;
P1^0 = ~P1^0; // 翻转 P1.0,形成方波
}
void main()
{
EA = 1; // 打开总中断(关键步骤)
ET0 = 1; // 打开定时器0中断
// ... 初始化定时器0(TMOD, TH0, TL0)并启动(TR0=1)
TMOD = 0x01; // T0 方式1,定时模式,GATE=0
TH0 = 0xB8; // 20 ms 初值 @11.0592MHz, 12T
TL0 = 0x00;
TR0 = 1; // 启动 T0
while (1);
}