一、现存问题
对于资源受限的嵌入式平台,由于多线程抢占内核,在某个线程中使用系统定时器可能达不到理想的定时效果。
例如我使用的MIPS7628, *** 作系统为Linux,最小的睡眠时间单位为4ms,想要定时10ms去内存数据并做相应的处理。
但是定时10ms不准确,每次定时都存在误差,时间长了以后,误差累计越来越大。
处理数据的数量越多,遍历的时间也越长,误差也会越来越大。
对于时间要求很严格的情况下,这是无法接受的。
那么如何消除这个累计误差呢?
二、消除累计时间误差方案
考虑使用相对时间来消除累计误差,即使有一个时间点存在误差,使用该方法也可在后续的定时中恢复正常。
代码逻辑如下:
1、 对每个数据点记录一个起始时间(记为startTv,系统时间,至少精确到1ms,有的可以精确到us)和定时时间(记为tick,例如10ms);
2、睡眠一段时间(睡眠主要是为了释放CPU,避免该线程独占,例如:4ms)遍历数据,获取当前的系统时间(记为curTv);
3、计算系统当前时间和起始时间的差(记为gap),若(gap >= tick)则判定为时间到,执行数据处理流程,并执行步骤4,否则执行步骤5,;
4、更新startTv,这是最为关键的一步,将startTv与tick的的和作为下一轮检查的startTv(这可消除累计误差),然后更新tick;
5、判断下一个数据,直到数据遍历完成,返回步骤2。
注意:在数据处理流程中不应作延时或耗时多的 *** 作,否则将影响定时效果。
三、示例代码
#include
#include
#include
#include
#include
typedef struct _time_tick{
struct timeval startTv;
int tick; //10ms
int data; //
}TimeTick_T;
//时间差,ms
int TimeGap(struct timeval newTv, struct timeval oldTv)
{
int gap = 0;
gap = 1000 * ((int)newTv.tv_sec - (int)oldTv.tv_sec) + (int)(newTv.tv_usec / 1000) - (int)(oldTv.tv_usec / 1000);
return gap;
}
void ChecktimeAndHandle(TimeTick_T *pt)
{
int gap = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
gap = TimeGap(tv, pt->startTv);
if(gap < 0){ //无效时间
return ;
}
gap = gap / 10;
if(gap < pt->tick){
//超时时间未到
return ;
}
//超时时间到,更新时间,非常重要
unsigned int us = pt->startTv.tv_usec + pt->tick * 10 * 1000; //微秒
pt->startTv.tv_sec = pt->startTv.tv_sec + us / 1000000;//计算秒
pt->startTv.tv_usec = us % 1000000;
//处理数据,不可做延时或耗时多的 *** 作
pt->data ++;
printf("current starttv : %d.%d ,gap = %d\n",pt->startTv.tv_sec ,pt->startTv.tv_usec/1000,gap);
}
int main()
{
TimeTick_T t = {0};
t.tick = 100;
gettimeofday(&t.startTv, NULL);
while (1)
{
usleep(4000);
ChecktimeAndHandle(&t);
/* code */
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)