IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> FreeRTOS个人笔记-支持时间片 -> 正文阅读

[嵌入式]FreeRTOS个人笔记-支持时间片

根据个人的学习方向,学习FreeRTOS。由于野火小哥把FreeRTOS讲得比较含蓄,打算在本专栏尽量细化一点。作为个人笔记,仅供参考或查阅。

配套资料:FreeRTOS内核实现与应用开发实战指南、野火FreeRTOS配套视频源码、b站野火FreeRTOS视频。搭配来看更佳哟!!!

支持时间片

FreeRTOS与RT-Thread和uC/OS一样,都支持时间片功能。

时间片:同一优先级下可以有多个任务,每个任务轮流地享有相同的CPU时间。享有相同的CPU时间称为时间片

在FreeRTOS中,最小的时间单位为1个tick,即SysTick的中断周期,时间片只能是一个tick。RT-Thread和uC/OS可以指定时间片的大小为多个tick。

时间片测试实验

假设目前系统中有三个任务就绪(算上空闲任务就是4个),Task1和Task2的优先级为2,Task3的优先级为3。IdeaTask的优先级默认为0。

为了方便在逻辑分析仪中分辨出Task1和Task2使用的时间片大小,?Task1和Task2的主体编写成一个无限循环函数(优先级低于2的Task就会被饿死,得不到执行,比如idleTask),不会阻塞,Task3的阻塞时间设置为1个tick。在真正的项目中,不会这么写,这只是为了实验方便。

main函数如下

/*
*************************************************************************
*                              全局变量
*************************************************************************
*/
portCHAR flag1;
portCHAR flag2;
portCHAR flag3;

extern List_t pxReadyTasksLists[ configMAX_PRIORITIES ];

/*
*************************************************************************
*                        任务控制块 & STACK 
*************************************************************************
*/
TaskHandle_t Task1_Handle;
#define TASK1_STACK_SIZE                    128
StackType_t Task1Stack[TASK1_STACK_SIZE];
TCB_t Task1TCB;

TaskHandle_t Task2_Handle;
#define TASK2_STACK_SIZE                    128
StackType_t Task2Stack[TASK2_STACK_SIZE];
TCB_t Task2TCB;

TaskHandle_t Task3_Handle;
#define TASK3_STACK_SIZE                    128
StackType_t Task3Stack[TASK3_STACK_SIZE];
TCB_t Task3TCB;

/*
*************************************************************************
*                               函数声明 
*************************************************************************
*/
void delay (uint32_t count);
void Task1_Entry( void *p_arg );
void Task2_Entry( void *p_arg );
void Task3_Entry( void *p_arg );


/*
************************************************************************
*                                main函数
************************************************************************
*/
int main(void)
{	
    /* 硬件初始化 */
	/* 将硬件相关的初始化放在这里,如果是软件仿真则没有相关初始化代码 */
    
    /* 创建任务 */
    Task1_Handle = xTaskCreateStatic( (TaskFunction_t)Task1_Entry,   /* 任务入口 */
					                  (char *)"Task1",               /* 任务名称,字符串形式 */
					                  (uint32_t)TASK1_STACK_SIZE ,   /* 任务栈大小,单位为字 */
					                  (void *) NULL,                 /* 任务形参 */
                                      (UBaseType_t) 2,               /* 任务优先级,数值越大,优先级越高 */
					                  (StackType_t *)Task1Stack,     /* 任务栈起始地址 */
					                  (TCB_t *)&Task1TCB );          /* 任务控制块 */
                                
    Task2_Handle = xTaskCreateStatic( (TaskFunction_t)Task2_Entry,   /* 任务入口 */
					                  (char *)"Task2",               /* 任务名称,字符串形式 */
					                  (uint32_t)TASK2_STACK_SIZE ,   /* 任务栈大小,单位为字 */
					                  (void *) NULL,                 /* 任务形参 */
                                      (UBaseType_t) 2,               /* 任务优先级,数值越大,优先级越高 */                                          
					                  (StackType_t *)Task2Stack,     /* 任务栈起始地址 */
					                  (TCB_t *)&Task2TCB );          /* 任务控制块 */
                                      
    Task3_Handle = xTaskCreateStatic( (TaskFunction_t)Task3_Entry,   /* 任务入口 */
					                  (char *)"Task3",               /* 任务名称,字符串形式 */
					                  (uint32_t)TASK3_STACK_SIZE ,   /* 任务栈大小,单位为字 */
					                  (void *) NULL,                 /* 任务形参 */
                                      (UBaseType_t) 3,               /* 任务优先级,数值越大,优先级越高 */                                          
					                  (StackType_t *)Task3Stack,     /* 任务栈起始地址 */
					                  (TCB_t *)&Task3TCB );          /* 任务控制块 */                                      
                                      
    portDISABLE_INTERRUPTS();
                                      
    /* 启动调度器,开始多任务调度,启动成功则不返回 */
    vTaskStartScheduler();                                      
    
    for(;;)
	{
		/* 系统启动成功不会到达这里 */
	}
}

