嵌入式FreeRTOS学习十,任务调度和任务就绪链表任务调度过程

一.main函数里面的栈是哪里分配的

main函数里面用到的栈,假设为msp,是汇编代码里面设定的,对于STM32F103,在汇编代码里的向量表设置了一个栈_initial_sp,那这个栈是给谁用的呢?

可以看到,这个_initial_sp在内存中分配了一个空间区域,Stack_Size=0x00000200,大小为16进制的200个字节,将这块内存空间的高地址放入_initial_sp,对于STM32F103,单片机启动的时候,会将_initial_sp的值存进一个main_sp 寄存器中。c函数中要用到栈,栈里面保存返回地址,保存局部变量,那么c函数什么时候用到栈呢?

在将_initial_sp这个值入栈后,接下来会跳转到Reset_Handler,Reset_Handler函数会调用__main函数,__main进行一系列初始化以后,会调用main函数。Reset_Handler下面有很多的中断函数,这些中断函数也是C函数,也是使用分配的这些栈的

========================================================================= 

二.任务执行流程

任务切换的流程在第九章已经了解了,现在假设任务Task 1,任务Task 2,任务Task 3的任务优先级都设置为0,那么这三个任务都会进入同一个就绪链表里面,进入pxReadyTasksList[0]就绪链表,那么这三个任务谁先执行?

 //创建三个任务   
int main( void )
{
	prvSetupHardware();
	
	xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
	xTaskCreate(vTask2, "Task 2", 1000, NULL, 1, NULL);
	xTaskCreate(vTask3, "Task 3", 1000, NULL, 1, NULL);
	/* 启动调度器 */
	vTaskStartScheduler();
	/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
	return 0;
}

可以看到,我们创建了三个优先级为01的任务,第一个任务Task1进入就绪链表以后,任务Task1就是当前任务,创建任务Task2的时候,因为任务Task2和任务Task1是同等任务优先级,所以任务Task2就成为了当前任务,同样的道理,任务Task3与任务Task2同等任务优先级,当任务Task3加入任务就绪链表以后,任务Task3就成为了当前任务。所以执行任务的话是任务Task3先运行,执行完后,把任务Task3放入链表后面;然后遵循链表先进先出的原则,依次执行任务Task1,任务Task2。

这是同等任务优先级的情况,记住,高优先级一定会抢占低优先级的任务,高优先级一但长时间处于运行状态(没有vTaskDelay( xDelay5ms )函数进行阻塞),低优先级根本得不到运行。如果没有更高优先级的任务,大家的优先级都一样,则轮流执行。

 上面的main函数中,我们使用xTaskCreate函数创建了三个任务,那仅仅创建了三个任务吗?不是的,我们调用vTaskStartScheduler()函数启动任务调度器的时候,还创建了一个空闲任务,什么是空闲任务,有什么作用呢?

开启任务调度函数会创建一个空闲任务idle_Task,此时空闲任务会把CPU交给任务Task1,务Task1开始运行。空闲任务idle_Task执行其他任务的栈空间清理工作,例如任务Task1自己死掉了,那么任务Task1的栈空间里的内存空间由空闲任务idle_Task进行释放。

=========================================================================

三.任务调度器函数 

启动任务调度器后会创建空闲任务,空闲任务idle_task的任务优先级也是0,会进入任务就绪链表pxReadyTasksList[0],当前任务就会指向空闲任务,如果创建3个任务优先级为0的任务Task 1,任务Task 2,任务Task 3,会先运行空闲任务。也就是说,空闲任务会影响调度过程。当前TCB指向idle_task,然后任务Task 1,任务Task 2,任务Task 3。

//任务调度函数
void vTaskStartScheduler( void )
{
    BaseType_t xReturn;
    /* Add the idle task at the lowest priority. */
    #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
        {
            StaticTask_t * pxIdleTaskTCBBuffer = NULL;
            StackType_t * pxIdleTaskStackBuffer = NULL;
            uint32_t ulIdleTaskStackSize;
            /* The Idle task is created using user provided RAM - obtain the
             * address of the RAM then create the idle task. */
            vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
            xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
                                                 configIDLE_TASK_NAME,
                                                 ulIdleTaskStackSize,
                                                 ( void * ) NULL,      
                                                 portPRIVILEGE_BIT,     /
                                                 pxIdleTaskStackBuffer,
                                                 pxIdleTaskTCBBuffer );
            if( xIdleTaskHandle != NULL )
            {
                xReturn = pdPASS;
            }
            else
            {
                xReturn = pdFAIL;
            }
        }
    #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
        {
            xReturn = xTaskCreate( prvIdleTask,
                                   configIDLE_TASK_NAME,
                                   configMINIMAL_STACK_SIZE,
                                   ( void * ) NULL,
                                   portPRIVILEGE_BIT,  
                                   &xIdleTaskHandle );
        }

                                                                                                                                       

猜你喜欢

转载自blog.csdn.net/weixin_44651073/article/details/127881962