C语言 如何处理嵌入式 C 中的包装计数器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3095623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to deal with a wrapping counter in embedded C
提问by jramirez
I need to deal with a counter that gives me ticks for my application. The counter is 32bits so what i need to know is how to deal with it when it wraps. for example:
我需要处理一个计数器,它为我的应用程序提供刻度。计数器是 32 位的,所以我需要知道的是在包装时如何处理它。例如:
I have a function that returns a (timestamp + shifttime) and i have another function that will return 1 or 0 depending whether or not the time has elapsed, but there could a possibility that that my counter will wrap how do I deal with this ?.
我有一个返回 (timestamp + shifttime) 的函数,我有另一个函数将返回 1 或 0,具体取决于时间是否已经过去,但我的计数器可能会换行,我该如何处理? .
Thanks
谢谢
Thanks a lot for all the responses guys. I will give more detail in this edit.
非常感谢所有回答的家伙。我将在此编辑中提供更多详细信息。
I am using the STM32 Cortex-M3. I wanna use the RTC counter to use it as the tick for my application to schedule tasks that need to happen at certain intervals. The RTC can generate an overflow interrupt so it's not a problem to detect the interrupt. the main problem that I have(or at least I think is a problem) is when certain tasks gets a (timestamp+shift) ie.
我正在使用 STM32 Cortex-M3。我想使用 RTC 计数器将其用作我的应用程序的刻度,以安排需要在特定时间间隔发生的任务。RTC 可以产生溢出中断,因此检测中断不是问题。我遇到的主要问题(或至少我认为是一个问题)是某些任务何时获得(时间戳+移位)即。
int main( void )
{
FlashLedTimeStamp = ReturnCounter( 20 ); // currentcounter value + a shift of 20
StatusLedTimeStamp = ReturnCounter( 3 ); // currentcounter value + a shift of 3
//then later on ....
while(1)
{
/* other tasks could go here */
if( HasTimeElapsed( FlashLedTimeStamp );
{
/* do something and get another timestamp value */
FlashLedTimeStamp = ReturnCounter( 20 ); // currentcounter value + a shift of 20
}
if( HasTimeElapsed( StatusLedTimeStamp );
{
/* do something and get another timestamp value */
FlashLedTimeStamp = StatusLedTimeStamp( 3 ); // currentcounter value + a shift of 3
}
}
}
lets assume that my RTC counter is only 8 bits long to make the math easy.
让我们假设我的 RTC 计数器只有 8 位长,以便于计算。
if my current counter is at 250 when I get my timestamps that means that FlashLedTimeStamp = 14 and StatusLedTimeStamp = 253 how would i check to see that FlashLedTimeStamp has expired ??
如果我得到时间戳时当前计数器为 250,这意味着 FlashLedTimeStamp = 14 和 StatusLedTimeStamp = 253 我将如何检查 FlashLedTimeStamp 是否已过期?
keep in mind that I dont necessarily check all the time to see what the current counter is and whether or not certain timestamp has expired. I hope this makes it clear what the problem I have is thanks to all in advanced.
请记住,我不必一直检查以查看当前计数器是什么以及某个时间戳是否已过期。我希望这能让我清楚我遇到的问题是什么,感谢所有先进的人。
回答by Clifford
It will not matter so long as the difference between the start and end count is less than (2^32)/2, and assuming 2's complement 32bit arithmetic is performed (almost universally true), even if the count value spans the wrap-point. For example:
只要开始计数和结束计数之间的差值小于 (2^32)/2,并且假设执行 2 的补码 32 位算术(几乎普遍为真),即使计数值跨越包点也没关系. 例如:
Start count: 0xfffffff
End Count: 0x00000002 (incremented through 0,1,2 - i.e. three counts)
End - Start == 0x00000002 - 0xfffffff == 0x00000003
So the right answer is achieved so long as the counter is the bit width of a built-in integer type, and that type is used. Where perhaps a counter register is not the width of a built-in integer type, you can achieve the same effect by masking the higher order "overflow" bits.
因此,只要计数器是内置整数类型的位宽,并且使用该类型,就可以获得正确的答案。也许计数器寄存器不是内置整数类型的宽度,您可以通过屏蔽高阶“溢出”位来实现相同的效果。
If you need the larger count for other reasons or if the difference between successive timestamps is too large, then you can simply use another integer that is incremented when the lower-order counter wraps. This integer will form the high order bits of a larger integer, so the LSB of the second integer is the 33rd bit of this larger integer.
如果由于其他原因需要更大的计数,或者如果连续时间戳之间的差异太大,那么您可以简单地使用另一个在低阶计数器回绕时递增的整数。这个整数将形成一个更大整数的高位,所以第二个整数的 LSB 是这个更大整数的第 33 位。
回答by bta
If you take two timestamp readings and your first reading is greaterthan the second, then your counter has wrapped. That is the basic way to detect a wrapping counter.
如果您读取两个时间戳读数并且您的第一个读数大于第二个读数,则您的计数器已回绕。这是检测包装计数器的基本方法。
This, however, won't detect if a counter has wrapped multiple times, or the case where a counter has wrapped and happens to be greater than the first reading. Since you said this was an embedded system and your description makes your "counter" sound like a clock, see if you can set an interrupt to fire whenever the clock reaches zero (so that you will get an interrupt every time the clock resets). When this interrupt fires, increment a separate counter. This should effectively add extra precision to your clock and allow your counter to wrap without causing problems.
但是,这不会检测计数器是否已回绕多次,或者计数器已回绕并且恰好大于第一次读数的情况。既然您说这是一个嵌入式系统,并且您的描述使您的“计数器”听起来像一个时钟,那么看看您是否可以在时钟达到零时设置一个中断来触发(这样每次时钟重置时您都会得到一个中断)。当这个中断触发时,增加一个单独的计数器。这应该有效地为您的时钟增加额外的精度,并允许您的计数器回绕而不会引起问题。
回答by caf
If you use unsigned variables to store your counter and timer expiry time, then you can simply use this test:
如果您使用无符号变量来存储您的计数器和计时器到期时间,那么您可以简单地使用这个测试:
if (current_time - expiry_time < 0x80000000UL)
/* timer has expired */
This assumes that you test for expiry at least once every 0x80000000 ticks, and that your longest timer is set to expire less than 0x80000000 ticks into the future.
这假设您至少每 0x80000000 个滴答测试一次到期,并且您最长的计时器设置为在未来不到 0x80000000 个滴答时到期。
回答by Peter G.
The question is a bit vague. One possibility is to set a flag when you first notice that the time has elapsed. A surefire way would be add a second counter which is incremented when the first counter overflows. This will in effect create a 64 bit counter which won't overflow.
这个问题有点含糊。一种可能性是在您第一次注意到时间已经过去时设置一个标志。一种万无一失的方法是添加第二个计数器,当第一个计数器溢出时,该计数器会递增。这实际上会创建一个不会溢出的 64 位计数器。
回答by tomlogic
Cast the result of unsigned subtraction to signed and compare to zero. Should handle overflow when you check it often enough (and your timeout is less than half the range of your timer).
将无符号减法的结果转换为有符号并与零进行比较。当您经常检查它时应该处理溢出(并且您的超时小于计时器范围的一半)。
uint32_t timer( void); // Returns the current time value
uint32_t timeout;
timeout = timer() + offset;
// wait until timer() reaches or exceeds timeout value
while ((int32_t)(timeout - timer()) > 0);
回答by John R. Strohm
The simplest way to do this is to make an "epoch counter", that explicitly counts rollovers. (Example: you have a hardware counter that counts seconds 0..59. Your epoch counter would count minutes, by incrementing each time it noticed that the seconds counter had rolled over.)
最简单的方法是制作一个“纪元计数器”,明确计算翻转。(例如:您有一个硬件计数器,它计算 0..59 秒。您的纪元计数器将计算分钟数,每次它注意到秒计数器已翻转时递增。)
Your future_scheduler function then reads the current epoch and time,and computes a new epoch and time for your event.
您的 future_scheduler 函数然后读取当前的纪元和时间,并为您的事件计算新的纪元和时间。
Alternatively, you could just punt, and make your timing function count your event schedules down to zero on each timer tick.
或者,您可以直接下注,并让您的计时功能在每个计时器滴答时将您的事件时间表计数为零。
回答by pmod
One of the possibilities is to cast both variables to 64-bit long and then do sum. After that compare with maximum 32-bit value to identify if it's wrapped.
一种可能性是将两个变量都转换为 64 位长,然后求和。之后与最大 32 位值进行比较以确定它是否被包装。
回答by old_timer
lets assume the counter counts down (many count down to save on gates in the logic).
让我们假设计数器倒计时(许多倒计时以节省逻辑中的门)。
you need to first know the period of time it takes to get to 2^32 ticks and need to insure that you are well oversampling that.
您首先需要知道达到 2^32 个刻度所需的时间,并需要确保您对它进行了很好的过采样。
If you want to find the time period between two events, say start and end
如果要查找两个事件之间的时间段,请说开始和结束
start = read timer lasttime = start rollover = 0
开始 = 上次读取计时器 = 开始翻转 = 0
while waiting for thing to happen
在等待事情发生的同时
nowtime = read timer if(nowtime>lasttime) rollover+=1 (this is a down counter) lasttime = nowtime
nowtime = 读取计时器 if(nowtime>lasttime) rollover+=1(这是一个递减计数器) lasttime = nowtime
event happens: end = read timer
事件发生:结束 = 读取计时器
total time = start - end (this is a down counter and note that this math works even when rolling over)
总时间 = 开始 - 结束(这是一个递减计数器,请注意,即使翻滚,此数学运算也有效)
total time = total time/ scaling factor to get from ticks to seconds, minutes, whatever total time += rollover * seconds/minutes/whatever per 2^32 counts
总时间 = 总时间/比例因子从滴答到秒,分钟,无论总时间 += 翻转 * 秒/分钟/每 2^32 个计数
if you have an up counter then nowtime
如果你有一个柜台,那么现在
If you can guarantee that your event will happen within 2^32 counts you dont need to do the rollover now time last time thing you only need start and end and the total ticks = start - end will work even if the counter rolls from 0x00000000 to 0xFFFFFFFF between start and end.
如果您可以保证您的事件将在 2^32 个计数内发生,那么您不需要在上次时间进行翻转,您只需要开始和结束,并且即使计数器从 0x00000000 滚动到结束,总滴答数 = 开始 - 结束也会起作用开始和结束之间的 0xFFFFFFFF。
回答by IntelliChick
I think one of the easiest ways to do this, would be to have another counter (lets call it Wrap counter, let this be a static global for the timer module), count up each time your original 32 bits counter wrapped.
我认为最简单的方法之一是使用另一个计数器(让我们称其为 Wrap counter,让它成为计时器模块的静态全局变量),每次您的原始 32 位计数器包装时计数。
In the function where your counter is ticking away, everytime this counter reaches its maximum count, you have your Wrap counter increment. So when you are reading the function which returns whether or not the timer has elapsed, you also read the Wrap counter, to check how many times it wrapped over. The important thing is, to also do this: everytime you read the wrap counter, you want to clear it, for your next reading.
在您的计数器滴答作响的函数中,每次该计数器达到其最大计数时,您的 Wrap 计数器都会递增。因此,当您阅读返回计时器是否已结束的函数时,您还阅读了 Wrap 计数器,以检查它已结束的次数。重要的是,也要做到这一点:每次您阅读包装计数器时,您都想清除它,以备下次阅读。
回答by Jerry Coffin
Assuming you're dealing with unsigned types, you can check for wrapping pretty easily --
假设您正在处理无符号类型,您可以很容易地检查包装——
if (timestamp + shifftime < timestamp)
it_wrapped();

