如何处理嵌入式C中的包装计数器

jra*_*rez 12 c embedded integer-overflow

我需要处理一个计数器,它为我的应用程序提供了滴答声.计数器是32位,所以我需要知道的是如何在它包装时处理它.例如:

我有一个函数返回一个(timestamp + shifttime),我有另一个函数将返回1或0取决于时间是否已经过去,但我的计数器可能会包装如何处理这个? .

谢谢

非常感谢所有回复的人.我将在此编辑中提供更多详细信息.

我使用的是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
    }
}   
}
Run Code Online (Sandbox Code Playgroud)

我们假设我的RTC计数器只有8位长,以便简化数学运算.

如果我的当前计数器是250,当我得到我的时间戳,这意味着FlashLedTimeStamp = 14和StatusLedTimeStamp = 253我将如何检查FlashLedTimeStamp是否已经过期?

请记住,我没有必要一直检查当前计数器是什么以及某个时间戳是否已过期.我希望这能说清楚我所面临的问题是多少先进的.

Cli*_*ord 21

只要开始和结束计数之间的差异小于(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
Run Code Online (Sandbox Code Playgroud)

因此,只要计数器是内置整数类型的位宽,并且使用该类型,就可以实现正确的答案.如果计数器寄存器可能不是内置整数类型的宽度,则可以通过屏蔽高阶"溢出"位来实现相同的效果.

如果由于其他原因需要更大的计数,或者如果连续时间戳之间的差异太大,那么您可以简单地使用另一个在低阶计数器换行时递增的整数.该整数将形成较大整数的高位,因此第二个整数的LSB是该较大整数的第33位.

  • 这是正确的答案。始终进行减法并与零进行比较,而不是原始比较。减法“解决”了包装问题。 (4认同)

bta*_*bta 13

如果您读取两个时间戳读数并且您的第一次读数大于第二次读数,那么您的计数器已经包装好了.这是检测包装计数器的基本方法.

然而,这不会检测计数器是否已经多次包裹,或者计数器已经包裹并且恰好大于第一次读数的情况.既然你说这是一个嵌入式系统,你的描述使你的"计数器"听起来像一个时钟,看看你是否可以设置一个中断,以便在时钟到零时触发(这样你每次时钟复位时都会得到一个中断).当此中断触发时,增加一个单独的计数器.这应该有效地为您的时钟增加额外的精度,并允许您的计数器包装而不会导致问题.

  • 也许编辑说:“如果你读取两个时间戳读数*递增计数器/计时器*...”——我工作的最后3个(嵌入式)项目使用了*倒计时*计时器,所以环绕是当第二个值时大于第一个。例如,ARM Cortex M3 的内置 SYSTICK 定时器递减计数到 0,然后重新加载特定值,然后再次递减计数。不过,很好的答案。 (2认同)
  • @Dan-好点。也许这样说会更清楚:“如果您计算两个时间戳之间的(有符号)差异,并且结果具有与您期望的相反的符号,则计数器被包装”。 (2认同)

tom*_*gic 5

将无符号减法的结果转换为有符号并与零进行比较。当您经常检查它时应该处理溢出(并且您的超时小于计时器范围的一半)。

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);
Run Code Online (Sandbox Code Playgroud)


caf*_*caf 5

如果您使用无符号变量来存储您的计数器和计时器到期时间,那么您可以简单地使用这个测试:

if (current_time - expiry_time < 0x80000000UL)
    /* timer has expired */
Run Code Online (Sandbox Code Playgroud)

这假设您至少每 0x80000000 个滴答测试一次到期,并且您最长的计时器设置为在未来不到 0x80000000 个滴答时到期。