想必各位嵌入式工程师对于Delay延时函数再也熟悉不过了~
但对于各位刚入RTOS的小白来说,有操作系统的延时函数,真的和裸机中的延时函数一样吗?FreeRTOS的任务调度是怎么调度的?如何分配系统的CPU?
今天小编就带大家来扒一下FreeRTOS中的延时函数相对延时vTaskDelay函数,绝对延时vTaskDelayUntil函数。
从事嵌入式这一行的,想必大家在大学的时候一定上过C语言吧,上C语言的时候老师一定给大家写过Delay这个函数吧,给大家举个最简单的延时函数吧~
void Delay (u32 a)
{
while(a--);
}
那同学们是否记得老师讲过这样一句话,“在以后项目开发中,千万不要用Delay这种死循环的方式来延时,最好用定时器来代替Delay延时函数“。
一般情况下,老师都会说过的对吧~
这是因为Dealy的延时,是通过CPU做循环的方式来延时,CPU在延时中是做不了其他东西的,大大浪费了CPU的效率!而且非常危险!
所以大家在裸机中如果要需要很长时间延时的话,建议用定时器来延时。但今天的重点不是裸机的延时函数,而是有操作系统的延时函数。
/*********************************************************************************************************************************************************************************/
刚开始学习FreeRTOS的时候看到FreeRTOS的API延时函数,不竟在想,实时操作系统不是讲究的是实时性吗,怎么也会有这种延时函数!给位大佬有没有共同的感受!
后来深入了解FreeRTOS之后,才发现,原来这延时函数写的这么巧妙!
我们先来看一下 vTaskDelay的源码。这是FreeRTOS中的延时API函数。
void vTaskDelay( const TickType_t xTicksToDelay )
{
BaseType_t xAlreadyYielded = pdFALSE;
if( xTicksToDelay > ( TickType_t ) 0U )
{
configASSERT( uxSchedulerSuspended == 0 );
vTaskSuspendAll();
{
traceTASK_DELAY();
prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
}
xAlreadyYielded = xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
参数:const TickType_t xTicksToDelay 这是输入你要延时的时间
原来在任务中调用延时函数,只是把任务挂起了,等延时时间到,在把任务恢复。
举个例子:
我这边有两个TASK,TASK1和TASK2;
void Task1( void * pvParameters )
{
uint8_t i=0;
while(1)
{
printf("TASK1 RUNNING%d\r\n",i);
GPIO_SetBits(GPIOC,GPIO_Pin_2);
vTaskDelay(500);
GPIO_ResetBits(GPIOC,GPIO_Pin_2);
i++;
vTaskDelay(500);
}
}
void Task2( void * pvParameters )
{
uint8_t j=0;
while(1)
{
j++;
GPIO_ResetBits(GPIOC,GPIO_Pin_3);
vTaskDelay(200);
GPIO_SetBits(GPIOC,GPIO_Pin_3);
vTaskDelay(800);
printf("TASK2 RUNNING%d\r\n",j);
}
}
FreeRTOS这个任务执行是这样的。首先TASK1创建,然后在创建TASK2
TASK先执行, 执行到GPIO_SetBits(GPIOC,GPIO_Pin_2); 下一句vTaskDelay(500); 延时500ms,其实就是任务挂起500ms,CPU此时不会执行TASK的任务,去执行
处于就绪态的TASK2, 当TASK2的GPIO_ResetBits(GPIOC,GPIO_Pin_3); 执行好了之后执行下一条 vTaskDelay(200);此时TASK1延时500ms,TASK延时200ms。
这时候FreeRTOS是没有执行处于就绪态的任务的,只有执行空闲任务 。此时由于TASK2是延时200ms,比TASK2延时的500ms要快,所以TASK2比TASK1更早进入
就绪态,此时CPU执行 GPIO_SetBits(GPIOC,GPIO_Pin_3); 这一语句,执行好了之后TASK2又延时800ms,进入挂起态。当TASK1延时500ms到,TASK1进入就绪态,
执行GPIO_ResetBits(GPIOC,GPIO_Pin_2); i++;语句,执行完之后,TASK1又进入500ms的延时,进入挂起态~
所以在FreeRTOS中的延时函数,只是任务挂起和任务恢复而已,就像创建二值信号量,其实就是创建队列~
学习操作系统本来就是一件枯燥且乏味的事情~共勉
绝对延时vTaskDelayUntil函数下次又机会在讲。