打印

定时器校正

[复制链接]
2775|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xvezhe|  楼主 | 2013-11-13 22:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
tyw| | 2013-11-14 10:39 | 只看该作者
本帖最后由 tyw 于 2013-11-14 10:56 编辑

造成定时误差有多种原因:
1. 定时中断设定级别不高,被其他中断打断,可提升级别,或定时中断时关闭其他中断,返回时再恢复.
2. 定时中断里动作太多且不规则(忽长忽短),超出一个定时周期,可把中断内任务尽可能放到外面做.
3. 定时计数器设置不准.可重算解决.
4. 系统时钟所用晶振温漂级别,陶振是10-5,石英晶振是10-6,RC是是10-4,选用合适的器件.来满足定时温漂.
5. 根据实测误差,修正定时计数器预置值来补尝,但量产时不方便.

使用特权

评论回复
板凳
chunyang| | 2013-11-14 15:07 | 只看该作者
你想要多高精度?

使用特权

评论回复
地板
dirtwillfly| | 2013-11-14 20:46 | 只看该作者
T叔威武

使用特权

评论回复
5
qzlbwang| | 2013-11-14 21:18 | 只看该作者
如何消除定时器的积累误差?——响应中断是需要时间的,且这个时间随外部条件变化会有所变化,虽然变化不会太大,但多次的积累有可能会造成时间忽长忽短,会有比较明显的定时不准的感觉。解决的办法是,每次响应中断后读定时器,然后根据该次中断的响应时间修正中断时间常数。这样定时器的误差就不再积累。其他方面老T已经说得比较全面了。

使用特权

评论回复
6
huangxz| | 2013-11-14 21:38 | 只看该作者
要做到很准是不可能的,够用就行了。

使用特权

评论回复
7
xvezhe|  楼主 | 2013-11-14 22:40 | 只看该作者
本帖最后由 xvezhe 于 2013-11-14 22:44 编辑
chunyang 发表于 2013-11-14 15:07
你想要多高精度?

100秒倒计时,误差不超0.1秒,还有误差能在一个阶段校正,不让误差累计。。。可以达到吗?谢谢,

使用特权

评论回复
8
xvezhe|  楼主 | 2013-11-14 22:42 | 只看该作者
本帖最后由 xvezhe 于 2013-11-14 22:47 编辑
tyw 发表于 2013-11-14 10:39
造成定时误差有多种原因:
1. 定时中断设定级别不高,被其他中断打断,可提升级别,或定时中断时关闭其他中断, ...

程序就一个定时器中断。。。。在中断中处理数据很少,只要是用于定时1s,0.75s标志位。。。。
现在若40s,倒数到最后相差0.3s左右,之后还误差累加。。。。    如何降低误差,请指教

想请教如何重算呢?谢谢

使用特权

评论回复
9
xvezhe|  楼主 | 2013-11-14 22:49 | 只看该作者
huangxz 发表于 2013-11-14 21:38
要做到很准是不可能的,够用就行了。

恩恩,若能在一定阶段校正误差的话。。。。就可以了。。。谢谢

使用特权

评论回复
10
xvezhe|  楼主 | 2013-11-14 22:50 | 只看该作者
qzlbwang 发表于 2013-11-14 21:18
如何消除定时器的积累误差?——响应中断是需要时间的,且这个时间随外部条件变化会有所变化,虽然变化不会 ...

呵呵,有例子参考一下,谢谢指教。。。

使用特权

评论回复
11
chunyang| | 2013-11-14 22:59 | 只看该作者
xvezhe 发表于 2013-11-14 22:40
100秒倒计时,误差不超0.1秒,还有误差能在一个阶段校正,不让误差累计。。。可以达到吗?谢谢, ...

这当然可以轻松实现,注意控制好软件的时序,结构是否最优无所谓,但每个循环的时间要尽量相同,同时针对晶体的频偏和温漂做一个补偿就可以了。

使用特权

评论回复
12
nyf1972| | 2013-11-15 00:11 | 只看该作者
本帖最后由 nyf1972 于 2013-11-15 00:22 编辑

这个是个老问题了,N年前我就在这个坛子中写过,现在再说一下:
1.你要求的精度是完全可以保证的,每个月的误差可以控制在20秒以内,这个主要是由于晶振的误差造成的。
2.单片机处理的误差几乎可以忽略不计,但是要按如下的方法来进行处理:
  设计一个定时器,使用8位定时器,不要进行赋值,直接让其自由运行,溢出的时候产生会中断(255变到0 或65535变到0),中断中把溢出次数加一处理。这个中断的级别要求要高一些!切记切记!
  说明:为何要只有运行,不赋值?因为在赋值的时候有几个机器周期的误差,而且不可控,而自由运行的时候,是没有这个误差的
  再设计一个任务,每次中断间隔为10ms,这个间隔多少可以调整,这个任务主要作用是查询前面一个定时器的溢出次数,根据溢出次数进行计算,然后得到你想要的数据。
3.对于一般任务而言,不用温度补偿,其实普通的晶体已经可以达到你的要求,除非你做更高精度的设计,如果是这样,将严重受控于晶体的温度系数。
4.鄙视一下那些用DELAY的方法和外加补偿的方法来实现延迟或定时的程序方法。明显的又费马达又费油的做法。
5.不要老想到用程序补偿的方法来做,那是治标不治本的做法。
   
   

使用特权

评论回复
13
linfeng24| | 2013-11-15 00:43 | 只看该作者
好吧, T叔和楼上个哥们都说得好详细了,我再次肯定晶振的误差是最主要的。

使用特权

