51实现定时器定时调整

随着学习的深入对51的认识也越来越深,尤其对中断的重要性更是深深体会!如果你是和我一样的初学者,请一定要学好中断!

今天来分享一下有关定时器定时补偿的冷知识。

不知道你是否做过这样的实验,就是当你用定时器来定时1ms来实现数码管的自动加1。随着时间的推移,会发现和真正的时间略有偏差。于是就引出了接下来所要讲的。

到底这些值差在哪里呢?主要在三个方面:

进入中断前要进行压栈,即是进行数据保护,这里要耗费几个机器周期
进出中断这个过程也要耗费一定的机器周期
进入中断后的重新赋值也要耗费一定的机器周期

所以累计误差就这么慢慢增加了。

如何补偿呢?

其实思路很简单就是进入debug,看两次中断相差的时间间隔和我们真正的定时相差多少,然后在赋初值的时候进行一个调整即可。

下面来分享一个自己的调试过程。
(以12M晶振为例)

先上自己的调试代码:

#include <reg52.h>

unsigned char T0RH;
unsigned char T0RL;

void ConfigTimer0(unsigned int ms)
{
    unsigned long tmp;

    tmp = 12000000/12;//以12M晶振为例子
    tmp = (tmp*ms)/1000;
    tmp = 65536 - tmp;
    //tmp = tmp + 6;//这里是后面进行的初值补偿
    T0RH = (unsigned char)(tmp >> 8);
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0;
    TMOD |= 0x01;
    TH0 = T0RH;
    TL0 = T0RL;
    ET0 = 1;
    TR0 = 1;
}

void main()
{   
    ConfigTimer0(1);
    EA = 1;
    while(1);   
}

void InterruptTimer0() interrupt 1
{
    TH0 = T0RH;
    TL0 = T0RL;
}


设置软件调试的晶振值
一
②进入debug
定位两次中断的时间,算出时间间隔
1
2

注意:程序定时的是1ms但是实际上却是1.006ms多出来了6us!
即压栈、进出中断、中断的赋值这些过程耗费了6个机器周期
我们知道12M晶振来说,一个机器周期就是1us,所以当赋初值的时候多上6个机器周期就可以了

③把注释去掉后的
1
2

怎么样?是不是恰好是1ms?
哇哈哈~~~~

其实这样在实际应用中也并不是精确的定时,因为我们知道一切都是相对的,没有什么是绝对的,没有什么会是永垂不朽的!所以这样定时虽然已经相当精确了,但也只能说相对!!!别忘了还有很多因素,比如气压,温度,……均会有所影响硬件!

