☰
FreeRTos 笔记(7a)任务调度器的挂起与恢复:_SuspendAll 见 5C。SysTick_Handler(源) 经 xTaskIncrementTick(源码)触发任务调度 pendSV
2026/11/4 7:12:43 网站建设 项目流程

(59)ppt:

++脑图 pdf:

++补充最后一部分:

(60)任务调度始于 SysTick_Handler:

voidSysTick_Handler(void)// 正点原子自定义的 delay.c 文件中{HAL_IncTick();// 意思是只要调度器启动了,无论调度器是否又被挂起,都执行下面的 if 内容if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)// taskSCHEDULER_NOT_STARTED = 1xPortSysTickHandler();/* OS开始跑了,才执行正常的调度处理 */}

(61)SysTick_Handler 调用了下面的变量与函数 xTaskGetSchedulerState:

__IOuint32_tuwTick;// stm32f1xx_hal.c 68 行, 这是全局变量uint32_tuwTickPrio=(1UL<<__NVIC_PRIO_BITS);/* Invalid PRIO */HAL_TickFreqTypeDef uwTickFreq=HAL_TICK_FREQ_DEFAULT;/* 1KHz */__weakvoidHAL_IncTick(void)// 本函数其实并没有被重写 // stm32f1xx_hal.c 293 行{uwTick+=uwTickFreq;// __IO uint32_t uwTick; 全局变量}BaseType_txTaskGetSchedulerState(void)// tasks.c 3727{BaseType_t xReturn;if(xSchedulerRunning==pdFALSE)xReturn=taskSCHEDULER_NOT_STARTED;//= 1else{if(uxSchedulerSuspended==(UBaseType_t)pdFALSE)xReturn=taskSCHEDULER_RUNNING;//= 2elsexReturn=taskSCHEDULER_SUSPENDED;//= 0}returnxReturn;}

(62)SysTick_Handler 也调用了下面的变量与函数 xPortSysTickHandler:

voidxPortSysTickHandler(void)// port.c 429{//SysTick 以最低内部中断优先级运行,因此当此中断执行时,必须解除屏蔽所有中断。//因此,无需保存和恢复中断屏蔽值,因为其值已知//一一因此使用稍快的 vPortRaiseBASEPRI 函数来替代 portSET_INTERRUPT_MASK_FROM_ISR()//static portFORCE_INLINE void vPortRaiseBASEPRI( void )vPortRaiseBASEPRI();// 此函数有返回值,返回 BASEPRI 里原来的值{/* Increment the RTOS tick. */if(xTaskIncrementTick()!=pdFALSE){/* A context switch is required. * Context switching is performed in the PendSV interrupt. Pend the PendSV interrupt. */portNVIC_INT_CTRL_REG=portNVIC_PENDSVSET_BIT;// * 0xE000ED04 = 1 << 28 // SCR_ICSR 寄存器的 bit28 置 1 就会触发 pendSV 中断}}vPortClearBASEPRIFromISR();// msr basepri, # 0}

(63)xPortSysTickHandler 调用了下面的 xTaskIncrementTick:

