发新帖本帖赏金 3.00元(功能说明)我要提问
12
返回列表
[51单片机]

【已推翻结论】只使用单片机定时器是无法100%精确时间的

[复制链接]
楼主: cov0xt
手机看帖
扫描二维码
随时随地手机跟帖
nuaabob| | 2016-1-17 17:28 | 显示全部楼层
中断+自动重装初值,从理论上来讲可以做到0误差,当然由于我们使用的晶振是不可能百分百精确无误,因此误差是客观存在的。

使用特权

评论回复
changmiao| | 2016-1-20 08:37 | 显示全部楼层
自我纠正得挺及时,其实一个做技术的,还是不要轻易地下这些结论为好。时钟芯片和定时器精度的区别本质上应该是晶振精度的区别。

使用特权

评论回复
597898332| | 2016-1-20 17:05 | 显示全部楼层
cov0xt 发表于 2016-1-8 11:12
晶振是11.0592MHz

机器周期= 11.0592/12 = 0.9216

无意翻到,真赞:lol

使用特权

评论回复
yzai| | 2016-1-21 11:24 | 显示全部楼层
好贴

使用特权

评论回复
受不了了| | 2016-1-21 17:27 | 显示全部楼层
nuaabob 发表于 2016-1-17 17:28
中断+自动重装初值,从理论上来讲可以做到0误差,当然由于我们使用的晶振是不可能百分百精确无误,因此误差 ...

哪怕排除晶振的误差,你这方法理论上仍然有误差,不信发个1KHZ的脉冲,示波器搭上去看看频率能稳定到小数点后几位:lol

使用特权

评论回复
huangqi412| | 2016-1-22 12:49 | 显示全部楼层
。。。。。。。。。。

使用特权

评论回复
coody| | 2016-1-24 22:02 | 显示全部楼层
受不了了 发表于 2016-1-21 17:27
哪怕排除晶振的误差,你这方法理论上仍然有误差,不信发个1KHZ的脉冲,示波器搭上去看看频率能稳定到小数 ...

如果用自动重装、溢出可以自动硬件输出取反IO的(比如STC的1T系列,或者像AT89C52这样标准的51系列有Timer2的),则,输出1KHZ脉冲基本跟晶振的精度一样,抖动近似。比如用一个0.1ppm的有源时钟,则输出1KHZ也是0.1ppm。

使用特权

评论回复
通宵敲代码| | 2016-1-26 17:08 | 显示全部楼层
当年用最垃圾的89C52做的万年历,误差每年10分钟左右

使用特权

评论回复
lcdi| | 2016-1-28 21:56 | 显示全部楼层
晶振本身也有误差和漂移,所以适时做补偿就可以了。

使用特权

评论回复
jazzyfox| | 2016-1-31 14:45 | 显示全部楼层
我觉得楼主应该把系统移植到ARM芯片上,用系统嘀嗒计时器来做产考

使用特权

评论回复
林永健| | 2016-3-13 19:04 | 显示全部楼层
楼主你好,我觉得你如何想在单片机内部实现精准计时,可以用STM32类的内部自带的RTC,实时时钟,就可以做到万年历 。

使用特权

评论回复
无超~吞立吉| | 2016-3-31 22:52 | 显示全部楼层
datouyuan 发表于 2016-1-8 09:25
介绍一种很特别的自动重载的方法.

1:51mcu的晶振选择11.0592M.这样50毫秒定时间隔的TL0的值为0.

哥,小弟是菜鸟,理解能力有限,能不能贴出代码看一下!

使用特权

评论回复
datouyuan| | 2016-4-1 10:53 | 显示全部楼层
//11.0592MHz 10mS重载值(65536-9216)
#define T_RELOAD_ (65536-9216)
#define T_RELOAD_LO        (T_RELOAD_ & 0x00FF)//等于0
#define T_RELOAD_HI        (T_RELOAD_ >> 8)

//T_RELOAD_LO为0,代码如下.
void T0_int(void) interrupt 1
{
        TH0 = T_RELOAD_HI;
        //代码
}



//12MHz 10mS重载值(65536-10000)
#define T_RELOAD_ (65536-10000)
#define T_RELOAD_LO        (T_RELOAD_ & 0x00FF)//等于240
#define T_RELOAD_HI        (T_RELOAD_ >> 8)
//T_RELOAD_LO不为0,代码如下.
void T0_int(void) interrupt 1
{
        unsigned int i;
        TR0 = 0;
        i=T_RELOAD_+15+(TL0|(TH0<<8));
        //修正值15是T0由关闭到开启的机器周期数.要看汇编代码调整.
        TL0=(unsigned char)i;
        TH0=(unsigned char)(i>>8);
        TR0 = 1;
        //代码
}
上述2段代码都能实现精确定时,无累积误差.可以看出,使用11.0592M晶振代码更简单,效率更高.

使用特权

评论回复
datouyuan| | 2016-4-1 11:02 | 显示全部楼层
无超~吞立吉 发表于 2016-3-31 22:52
哥,小弟是菜鸟,理解能力有限,能不能贴出代码看一下!

上面代码改成50mS.
//12MHz 50mS重载值(65536-50000)
#define T_RELOAD_ (65536-50000)
#define T_RELOAD_LO        (T_RELOAD_ & 0x00FF)//等于176
#define T_RELOAD_HI        (T_RELOAD_ >> 8)
//T_RELOAD_LO不为0,代码如下.
void T0_int(void) interrupt 1
{
        unsigned int i;
        TR0 = 0;
        i=T_RELOAD_+15+(TL0|(TH0<<8));
        //修正值15是T0由关闭到开启的机器周期数.要看汇编代码调整.
        TL0=(unsigned char)i;
        TH0=(unsigned char)(i>>8);
        TR0 = 1;
        //代码
}

使用特权

评论回复
datouyuan| | 2016-4-1 11:04 | 显示全部楼层
//11.0592MHz 50mS重载值(65536-46080)
#define T_RELOAD_ (65536-46080)
#define T_RELOAD_LO        (T_RELOAD_ & 0x00FF)//等于0
#define T_RELOAD_HI        (T_RELOAD_ >> 8)

//T_RELOAD_LO为0,代码如下.
void T0_int(void) interrupt 1
{
        TH0 = T_RELOAD_HI;
        //代码
}

使用特权

评论回复
无超~吞立吉| | 2016-4-1 14:58 | 显示全部楼层
datouyuan 发表于 2016-4-1 11:02
上面代码改成50mS.

哥,太给力了。TL0直接赋值为零,不进行右移八位是不是也可以?

使用特权

评论回复
datouyuan| | 2016-4-2 09:26 | 显示全部楼层
本帖最后由 datouyuan 于 2016-4-2 09:28 编辑

不行.
定时器溢出,TL0后还会继续增加,假如TL0直接赋值为零,就会产生误差.
只能给TH0赋值.

T0中断发生后,要尽快响应.假如响应时间可以超过256个机器周期,也会产生误差.
下面的代码可以让响应时间超过256个机器周期.
//T_RELOAD_LO为0,代码如下.
void T0_int(void) interrupt 1
{
        TH0 = T_RELOAD_HI+TH0;
        //代码
}


使用特权

评论回复
15698208161| | 2016-4-2 10:52 | 显示全部楼层
对于中断这一块,看了网上很多教程都不明白,上了单片机的课一下就清楚了。网上的资料太没条理了,没法和书上比。兴趣很重要,但老师也很重要。看来考一个好的大学,比泡论坛要有用多了。

使用特权

评论回复
发新帖 本帖赏金 3.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则