<think>好的,我现在需要帮用户找到51单片机使用定时器实现2ms定时的程序代码。首先,我得回忆一下51单片机定时器的相关知识,以及如何配置定时器。 用户提到了引用[3]和[4],里面提到了定时器初始化的代码,特别是Timer0_Init函数。看起来用户可能需要类似的结构,但需要调整为2ms的定时。之前的例子是1ms,所以可能需要调整初值。 首先,51单片机定时器工作方式。通常使用方式1,也就是16位定时器模式。晶振频率如果是12MHz的话,机器周期是1微秒。定时器每计数一次需要1us,所以要达到2ms,也就是2000us,需要计数2000次。但是16位定时器的最大值是65536,所以初值应该是65536 - 2000 = 63536,转换成十六进制是0xF800。所以TH0=0xF8,TL0=0x00。不过用户提供的引用[4]中,1ms的初值是TH0=0xFC,TL0=0x18,这里计算的是65536 - 1000 = 64536,即0xFC18。所以同样的方法,2ms的话应该是65536 - 2000 = 63536,即0xF800。但可能需要确认晶振频率是否一致。 引用[4]中的代码使用的是12MHz晶振,所以机器周期是1us。因此,计算是正确的。所以,用户需要将初值设置为TH0=0xF8,TL0=0x00。或者可能要根据具体的分频设置,比如是否12T模式,这里默认是12T的话,每个机器周期是12个时钟周期,但如果是12MHz晶振,12T模式下,机器周期是1us。所以之前的计算是对的。 然后,配置定时器模式。TMOD的设置,方式1是0x01,所以TMOD |= 0x01。需要确保其他位不变,所以TMOD &= 0xF0,然后或上0x01。这样设置定时器0为方式1。 接下来是中断使能,ET0=1(定时器0中断允许),EA=1(总中断允许),PT0=0(优先级设置)。 然后在中断服务函数中,需要重新装载初值,因为方式1不会自动重载。所以每次中断发生后,要再次将TH0和TL0设置为0xF800。比如: void Timer0_ISR() interrupt 1 { TH0 = 0xF8; TL0 = 0x00; // 用户代码 } 这样就能实现每2ms进入一次中断。 需要检查代码是否正确,是否考虑了所有配置步骤。例如,是否开启了定时器启动TR0=1,是否正确设置了中断允许位。 现在,用户需要的是一个完整的示例代码,可能包括初始化和中断函数。根据引用[4]的结构,修改初值部分即可。 另外,用户可能需要注意定时器的溢出标志是否需要清除,在中断服务函数中,是否需要手动清除TF0。在引用[4]的代码中,TF0 = 0是在初始化时清除的,但中断发生后,硬件会自动清除TF0吗?在51单片机中,进入中断服务程序后,硬件不会自动清除TF0,需要软件清除。所以可能在中断函数中需要将TF0=0,或者在初始化时已经处理过。 不过,在引用[4]的代码中,初始化时已经将TF0=0,并且中断发生后,是否需要再次清除?可能需要确认。或者,是否在进入中断后,硬件会自动清除TF0标志?根据资料,51单片机在响应定时器中断后,硬件会自动清除中断标志位,即TF0会被自动清除。因此,在中断服务函数中不需要手动清除TF0。但不同型号的单片机可能有差异,这里假设是标准的51,所以可以不用写TF0=0。 综上,修改引用[4]中的代码,将初值改为TH0=0xF8,TL0=0x00,定时时间2ms,其他配置类似。给出完整的初始化函数和中断处理函数示例。 此外,用户可能需要知道如何验证定时是否准确,比如通过LED闪烁或者串口输出。这部分可以作为补充说明,但用户主要需要的是代码示例。 最后,生成相关问题,例如如何调整定时时间、多个定时任务的处理、定时器模式的选择等。</think>根据51单片机定时器配置方法,以下是实现2ms定时的完整程序示例(基于12MHz晶振): ### 定时器0初始化配置 ```c #include <REGX52.H> void Timer0_Init(void) { TMOD &= 0xF0; // 清除T0配置位 TMOD |= 0x01; // 设置定时器0为模式1(16位定时器) TH0 = 0xF8; // 设置定时初值高8位(2ms@12MHz) TL0 = 0x00; // 设置定时初值低8位 TF0 = 0; // 清除溢出标志 TR0 = 1; // 启动定时器0 ET0 = 1; // 允许定时器0中断 EA = 1; // 开启总中断 PT0 = 0; // 设置低优先级 } ``` ### 中断服务函数 ```c void Timer0_ISR(void) interrupt 1 { TH0 = 0xF8; // 重载初值 TL0 = 0x00; // 用户代码区(每2ms执行一次) // 示例:P1口LED闪烁 static unsigned int count = 0; if(++count >= 500) { // 实现1秒间隔 P1 = ~P1; // LED状态翻转 count = 0; } } ``` ### 关键配置说明 1. **初值计算**: 定时时间 $T = (2^{16} - X) \times 1\mu s = 2000\mu s$ 计算得 $X = 65536 - 2000 = 63536$ 对应十六进制 `0xF800`,即 `TH0=0xF8`, `TL0=0x00`[^4] 2. **中断机制**: 每次定时器溢出后自动触发中断,需在中断中手动重载初值(模式1特性)[^3] 3. **执行周期**: 中断服务程序中的用户代码会精确地每2ms执行一次 ### 验证方法 1. 连接LED到P1.0口 2. 代码中500次中断累积实现1秒间隔 3. 观察LED是否每秒闪烁一次 $$ \text{定时精度} = \frac{1}{12MHz} \times 12 \times 2000 = 2ms $$
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReCclay

如果觉得不错,不妨请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值