打印

征集最好的计时方法,看谁的方法最好。

[复制链接]
2675|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
流行音乐|  楼主 | 2011-7-3 16:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
征集最好的计时方法,看谁的方法最好。

单片机程序中现有一个 1.234567ms 的时钟中断。
现要求不准用定时器功能,只利用此 1.234567ms 时钟中断,实现长时间的秒计时功能,例如从 0 秒到 1000000000 秒的计时。
假设条件:假设单片机的晶振频率是理想恒定的,即这个 1.234567ms 中断是严格精确的 1.234567ms 中断。
评比最好方法的依据:
1:谁的累积误差最小 (这个依据占的比重很大)
2:瞬时误差超出 5ms 将直接被淘汰。
3:谁的方法最简单方便 (这个依据占的比重很小,当其它依据相同的时候,用此依据区分优劣)

相关帖子

沙发
ahgao| | 2011-7-4 01:28 | 只看该作者
这能有什么好办法,把每秒误差算出来,等它积累到了最小分度时补偿上去。补偿后还是有误差,再积累再补偿一次就好了。以楼主的例子:
最小分度是1.234567ms,记数到810时时间是999.99927ms,与一秒的误差是-0.00073ms,那么,当秒数走到1691时,累计误差为-1.23443ms,所以此时要补偿一个1.234567ms。也就是说,在1691秒内,误差为0.000137ms。等秒钟走到9011*1691 = 15237601秒时,再补偿一个1.234567ms就好了,这样在15237601秒内,误差不超过一个最小分度。以此类推,看你要多少。

使用特权

评论回复
板凳
ahgao| | 2011-7-4 01:35 | 只看该作者
我也是无聊,大晚上的算这个。想说的原理就是积累到最小分度时做补偿。楼主的问题只是一个例子,这个原理也经常用于除法运算,比如你要对某个连续输入的数据序列除3,有66.7%的情况下不能整除,那么你要把余数保留,积累到3时补偿到结果里面去,这样才不会累计误差。

使用特权

评论回复
地板
aihe| | 2011-7-4 07:22 | 只看该作者
自己不会,请教就请教,征集啥啊
成功的路有千万条,看你自己怎么选了

使用特权

评论回复
5
呆板书生| | 2011-7-4 07:30 | 只看该作者
最简单的方法就是润秒,

解决请参考数论方面的书籍

使用特权

评论回复
6
ayb_ice| | 2011-7-4 08:19 | 只看该作者
计算累积误差,在适应的时候修正即可

使用特权

评论回复
7
SeaSun| | 2011-7-4 09:59 | 只看该作者
本帖最后由 SeaSun 于 2011-7-4 10:32 编辑

UINT32        Counter=0;
UINT32        Sec;


INT_RTC()
{
        Counter+=1234567;
        if(Counter>=1000000000)
        {
                Sec++;
                Counter-=1000000000;
        }

}

//===========================
//改进版;;   有错误,不要往下看了,,糊涂了...
INT_RTC()
{
        Counter+=1234567;
        if(Counter>=1000000000)
        {
                Sec++;
                Counter-=1000000000;
        }

        
        if(Counter>=999500000)  //四舍五入  (错!)
        {
                Sec++;
                Counter-=999500000;
        }

}

使用特权

评论回复
8
SeaSun| | 2011-7-4 10:15 | 只看该作者
2:瞬时误差超出 5ms 将直接被淘汰。????

糊涂了,什么叫瞬时误差. 能举个例子吗?

使用特权

评论回复
9
xwj| | 2011-7-4 10:27 | 只看该作者
最简单准确的方法就是:
1、设置浮点或定点小数变量x,起始值为  1.234567ms/2
2、每次中断x+ 1.234567ms,判断是否大于1000,大于则加1秒并让x-1000。

如此一路累积下去即可,不会有累积误差。只是计算时间多一点罢了。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
ahgao + 1
10
ahgao| | 2011-7-4 10:48 | 只看该作者
最简单准确的方法就是:
1、设置浮点或定点小数变量x,起始值为  1.234567ms/2
2、每次中断x+ 1.234567ms,判断是否大于1000,大于则加1秒并让x-1000。

如此一路累积下去即可,不会有累积误差。只是计算时间多一点 ...
xwj 发表于 2011-7-4 10:27

这个好,我在某个Windows程序里面也正准备这么干。老X这么一说,到省的我仔细想细节了。

使用特权

评论回复
11
t.jm| | 2011-7-4 11:06 | 只看该作者
本帖最后由 t.jm 于 2011-7-4 11:08 编辑

写个求商并且4舍5入的函数,延时之前不就是对一个变量赋值嘛,比如延时时间t1=100000mS,如果延时时间是固定的,这个函数的功能还可以由编译器完成。
把t1=t1/1.234567(t1=t1*1000000/1234567),由时间单位转为CLICK单位,在中断里就是简单的减1操作,减到0就是时间到。
if(0==--t1){....}
这样的好处是:
1)有多个延时需求时代码量反而会小。
2)在中断中的代码是最小的,速度是最快的,因为已经把时间单位转为中断CLICK单位了。

使用特权

评论回复
12
mohanwei| | 2011-7-4 11:17 | 只看该作者
浮点数的舍入误差是一个问题……最好转换成定点数来算,这里可以把时基放大100万,得到1234567。一个unsigned long最多可以记(2^32-1)/1234567=3478个(也就是3478*1.234567=4.29秒,足够用了),算法和XWJ提出的一样。
代码:
unsinged long mSecond=0;//秒计数器
void xxx_int(void)//定时器中断
{
        #define _1000ms (1000000L*1000L) //1000ms
        static unsigned long ulCnt=0;
        ulCnt += 1234567;
        if(ulCnt >= _1000ms)//大于1000ms
        {
                ulCnt -= _1000ms;
                mSecond ++;
        }
}

使用特权

评论回复
13
lxyppc| | 2011-7-4 11:22 | 只看该作者
2:瞬时误差超出 5ms 将直接被淘汰。????

糊涂了,什么叫瞬时误差. 能举个例子吗?
SeaSun 发表于 2011-7-4 10:15

假设有一块表走得很准,但是你说话很慢,说一句话最少要10秒
有人问你几点了,你说11点8分37秒。
由于你说话用了10秒钟,问你的人实际上得到的是10秒钟之前的时间。这就叫瞬时误差.

由于你的表很准,所以不会有累计误差。

使用特权

评论回复
14
liang7143| | 2011-7-4 16:40 | 只看该作者
最简单准确的方法就是:
1、设置浮点或定点小数变量x,起始值为  1.234567ms/2
2、每次中断x+ 1.234567ms,判断是否大于1000,大于则加1秒并让x-1000。

如此一路累积下去即可,不会有累积误差。只是计算时间多一点 ...
xwj 发表于 2011-7-4 10:27


X哥 威武

使用特权

评论回复
15
流行音乐|  楼主 | 2011-7-4 23:01 | 只看该作者
感谢大家的回复,老x的方法的累积误差为0,是最好的方法。

使用特权

评论回复
16
hall| | 2011-7-7 16:35 | 只看该作者
最简单准确的方法就是:
1、设置浮点或定点小数变量x,起始值为  1.234567ms/2
2、每次中断x+ 1.234567ms,判断是否大于1000,大于则加1秒并让x-1000。

如此一路累积下去即可,不会有累积误差。只是计算时间多一点 ...
xwj 发表于 2011-7-4 10:27


:dizzy:
太笨,一时没想明白这是什么原理。。。哪位前辈帮忙讲讲吧

使用特权

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

本版积分规则

10

主题

375

帖子

1

粉丝