FreeRTOS vTaskDelayUntil() 立即完成

FreeRTOS vTaskDelayUntil() finishes immediately

我对 vTaskDelayUntil() 函数没有延迟但立即完成有问题。这是代码:

TickType_t xLastWakeTime = xTaskGetTickCount();
while(1){
    if (xSemaphoreTake(xSemaphoreRS485, portMAX_DELAY) == pdTRUE) {
        printf("S display data %d\n", xTaskGetTickCount());
        sendDisplayData();
        printf("E display data %d\n", xTaskGetTickCount());
        xSemaphoreGive(xSemaphoreRS485);
        printf("W display data %d\n", xLastWakeTime);
        vTaskDelayUntil(&xLastWakeTime, 2000);
    }
}

由此我得到以下输出:

S display data 29928
E display data 30534
W display data 3919
S display data 30534
E display data 31140
W display data 5919
S display data 31140
E display data 31746
W display data 7919
S display data 31746
E display data 32352
W display data 9919

函数 sendDisplayData() 的执行时间约为 670 毫秒,xTaskGetTickCount() 对此进行了确认。然后任务应该等待大约 1230 毫秒,这样整个迭代可能需要 2000 毫秒。但是 vTaskDelayUntil() 立即完成。第一次执行结束于 30534,第二次执行也于 30534 开始。 xTaskGetTickCount() 返回的值证明 vTaskDelayUntil() 没有引入延迟。我也可以通过 sendDisplayData() 的输出频率看到它。

第二个有趣的事情是 xLastWakeTime 显示完全不同的值,这些值实际上增加了 2000。它不应该存储与 xTaskGetTickCount() 返回的相似值吗?

在您的第一次迭代中,xLastWakeTime 的值为 3919,您请求增加 2000,因此延迟到 5919,但您在时间 30534 调用了它。

来自 vTaskDelayUntil()

的文档

It should be noted that vTaskDelayUntil() will return immediately (without blocking) if it is used to specify a wake time that is already in the past.

您的任务在初始信号量上阻塞了 26009 个滴答 (29928 - 3919)。您的目标 2000 刻度增量早已过去。

我建议以下内容至少更接近您的预期

for(;;)
{
    if (xSemaphoreTake(xSemaphoreRS485, portMAX_DELAY) == pdTRUE)  // Lock
    {
        TickType_t xLastWakeTime = xTaskGetTickCount();
        sendDisplayData();
        xSemaphoreGive(xSemaphoreRS485); // Unlock

        vTaskDelayUntil(&xLastWakeTime, 2000);
}

这将使循环迭代总共花费 2000 个滴答,包括执行 sendDisplayData() 加上 等待 RS485 资源可用的时间,这我认为你的意图是什么。

如上所示,如果指定的唤醒时间已经过去,vTaskDelayUntil() 将立即return。建议改用 vTaskDelay()