以下是我在固件中发现的延迟功能。它看起来有些危险,或者至少使读者感到困惑。

全局变量

static int32u masterTimerCounter; // 32-bit unsigned timer counter


系统滴答中断处理程序

/* Called Every Millisecond */
void sysTickIrqHandler(void)
{
    masterTimerCounter++;
}


设置计时器到期功能

void setTimerExpiration(int32u *timerExpiration, int32u delay)
{
    *timerExpiration = masterTimerCounter + delay;
}


检查计时器是否过期功能

boolean timerExpired(int32u timerExpiration, int32u delay)
{
    if((masterTimerCounter - timerExpiration) < delay)
        return TRUE; // Timer has expired
    else
        return FALSE; // Timer still active
}


设置计时器到期并阻止直到计时器到期

int32u timerExpiration;
setTimerExpiration(&timerExpiration, 15); // Set expiration timer to 15 milliseconds
while(!timerExpired(timerExpiration, 15) // Block until timer has expired
    continue;




如您在timerExpired()中看到的,masterTimerCountertimerExpiration减去。如果计时器尚未到期,则计算将产生非常大的数字(因为两个操作数均为无符号数字)。当计时器到期时,计算将得出小于延迟量的值。

尽管这似乎可以正常工作,但似乎可能很危险,或者至少会使读者感到困惑(我必须阅读几次才能理解原始程序员的意图)。

如果必须编写与此类似的内容,则可以如下定义timerExpired函数:

boolean timerExpired(int32u timerExpiration)
{
    if(timerExpiration > masterTimerCounter)
        return FALSE; // Timer still active
    else
        return TRUE; // Timer has expired
}


我应该重新定义'timerExpired()`吗?

注意:函数和变量名称已更改,以保护无辜。

最佳答案

您遇到的问题是,如果masterTimerCounter + delay导致32位int的翻转,则timerExpired测试会立即通过。

我认为在可能发生翻转的情况下执行整数计时器的最直接方法是这样的:

void startTimer(int32u *timerValue)
{
    *timerValue = masterTimerCounter;
}


检查计时器是否过期功能

boolean timerExpired(int32u timerVal, int32u delay)
{
    if ((masterTimerCounter - timerVal) >= delay)
        return TRUE; // Timer has expired
    else
        return FALSE; // Timer still active
}


用法:

int32u timer;
startTimer(&timer); // Start timing
while(!timerExpired(timer, 15) // Block for 15 ticks
    continue;


即使timerExpired中的减法下溢也会返回正确的结果。

10-02 05:38