评论回复
14
xvezhe|  楼主 | 2013-11-15 08:36 | 只看该作者
nyf1972 发表于 2013-11-15 00:11
这个是个老问题了,N年前我就在这个坛子中写过,现在再说一下:
1.你要求的精度是完全可以保证的,每个月的 ...

谢谢指点。。。。新手学习了。。。。。不过程序代码不知如何写,有代码参考吗?(C语言)

使用特权

评论回复
15
qzlbwang| | 2013-11-15 08:44 | 只看该作者
      100秒允许误差0.1秒,也就是允许误差0.1%!楼主的误差都超过0.1%了,还会是“晶振的误差是主要的”?您又是如何肯定的呢?依据又在哪里?
    回答楼主:这个以前做过(是用汇编做的),肯定可以达到你的要求,但例程已经找不到了(因为笔记本被偷了),说一下思路吧,不复杂:响应中断后(响应中断的时间不固定,因为和中断发生的时机有关),关中断,做好现场保护,然后读定时器,再加上后面几条指令所需的时间(这是固定的,因为已经关中断,不会有其他中断来干扰这几条指令的执行时间),再加上定时时间常数,然后将其送入定时器,这时候实际定时时间常数将定时中断发生时到现在的这段时间扣除,其中包含了不确定的中断响应时间。那么即便重复使用再多次的该定时中断,也只有一次误差,而不会积累。也就是说误差至多是若干个机器周期,当然这是建立于晶振准确的基础之上的,但晶振的误差是很小的,对于你要求的精度来说足足有余,使用不用考虑。除非你用的伪劣的。

使用特权

评论回复
16
qzlbwang| | 2013-11-15 08:52 | 只看该作者
12楼的方法也正确。只是不重新赋值的话,有时候需要延时的时间会出现要N次中断再加若干个机器周期的情况,这另外加若干个机器周期的情况处理起来感觉繁琐。当然也可以采用自动更新时间常数的模式,但在51里就只能用8位定时器了,需要比较长的延时的话中断的次数会很多。感觉定时器的使用不够灵活。

使用特权

评论回复
17
xvezhe|  楼主 | 2013-11-15 09:31 | 只看该作者
qzlbwang 发表于 2013-11-15 08:52
12楼的方法也正确。只是不重新赋值的话,有时候需要延时的时间会出现要N次中断再加若干个机器周期的情况, ...

谢谢。。。:loveliness:

使用特权

评论回复
18
受不了了| | 2013-11-15 12:27 | 只看该作者
二姨每过一阵子都会出现这个讨论单片机定时器精度的帖子,论坛里有一篇灯苗大侠的汇编的帖子,那个精度是最高的,无出其右

使用特权

评论回复
19
nyf1972| | 2013-11-17 22:28 | 只看该作者
本帖最后由 nyf1972 于 2013-11-18 00:16 编辑

假设你使用的是12M的晶振(而且使用12分频的)
    T0 设计为8位,等效于每0.256mS中断一次
    T0中断程序内容:(最高优先级别)
       {
         CntT0Base256us++;  //长整型(可涵盖你的100S)
        }
    外部再用另外一个定时器设计一个中断,每10ms中断一次:(这个时间尽量大点,可以尽量控制终端程序的处理量小一点,决定时间精度不在这个地方,这个仅仅用于输出用)
        {
        TotalTime_ms=CntT0Base256us*256/1000;
        DispTime_s=TotalTime_ms/1000;
        DispTime_ms =TotalTime_ms%1000;
        }
     这个程序最关键的地方就是:
     1.中断发生后,不对T0进行赋值,内部硬件会自动由255变成0的。(如果要去赋值,又有几个周期去了,只是你没有意识到这个问题而已,如果这个地方做补偿,如果运气好可能行,但是绝大多数情况是不能完全补偿到1个周期都不差的,用C写代码你知道到底保护了那些寄存器?汇编中占用了几个机器周期?有得你计算了!!!!这就是造成定时不准确的原因),我们认为晶体是可靠的,并且精度能够满足,而定时器的运行完全靠硬件运行。不需要软件赋值,只是定时器发生中断的时候,我们去处理一件很小很小的事情,而且不动定时器的值,这样就能够消除累计误差,这样做下去理论是是没有累计误差的。
     2.有一点很多人想不通,为了程序方便,就把定时器设计成好处理的0.1ms或1ms,而如果你找不到合适的晶振使定时器刚好自由运行溢出的时间为0.1ms或1ms,那就必须通过软件去修改定时器的值,这样就造成误差。其实反过来想,我为何一定要设计成0.1ms,为何不可以设计成0.256ms??
     3.时间基数CntT0Base256us一定要准确。但是程序在处理输出和显示等程序由于误差的问题,是可以允许有一定误差的(TotalTime_ms以及DispTime_s和DispTime_ms这些数据中肯定有舍去数据的)。但是显示的一些数据误差并没有影响基数的误差(前面程序可以看出,并没有修改CntT0Base256us)。下一次显示任然是从基数中得到,这样做就一定没有累计误差的。
     4.个人觉得如果这样处理后还达不到要求才考虑更换晶体!千万不要本末倒置
   

使用特权

评论回复
20
nyf1972| | 2013-11-17 23:19 | 只看该作者
再补充一下:
    如果你觉得实用性不够广泛
    可以把基数设计成整数,
     if(CntT0Base256us++==1000)
            {
            if(CntT0Base256ms++==1000)
                {
                if(CntT0Base256s++==1000)
                     {
                     Cnt256s++;
                     }
                }
            }
     这样来处理不晓得还能不能满足你的应用???

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

54

主题

225

帖子

2

粉丝