/*
*************************************************************************
*                               函数实现
*************************************************************************
*/
/* 软件延时 */
void delay (uint32_t count)
{
	for(; count!=0; count--);
}
/* 任务1 */
void Task1_Entry( void *p_arg )
{
	for( ;; )
	{
		flag1 = 1;
        //vTaskDelay( 1 );
        delay (100);		
		flag1 = 0;
        delay (100);
        //vTaskDelay( 1 );        
	}
}

/* 任务2 */
void Task2_Entry( void *p_arg )
{
	for( ;; )
	{
		flag2 = 1;
        //vTaskDelay( 1 );
        delay (100);		
		flag2 = 0;
        delay (100);
        //vTaskDelay( 1 );        
	}
}


void Task3_Entry( void *p_arg )
{
	for( ;; )
	{
		flag3 = 1;
        vTaskDelay( 1 );
        //delay (100);		
		flag3 = 0;
        vTaskDelay( 1 );
        //delay (100);
	}
}

/* 获取空闲任务的内存 */
StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
TCB_t IdleTaskTCB;
void vApplicationGetIdleTaskMemory( TCB_t **ppxIdleTaskTCBBuffer, 
                                    StackType_t **ppxIdleTaskStackBuffer, 
                                    uint32_t *pulIdleTaskStackSize )
{
		*ppxIdleTaskTCBBuffer=&IdleTaskTCB;
		*ppxIdleTaskStackBuffer=IdleTaskStack; 
		*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}

进入软件调试,全速运行程序,从逻辑分析仪中可以看出Task1和Task2轮流执行,每一次运行的时间等于Task3中flag3输出高电平或低电平的时间,即一个tick。

?

之所以在同一个优先级下可以有多个任务,最终还是得益于taskRESET_READY_PRIORITY()和taskSELECT_HIGHEST_PRIORITY_TASK()这两个函数。

系统在任务切换的时候总会从就绪列表中寻找优先级最高的任务来执行,寻找优先级最高的任务。

这个功能由 taskSELECT_HIGHEST_PRIORITY_TASK()函数来实现,该函数在 task.c 中定义。

目前我们的实验是在优先级 2 上有任务 1和任务 2,假设任务 1 运行了一个 tick,那接下来再从对应优先级 2 的就绪列表上选择任务来运行就应该是选择任务 2?怎么选择,代码上
怎么实现?奥妙就在 listGET_OWNER_OF_NEXT_ENTRY()函数中,该函数在 list.h 中定义。

前面还谈到了另一个函数,taskRESET_READY_PRIORITY()。

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

taskRESET_READY_PRIORITY() 函 数 的 妙 处 在 于 清 除 优 先 级 位 图 表 uxTopReadyPriority 中相应的位时候,会先判断当前优先级链表下是否还有其它任务,如果有则不清零。
假设当前实验中,任务 1 会调用 vTaskDelay(),会将自己挂起,只能是将任务 1 从就绪列表删除,不能将任务 1 在优先级位图表 uxTopReadyPriority 中对应的位清 0,因为该优先级下还有任务 2,否则任务 2 将得不到执行。
?

当xTaskIncrementTick()函数返回为真时才进行任务切换, 原来的 xTaskIncrementTick()是不带返回值的, 执行到最后会调用 taskYIELD()执行任务切换。

xTaskIncrementTick()函数如下

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

	/* 开中断 */
    vPortClearBASEPRIFromISR();
}

xTaskIncrementTick()函数如下

//返回值为pdTrue时,需要执行一次任务切换
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 )    //宏,默认设为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();
}

这节没什么好写的,看不懂的话多看看配套文档和源码。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-07-21 21:42:18  更:2022-07-21 21:44:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:50:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码