2017-01-14 5 views
1

У меня проблема с функцией vTaskDelayUntil(), не делая задержки, но заканчивая немедленно. Вот код:FreeRTOS 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()?

+1

У вас есть #define INCLUDE_vTaskDelayUntil 1 в вашем файле конфигурации? И вы уверены, что не переопределили TickType_t, допустим, подписали 16 бит? Попробуйте переместить TickType_t xLastWakeTime = xTaskGetTickCount(); после того, как при семафоре возьмут, теперь он покажет правильные значения? (Я знаю, что это не сделает то, что вы хотите, просто для простой проверки, если это вызвано тем, что в первый раз вы попадаете в vTaskDelay. Если вы уже превысили xLastWakeTime + 2000. – koper89

+0

Да, у меня есть этот define и TickType_t - 32-разрядный тип. и инициализация xLastWakeTime помогает! Интересно, как. Конечно, мой оригинальный код не был идеальным, потому что получение semphore может занять до 10 секунд, а первый vTaskDelayUntil() немедленно выйдет. Но я до сих пор не знаю, почему на второй итерации эта переменная была установлена ​​на 5919 не 30534. – grzegorz

ответ

5

В вашей первой итерации 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 станет доступным, и я думаю, что вы намеревались.

+0

Семафор здесь работает как мьютекс для синхронизации доступа к ссылке RS485. Задача должна получить семафор до того, как он выполнит sendDisplayData(). Когда ссылка RS485 не используется другой задачей, я хотите, чтобы он выполнял sendDisplayData() каждые две секунды. И, пожалуйста, взгляните на последующие итерации. Как 5919 и 7919 можно объяснить относительно 30534? – grzegorz

+1

@grzegorz: достаточно справедливо, но после начальной синхронизации вы ничего не синхронизируете, так как вы даете семафор непосредственно перед тем и в том же контексте, что и вы его принимаете. Jour «оправдание» скорее свидетельствует о том, что вы не поняли моего ответа, а не причине того, что код является таким, каким он есть. Возможно, вам все еще нужно ждать семафора, но вам нужно удалить sem give, так как это побеждает вашу синхронизацию - это другая проблема, а не в рамках вашего вопроса - этот ответ исправит описанную вами проблему. – Clifford

+1

Что касается других итераций - да, они объясняются в этом ответе. Вы начинаете с 26000 тиков позади, потребуется несколько итераций, увеличивающих целевое время на 2000, прежде чем он настигнет текущее время. Понятно, что происходит с вашим отладочным результатом. – Clifford

1

Как указано выше, vTaskDelayUntil() немедленно вернется, если указанное время пробуждения уже было в прошлом. Вместо этого предложите использовать vTaskDelay().