51单片机从零到实战(7)——定时器

第 7 篇:定时器——精确控制时间

之前我们一直用 delay() 延时——两个 for 循环空转,精度差、阻塞 CPU。定时器彻底解决这个问题。


1. 定时器原理

STC89C52 的定时器本质是一个 16 位计数器:

TH0(高 8 位)  TL0(低 8 位)
┌──────┬──────┐
│ 0x3C │ 0xB0 │ = 0x3CB0 = 15536
└──────┴──────┘

每个机器周期(12 个时钟周期)计数器 +1
从 15536 加到 65536(溢出)= 50000 个机器周期

50000 × (12/11.0592MHz) = 50000 × 1.085μs ≈ 54ms

2. 初值计算

// 定时 50ms(晶振 11.0592MHz,12T 模式)
// 计数次数 = 50ms / (12 / 11059200) = 46080
// 初值 = 65536 - 46080 = 19456 = 0x4C00

TH0 = 0x4C;
TL0 = 0x00;

为什么用 11.0592MHz?因为它能被波特率整除——串口通信不会产生误差。


3. 用定时器实现精确 LED 闪烁

unsigned int count_50ms = 0;  // 50ms 计数器

void timer0_init(void)
{
    TMOD &= 0xF0;   // 低 4 位清零(定时器 0)
    TMOD |= 0x01;   // 方式 1(16 位定时器)
    TH0 = 0x4C;     // 初值 = 19456
    TL0 = 0x00;
    ET0 = 1;        // 使能定时器 0 中断
    TR0 = 1;        // 启动定时器 0
    EA  = 1;
}

void timer0_isr(void) interrupt 1
{
    TH0 = 0x4C;   // 重装初值
    TL0 = 0x00;

    count_50ms++;
    if (count_50ms >= 20) {  // 20×50ms = 1 秒
        count_50ms = 0;
        LED = ~LED;  // 每秒翻转一次
    }
}

void main()
{
    timer0_init();
    LED = 1;
    while (1) {
        // 主循环可以干别的事了
        // 数码管扫描、按键检测...全塞这里
    }
}

4. 用定时器做数码管动态扫描

前面第 4 篇我们用的 delay() 做扫描——占 CPU。用定时器才是正道:

void timer0_isr(void) interrupt 1
{
    TH0 = 0xFC;   // 定时 1ms
    TL0 = 0x66;

    display_scan();  // 每 1ms 切换一位数码管
    // 4 位数码管 = 4ms 一轮 = 250Hz 刷新率 → 完全看不到闪烁
}

5. 小结

  • 定时器 = 硬件计数器,溢出时触发中断
  • 初值 = 65536 - (定时时间 / 机器周期)
  • 用定时器 + 计数变量替代 delay(),CPU 利用率飙升
  • 数码管扫描、按键检测、LED 闪烁全可以挂在定时器中断里

下一篇:串口通信——让单片机"说话"


下一篇:串口通信——让单片机"说话"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值