在FreeRTOS中,任务调度是由调度器完成的。每个任务都可以通过调用不同的task API函数来添加任务到调度器中,vTaskDelay就是其中之一,它能够把任务阻塞一段时间。在这篇文章中,我们将详细介绍vTaskDelay的各种用法及其实现原理。
一、vTaskDelay(0)
vTaskDelay(0)是使用最普遍的调度函数之一。它允许其他任务获得时间片来执行,同时也会安排当前任务回到就绪状态。在实际开发中,很多任务需要在执行完成后立即回到任务列表中等待下一次执行,这时就可以使用vTaskDelay(0)。
void task_a(void *p) { while(1) { //处理任务a的相关操作 vTaskDelay(0); //将任务a放回任务列表 } }
二、vTaskDelayUntil函数
vTaskDelayUntil函数使任务在精确定时刻执行。这个函数的参数包括初始时间和延迟时间,任务将延迟至指定的时间再执行。在调用这个函数时需要注意的是,传入的tick值必须是由系统提供的时间源进行计算得到的,这可以通过FreeRTOS提供的configTICK_RATE_HZ宏定义来获取。
void task_b(void *p) { TickType_t xLastWakeTime; const TickType_t xFrequency = pdMS_TO_TICKS(1000); //任务周期为1s xLastWakeTime = xTaskGetTickCount(); while(1) { //处理任务b的相关操作 vTaskDelayUntil(&xLastWakeTime, xFrequency); //延时至循环周期结束 } }
三、vTaskDelay vinsertlist函数
vTaskDelay vinsertlist函数可以暂停一个任务的执行,为其分配不少于指定周期的时间片。比如,在一些特别紧急的情况下,我们可能希望让某个任务立即执行,这种情况下可以使用vTaskDelay vinsertlist指令来插入或者替换一个或几个任务的time list中的任务,已实现快速切换。
void task_c(void *p) { while(1) { //处理任务c的相关操作 vTaskDelay(1000); //暂停任务c1s vTaskDelayVInsert(&xTaskToDelay, 0); //插入/替换一个新任务 } }
四、vTaskDelay卡死
虽然vTaskDelay函数是非常有用的一个函数,但是在某些情况下可能会出现任务阻塞或卡死的现象。这种情况一般是由于系统调度器任务堵塞所导致的,可以通过增加系统tick时间,减少任务阻塞时间,来解决该问题。
五、vTaskDelay调用卡死
在一些特殊情况下,比如在中断服务程序中调用vTaskDelay函数,就会导致当前任务阻塞或卡死。这种情况下,建议使用Task-Notify机制,或者是在FreeRTOS中使用队列来实现相关功能。
六、vTaskDelay(100)
vTaskDelay(100)是一个阻塞当前任务的函数。它将任务放入任务等待列表,并在给定的时间(这里是100*configTICK_RATE_HZ)之后再执行该任务。在实际开发中,我们经常会使用这个函数来模拟并发执行。
void task_d(void *p) { while(1) { //处理任务d的相关操作 vTaskDelay(100); //等待100ticks后再次执行任务 } }
七、vTaskDelay用不了
如果您的程序中无法使用vTaskDelay函数,却不确定原因,可以考虑以下情况:
1、任务列表中只有一个任务,任务执行的频率太高。
2、推出中断锁定时调用vTaskDelay函数,会发生阻塞。
3、在中断服务程序中调用了vTaskDelay函数,导致任务卡死。
八、vTaskDelayUntil设置多少
在使用vTaskDelayUntil时,应该根据实际系统运行情况来设置任务延时时间。一般来说,任务的延时时间应该小于一个任务的周期,在本例中我们设置了1000ms,也就是一个周期。如果需要更高的实时性,建议将该值适当缩小。
以上就是关于vTaskDelay函数的详细介绍,通过了解vTaskDelay的常规用法及其实现原理,可以更好地用这个函数来掌握任务的执行时间。希望这篇文章能够帮助您更好地利用vTaskDelay。