1. 定时器与计数器的本质区别第一次接触STC15单片机时我也曾被定时器和计数器这两个概念搞糊涂过。后来在实际项目中才发现它们本质上就是同一个硬件模块的不同工作模式。想象一下你手里拿着一个机械计数器每按一次按钮数字就加1。如果你按照固定节奏按按钮比如每秒一次这就是定时器如果用来统计随机按下的次数这就是计数器。具体到STC15单片机定时器模式下会计数系统时钟脉冲。比如使用11.0592MHz晶振时每个时钟周期约90ns。而计数器模式下则会计数外部引脚如P3.4/T0、P3.5/T1的脉冲信号这在测量旋转编码器或频率时会非常有用。我做过一个电机转速测量项目就是用T0计数器模式统计编码器脉冲实测精度能达到±2RPM。2. 关键寄存器深度解析2.1 模式控制寄存器TMOD这个8位寄存器控制着T0和T1的工作模式每个定时器占用4位。最容易被忽视的是GATE位bit3/bit7当设置为1时定时器启停会受外部INT引脚控制。我曾用这个特性实现过电源管理——只有按下按键才启动定时器节省了80%的待机功耗。典型配置示例// T0定时模式1T1计数器模式2 TMOD 0x21; // 二进制解释0010 0001 // T1模式2(8位自动重载) | T0模式1(16位定时)2.2 速度控制寄存器AUXRSTC15的1T/12T模式切换就靠这个寄存器。新手常犯的错误是忽略时钟分频对定时初值的影响。实测在1T模式下同样的初值定时时间会缩短12倍。建议调试时先用12T模式稳定后再切到1T模式。关键位说明T0x12(bit7)T0速度选择T1x12(bit6)T1速度选择T2x12(bit2)T2速度选择3. 精准定时实战技巧3.1 1秒定时的三种实现方案方案A中断累计法unsigned int ticks 0; void Timer0_ISR() interrupt 1 { if(ticks 1000) { ticks 0; P1 ^ 0x01; // 每秒翻转LED } }这是最易理解的方式但存在累计误差。我在温控系统中实测发现24小时会偏差约3秒。方案B自动重装载优化法#define TIMER_RELOAD (65536 - FOSC/1000) TH0 TIMER_RELOAD 8; TL0 TIMER_RELOAD 0xFF;通过精确计算重载值误差可控制在0.01%以内。注意晶振频率要实测校准我用的11.0592MHz实际测得是11.0587MHz。方案CT2硬件辅助法STC15的T2有独立时钟源配合AUXR的T2_C/T位可以实现更高精度定时。在RFID读卡器项目中我用这个方法实现了±50ppm的时钟精度。3.2 抗干扰设计经验在工业现场遇到过定时器异常复位的问题后来总结出几个关键点初始化时先停止定时器TR00设置模式后再赋初值最后才开启中断和定时器 这个顺序能避免毛刺触发错误中断。4. 计数器模式的进阶应用4.1 频率测量实战用T1计数器定时器组合测量频率代码框架如下void MeasureFreq() { TMOD 0x51; // T1计数模式1T0定时模式1 TH0 (65536-50000)/256; // 50ms定时 TL0 (65536-50000)%256; while(!TF0); freq (TH18)|TL1) * 20; }实测注意事项输入信号幅度需0.5Vcc高频测量建议使用T2的捕获功能超过65535Hz时要配合中断累计4.2 旋转编码器处理通过配置TMOD的计数器模式配合外部中断可以实现四倍频解码sbit PHASE_A P3^4; sbit PHASE_B P3^5; void ExtInt0() interrupt 0 { if(PHASE_A ^ PHASE_B) Counter; else Counter--; }这种方案比纯软件解码节省80%的CPU资源。