2

我有一个问题,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() 返回的相似值吗?

4

2 回答 2

6

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

从文档vTaskDelayUntil()

需要注意的是,如果 vTaskDelayUntil() 用于指定已经过去的唤醒时间,它将立即返回(不阻塞)。

您的任务在初始信号量上花费了 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 资源可用的时间,我认为这是你想要的。

于 2017-01-14T16:53:04.460 回答
1

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

于 2017-01-15T00:39:13.953 回答