第12章 支持时间片

第12章 支持时间片


   FreeRTOS 与隔壁的 RT-ThreadμC/OS 一样,都支持时间片的功能。所谓时间片就是同一个优先级下可以有多个任务,每个任务轮流地享有相同的 CPU 时间,享有 CPU 的时间我们叫时间片。在 RTOS 中,最小的时间单位为一个 tick,即 SysTick 的中断周期, RT-ThreadμC/OS 可以指定时间片的大小为多个 tick,但是 FreeRTOS 不一样,时间片只能是一个 tick与其说 FreeRTOS 支持时间片,倒不如说它的时间片就是正常的任务调度。

12.4 原理分析

  在同一个优先级下可以有多个任务 , 最终还是得益于taskRESET_READY_PRIORITY()taskSELECT_HIGHEST_PRIORITY_TASK()这两个函数的实现方法。
  系统在任务切换的时候总会从就绪列表中寻找优先级最高的任务来执行,寻找优先级最高的任务这个功能由taskSELECT_HIGHEST_PRIORITY_TASK()函数来实现,该函数在task.c 中定义。

12.4.1 taskSELECT_HIGHEST_PRIORITY_TASK()函数

	#define taskSELECT_HIGHEST_PRIORITY_TASK()														    \
	{																								    \
	    UBaseType_t uxTopPriority;																	    \
																									    \
		/* 寻找包含就绪任务的最高优先级的队列 */								                            \
		portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );								    \
		/* 获取优先级最高的就绪任务的TCB,然后更新到pxCurrentTCB */                                        \
		listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );		    \
	} /* taskSELECT_HIGHEST_PRIORITY_TASK() */

12.4.2 listGET_OWNER_OF_NEXT_ENTRY()函数

entry 进入,加入;出场,莅临;门,入口;进入权,进入许可;参赛;参赛作品,竞赛答题;

/* 获取链表节点的OWNER,即TCB */
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )										\
{																							\
	List_t * const pxConstList = ( pxList );											    \
	/* 节点索引指向链表第一个节点调整节点索引指针,指向下一个节点,
    如果当前链表有N个节点,当第N次调用该函数时,pxInedex则指向第N个节点 */\
	( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;							\
	/* 当前链表为空 */                                                                       \
	if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )	\
	{																						\
		( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;						\
	}																						\
	/* 获取节点的OWNER,即TCB */                                                             \
	( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;											 \
}

12.4.3 taskRESET_READY_PRIORITY()函数

	#define taskRESET_READY_PRIORITY( uxPriority )														\
	{																									\
		if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 )	\
		{																								\
			portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );							\
		}																								\
	}

12.5 修改代码,支持优先级

12.5.1 xPortSysTickHandler()函数

void xPortSysTickHandler( void )
{
	/* 关中断 */
    vPortRaiseBASEPRI();
    {
        //xTaskIncrementTick();
        
        /* 更新系统时基 */
		if( xTaskIncrementTick() != pdFALSE )
		{
			/* 任务切换,即触发PendSV */
            //portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
            taskYIELD();
		}
	}
	/* 开中断 */
    vPortClearBASEPRIFromISR();
}
修改 xTaskIncrementTick()函数

//void xTaskIncrementTick( void )
BaseType_t xTaskIncrementTick( void )
{
	TCB_t * pxTCB;
	TickType_t xItemValue;    
    BaseType_t xSwitchRequired = pdFALSE;
    
	const TickType_t xConstTickCount = xTickCount + 1;
	xTickCount = xConstTickCount;

	/* 如果xConstTickCount溢出,则切换延时列表 */
	if( xConstTickCount == ( TickType_t ) 0U )
	{
		taskSWITCH_DELAYED_LISTS();
	}

	/* 最近的延时任务延时到期 */
	if( xConstTickCount >= xNextTaskUnblockTime )
	{
		for( ;; )
		{
			if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
			{
				/* 延时列表为空,设置xNextTaskUnblockTime为可能的最大值 */
				xNextTaskUnblockTime = portMAX_DELAY;
				break;
			}
			else /* 延时列表不为空 */
			{
				pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
				xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );

				/* 直到将延时列表中所有延时到期的任务移除才跳出for循环 */
                if( xConstTickCount < xItemValue )
				{
					xNextTaskUnblockTime = xItemValue;
					break;
				}

				/* 将任务从延时列表移除,消除等待状态 */
				( void ) uxListRemove( &( pxTCB->xStateListItem ) );

				/* 将解除等待的任务添加到就绪列表 */
				prvAddTaskToReadyList( pxTCB );
                

                #if (  configUSE_PREEMPTION == 1 )
                {
                    if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
                    {
                        xSwitchRequired = pdTRUE;
                    }
                }
                #endif /* configUSE_PREEMPTION */
			}
		}
	}/* xConstTickCount >= xNextTaskUnblockTime */
    
    #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
    {
        if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) 
                                     > ( UBaseType_t ) 1 )
        {
            xSwitchRequired = pdTRUE;
        }
    }
    #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
    
    
    /* 任务切换 */
    //portYIELD();
	return xSwitchRequired;
}

  其实 FreeRTOS 的这种时间片功能不能说是真正意义的时间片,因为它不能随意的设置时间为多少个 tick,而是默认一个 tick,然后默认在每个 tick 中断周期中进行任务切换而已。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值