3

我有一个计时器,我定期使用它来收集性能值。现在,我已经看到,有时我得到的值低于之前采样的值。

我发现将这种行为追溯到我这样做的事实:
1)读取低字节
2)读取高字节

值 = 上 <<8 + 下

 

但有时会发生:
1)读取低字节
2)发生低字节溢出,lower = 0,higher++
3)读取高字节(现在太高了!)

value = (upper<<8) + lower + [a value less than 255]

如果我切换顺序:
1)读取高字节
2)发生低字节溢出,lower = 0,higher++
3)读取低字节(现在太低了!)

value = (upper<<8) + lower - [一个小于 255 的值]

所以,在这两种情况下,我都偏离了我的真实价值。


有没有比下面介绍的更好的解决方案?
或者甚至有既定的解决方案?


我现在做的是这样的:

/* Sample as long as it takes to not hit an overflow 
   between sampling the lower and the upper byte */

do {
    upper = CounterH;
    lower = CounterL;
} while (upper != CounterH);

但我很害怕,因为这可能会导致僵局!(如果计时器计数足够快)


我也在考虑这个:

__DI();

upper =  CounterH;
lower =  CounterL;
value1 = upper<<8 + lower;

upper =  CounterH;
lower =  CounterL;
value2 = upper<<8 + lower;

value = max(value1, value2);

__EI();

(首先读取低字节将需要 min() 函数。)
这需要边缘条件,即计时器的周转时间大于上面代码的执行时间!

4

2 回答 2

3

首先,我会检查在读取高字节或低字节时计数器值是否锁存。许多计时器都这样做。

您的第二种方法(两次读取计数器)很有希望,但如果可能,请删除第一次和第二次读取计时器之间的任何计算,然后再进行所有计算。您还需要检查高字节环绕(从 255 到 0)是否也可能是一个问题。

如果在您的问题中说明您使用的是什么 8 位控制器和计时器,这将很有帮助,因为人们可以通过查看数据表和手册来提供更具体的建议

于 2013-07-09T07:31:09.147 回答
2

你可以展开你的第一种方法进行两次迭代,所以你得到

__DI();
upper1 = CounterH;
lower1 = CounterL;
upper2 = CounterH;
lower2 = CounterL;
__EI();
if ( upper1 == upper2 )
{
    // use lower1, upper1
}
else
{
    // use lower2, upper2
}

在这里,您假设如果CounterL在读取之间溢出,并且在读取upper1和.upper2upper2lower2

由于在分配块周围禁用了中断,因此它应该始终足够快,即使对于 8 位计数器也是如此。

于 2013-07-13T11:50:43.363 回答