BaseType_txTaskIncrementTick(void)// tasks.c 2482{TCB_t*pxTCB;TickType_t xItemValue;BaseType_t xSwitchRequired=pdFALSE;//返回值,表是否需要发起任务切换, T 表需要调度任务traceTASK_INCREMENT_TICK(xTickCount);// #define traceTASK_INCREMENT_TICK( xTickCount ) 统计测试//此 if 里有 150 行,是 tick 调度任务的逻辑,最复杂的情况,有 150 行。else 表调度器挂起的情况if(uxSchedulerSuspended==(UBaseType_t)pdFALSE)// uxSchedulerSuspended 是计数器{/* Minor optimisation. The tick count cannot change in this block. */constTickType_t xConstTickCount=xTickCount+(TickType_t)1;/* Increment the RTOS tick, switching the delayed and overflowed * delayed lists if it wraps to 0. */xTickCount=xConstTickCount;//FreeRTOS 32bit tick,1ms 节拍,约 49.7 天 tick 溢出,采用双延时链表轮换if(xConstTickCount==(TickType_t)0U){taskSWITCH_DELAYED_LISTS();// 这是很短的宏,记录在下面}elsemtCOVERAGE_TEST_MARKER();/* See if this tick has made a timeout expire. Tasks are stored in * the queue in the order of their wake time - meaning once one task * has been found whose block time has not expired there is no need to * look any further down the list. */// 这是处理阻塞任务与唤醒,暂时略if(xConstTickCount>=xNextTaskUnblockTime){for(;;){if(listLIST_IS_EMPTY(pxDelayedTaskList)!=pdFALSE){/* The delayed list is empty. Set xNextTaskUnblockTime * to the maximum possible value so it is extremely * unlikely that the * if( xTickCount >= xNextTaskUnblockTime ) test will pass * next time through. */xNextTaskUnblockTime=portMAX_DELAY;break;}else{/* The delayed list is not empty, get the value of the * item at the head of the delayed list. This is the time * at which the task at the head of the delayed list must * be removed from the Blocked state. */pxTCB=listGET_OWNER_OF_HEAD_ENTRY(pxDelayedTaskList);xItemValue=listGET_LIST_ITEM_VALUE(&(pxTCB->xStateListItem));if(xConstTickCount<xItemValue){/* It is not time to unblock this item yet, but the * item value is the time at which the task at the head * of the blocked list must be removed from the Blocked * state - so record the item value in * xNextTaskUnblockTime. */xNextTaskUnblockTime=xItemValue;break;}elsemtCOVERAGE_TEST_MARKER();/* It is time to remove the item from the Blocked state. */listREMOVE_ITEM(&(pxTCB->xStateListItem));/* Is the task waiting on an event also? If so remove * it from the event list. */if(listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem))!=NULL)listREMOVE_ITEM(&(pxTCB->xEventListItem));elsemtCOVERAGE_TEST_MARKER();/* Place the unblocked task into the appropriate ready * list. */prvAddTaskToReadyList(pxTCB);/* A task being unblocked cannot cause an immediate * context switch if preemption is turned off. */#if(configUSE_PREEMPTION==1){/* Preemption is on, but a context switch should * only be performed if the unblocked task has a * priority that is equal to or higher than the * currently executing task. */if(pxTCB->uxPriority>=pxCurrentTCB->uxPriority)xSwitchRequired=pdTRUE;elsemtCOVERAGE_TEST_MARKER();}#endif/* configUSE_PREEMPTION */}//if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )}//for( ; ; )}//if( xConstTickCount >= xNextTaskUnblockTime )//1:如果抢占功能已开启且应用程序编写者未显式关闭时间片,// 则与当前运行任务具有相同优先级的任务将共享处理时间(时间片)//2:FreeRTOS 的抢占式调度是高优先级任务永远不会让 CPU 给低优先级任务,除非自己睡眠,// 但多个最高优先级任务之间,会共享轮转时间片,轮转时间就是一个滴答, 1ms。内核是 9MHz。//3:这不同于 linux, linux 是所有任务都能得到时间片,只是高优先级的任务得到的时间片长一些而已。#if((configUSE_PREEMPTION==1)&&(configUSE_TIME_SLICING==1)){if(listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[pxCurrentTCB->uxPriority]))>(UBaseType_t)1)xSwitchRequired=pdTRUE;elsemtCOVERAGE_TEST_MARKER();}#endif#if(configUSE_TICK_HOOK==1)// 本项目里不成立//.....#endif/* configUSE_TICK_HOOK */#if(configUSE_PREEMPTION==1){if(xYieldPending!=pdFALSE)xSwitchRequired=pdTRUE;elsemtCOVERAGE_TEST_MARKER();}#endif/* configUSE_PREEMPTION */}else//当调度器被挂起的时候,仅递增下面的计数值,并返回 false{++xPendedTicks;//这是全局量 static volatile TickType_t xPendedTicks = ( TickType_t ) 0U;/* The tick hook gets called at regular intervals, even if the scheduler is locked. */#if(configUSE_TICK_HOOK==1)// configUSE_TICK_HOOK = 0,本 if 不成立vApplicationTickHook();#endif}returnxSwitchRequired;// BaseType_t xSwitchRequired = pdFALSE; 此局部变量的默认值是 False}// BaseType_t xTaskIncrementTick( void ) 返回值是是否需要发起任务切换

(64)用于交换延时链表的宏 taskSWITCH_DELAYED_LISTS:

/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick count overflows. */#definetaskSWITCH_DELAYED_LISTS()\{\List_t*pxTemp;\\/* The delayed tasks list should be empty when the lists are switched. */\configASSERT((listLIST_IS_EMPTY(pxDelayedTaskList)));\\pxTemp=pxDelayedTaskList;\pxDelayedTaskList=pxOverflowDelayedTaskList;\pxOverflowDelayedTaskList=pxTemp;\xNumOfOverflows++;\prvResetNextTaskUnblockTime();\}

(65)

谢谢

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询