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

如何在嵌入式C中处理包装计数器,c,embedded,integer-overflow,C,Embedded,Integer Overflow,我需要处理一个计数器,它为我的申请提供刻度。计数器是32位的,所以我需要知道的是当它包装时如何处理它。例如: Start count: 0xfffffff End Count: 0x00000002 (incremented through 0,1,2 - i.e. three counts) End - Start == 0x00000002 - 0xfffffff == 0x00000003 我有一个函数返回一个(timestamp+shifttime),还有一个函数返回1或0,这取

我需要处理一个计数器,它为我的申请提供刻度。计数器是32位的,所以我需要知道的是当它包装时如何处理它。例如:

Start count: 0xfffffff
End Count:   0x00000002 (incremented through 0,1,2 - i.e. three counts)

End - Start == 0x00000002 - 0xfffffff == 0x00000003
我有一个函数返回一个(timestamp+shifttime),还有一个函数返回1或0,这取决于时间是否已过,但我的计数器可能会包装我如何处理它

谢谢

非常感谢各位的回复。我将在这次编辑中提供更多细节

我使用的是STM32 Cortex-M3。我想使用RTC计数器将其用作我的应用程序计划需要在特定时间间隔执行的任务的勾号。RTC可以生成溢出中断,因此检测中断不是问题。我遇到的主要问题(或者至少我认为是个问题)是当某些任务得到(时间戳+移位)ie时

让我们假设我的RTC计数器只有8位长,以简化计算

如果在获取时间戳时,我的当前计数器为250,这意味着FlashLedTimeStamp=14和StatusLedTimeStamp=253,我如何检查FlashLedTimeStamp是否已过期


请记住,我不一定总是检查当前计数器是什么,以及某个时间戳是否已过期。我希望这能清楚地说明我的问题是什么,这要感谢所有的先进技术

假设您处理的是无符号类型,您可以非常轻松地检查包装--

if(时间戳+移位时间
这个问题有点模糊。一种可能是在您第一次注意到时间已过时设置一个标志。一个可靠的方法是添加第二个计数器,当第一个计数器溢出时,该计数器将递增。这实际上将创建一个不会溢出的64位计数器。

最简单的方法是创建一个“历元计数器”,它显式地计算滚动次数。(例如:您有一个计数秒数为0..59的硬件计数器。您的历元计数器将计数分钟,每次它注意到秒数计数器已滚动时都会递增。)

然后,future_scheduler函数读取当前的历元和时间,并为事件计算新的历元和时间


或者,您可以直接下注,并让计时函数在每个计时器滴答声中将事件计划计数为零。

一种可能性是将两个变量强制转换为64位长,然后求和。然后与最大32位值进行比较,以确定它是否已包装。

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


但是,这无法检测计数器是否已包装多次,或者计数器已包装且恰好大于第一个读数的情况。既然你说这是一个嵌入式系统,并且你的描述让你的“计数器”听起来像一个时钟,那么看看你是否可以设置一个中断,在时钟达到零时触发(这样,每次时钟重置时你都会得到一个中断)。当该中断触发时,增加一个单独的计数器。这将有效地为时钟增加额外的精度,并允许计数器在不引起问题的情况下进行包装。

嵌入时,您可能会访问CPU溢出位。这将在add溢出其寄存器时设置。对添加进位链有用。

只要开始计数和结束计数之间的差值小于(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
因此,只要计数器是内置整数类型的位宽度,并且使用该类型,就可以得到正确的答案。如果计数器寄存器的宽度可能不是内置整数类型的宽度,则可以通过屏蔽高阶“溢出”位来实现相同的效果


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

将无符号减法的结果强制转换为有符号并比较为零。如果您经常检查溢出(并且超时时间小于计时器范围的一半),则应处理溢出


如果使用无符号变量存储计数器和计时器到期时间,则只需使用以下测试:

if (current_time - expiry_time < 0x80000000UL)
    /* timer has expired */
if(当前时间-到期时间<0x80000000UL)
/*计时器已过期*/

这假设您至少每0x8000000个刻度测试一次到期时间,并且您的最长计时器设置为将来到期时间小于0x8000000个刻度。

我认为最简单的方法之一是使用另一个计数器(我们称之为Wrap counter,这是计时器模块的静态全局计数器),每次原始32位计数器包装时,都要进行计数

在计数器滴答作响的函数中,每当此计数器达到其最大计数时,您的换行计数器就会递增。
因此,当您在读取返回计时器是否已过的函数时,您还可以读取Wrap计数器,以检查它已结束多少次。重要的是,也要做到这一点:每次你阅读包装计数器时,你都想清除它,以便下次阅读

让我们假设计数器倒计时(多个倒计时以保存逻辑中的门)

您首先需要知道达到2^32个滴答声所需的时间段,并且需要确保对其进行过采样

如果要查找两个事件之间的时间段,请说开始和结束

开始=读取计时器 最后一次=开始 R
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);
if (current_time - expiry_time < 0x80000000UL)
    /* timer has expired */