FreeRTOS应用——任务

12. 任务

12.1 相关函数

12.1.1 任务创建函数与启动调度
12.1.1.1 xTaskCreateStatic() 静态创建任务
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,						/* 任务函数 */
									const char * const pcName,					/* 任务名称 */
									const uint32_t ulStackDepth,				/* 任务栈大小 */
									void * const pvParameters,					/* 传递给任务函数的参数 */
									UBaseType_t uxPriority,						/* 任务优先级 */
									StackType_t * const puxStackBuffer,			/* 任务栈 */
									StaticTask_t * const pxTaskBuffer )			/* 任务控制块 */
									
返回值: 创建成功:返回指向任务控制块的指针 TaskHandle_t类型	
		创建失败:返回NULL

相关注意事项:

  1. 任务名称是字符串形式,最大长度由FreeRTOSConfig.h中定义的configMAX_TASK_NAME_LEN宏指定
  2. 任务栈的大小是字,即4字节
  3. 任务入口函数形参,不用时配置为0或者NULL
  4. 任务优先级范围由FreeRTOSConfig.h中定义的configMAX_PRIORITIES决定。如果启用configUSE_PORT_OPTIMISED_TASK_SELECTION宏定义,则使用特殊方法查找下一个运行的任务,则最多支持32个优先级。如果不用,则不限制最大可用优先级数目
12.1.1.2 xTaskCreate() 动态创建任务
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )

	BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,						/* 任务函数 */
							const char * const pcName,						/* 任务名称 */
							const uint16_t usStackDepth,					/* 任务栈大小 */
							void * const pvParameters,						/* 传递给任务函数的参数 */
							UBaseType_t uxPriority,							/* 任务优先级 */
							TaskHandle_t * const pxCreatedTask )			/* 任务控制块指针 */
							
返回值: 创建成功:pdPass
		创建失败:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY

相关注意事项:

  1. 任务优先级范围由FreeRTOSConfig.h中定义的configMAX_PRIORITIES决定。如果启用configUSE_PORT_OPTIMISED_TASK_SELECTION宏定义,则使用特殊方法查找下一个运行的任务,则最多支持32个优先级。如果不用,则不限制最大可用优先级数目
  2. 任务入口函数形参,不用时配置为0或者NULL
12.1.1.3 vTaskStartScheduler() 启动调度
void vTaskStartScheduler( void )

这个任务是真正进入实时操作系统世界的入口。执行完毕后开始调度

调用该函数后会自动创建空闲任务,如果启用了configUSE_TIMERS宏定义,那么定时器任务也会被在其中自动创建。

12.1.2 任务管理函数
12.1.2.1 vTaskSuspend()挂起任务
void vTaskSuspend(TaskHandle_t xTaskToSuspend)

注意事项:

  1. 该函数用于挂起指定任务,被挂起的任务决不会得到CPU的使用权,不管该任务具有什么优先级
  2. 任务可以调用vTaskSuspend函数来挂起自身,但是在挂起自身时会进行一次任务上下文切换,需要挂起自身时将xTaskToSuspend设置为NULL传递进来即可。
  3. 挂起任务之前的状态会被系统保留下来,在恢复的瞬间继续执行
12.1.2.2 vTaskSuspendAll()挂起所有任务
void vTaskSuspendAll(void)
12.1.2.3 vTaskResume()恢复挂起任务
void	vTaskResume(TaskHandle_t xTaskToResume)

任务恢复函数会让挂起的任务重新进入就绪状态,恢复的任务会保留挂起前的状态信息,在恢复时根据挂起时的状态继续运行。如果被恢复任务在所有就绪态任务中处于最高优先级列表的第一位,那么系统将进行任务上下文的切换

12.1.2.4 xTaskResumeFromISR() 中断中恢复挂起任务
#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )

	BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )

该函数专门用在中断服务程序中,无论调用过多少次vTaskSuspend函数而挂起的任务,只需要调用一次xTaskResumeFromISR函数即可解挂。

注意事项:

  1. 要想使用该函数必须在FreeRTOSConfig.h中把INCLUDE_xTaskResumeFromISR和INCLUDE_vTaskSuspend都定义成1
12.1.2.5 xTaskReSumeAll( ) 恢复所有挂起任务
BaseType_t	xTaskResumeAll(void)

调用多少次vTaskSuspendAll函数就必须调用相同次数的xTaskResumeAll函数来解挂

12.1.2.6 vTaskDelete() 删除任务
#if ( INCLUDE_vTaskDelete == 1 )

	void vTaskDelete( TaskHandle_t xTaskToDelete )

注意事项:

  1. 当一个任务删除另一个任务时,形参为任务句柄。如果是删除自身,形参为NULL。
  2. 要想使用该函数,必须在FreeRTOSConfig.h中将INCLUDE_vTaskDelete定义为1
12.1.3 任务延时函数
12.1.3.1 vTaskDelay() 阻塞延时
#if ( INCLUDE_vTaskDelay == 1 )


	void vTaskDelay( const TickType_t xTicksToDelay )

注意事项:

  1. 该函数用于阻塞延时,调用该函数后,任务进入阻塞状态,将让出CPU资源
  2. 要想使用该函数,必须在FreeRTOSConfig.h中把INCLUDE_vTaskDelay定义为1
  3. vTaskDelay延时是相对性的延时,他指定的延时时间是从调用vTaskDelay()结束后开始计算的,经过指定的时间后延时结束。
  4. 其他任务和中断活动会影响到vTaskDelay上的调用(比如调用前高优先级任务抢占了当前任务),进而会影响到任务的下一次执行的时间。
12.1.3.2 vTaskDelayUntil() 绝对延时
#if ( INCLUDE_vTaskDelayUntil == 1 )

	void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )

注意事项:

  1. 要想使用该函数,必须在FreeRTOSConfig.h中把INCLUDE_vTaskDelayUntil定义为1
  2. vTaskDelayUntil函数是绝对延时,绝对延时常用于比较精确的周期运行任务,比如希望某个任务以固定频率定期执行,而不受外部的影响,任务从上一次开始都下一次开始的时间间隔是绝对的而不是相对的。
  3. 任务执行的时间必须小于任务周期时间,不能存在任务周期为10ms的任务,因为其主体代码执行时间为20ms,这样根本执行不完任务主体代码。
  4. 即使任务在执行过程中发生中断,也不会影响这个任务的运行周期,仅仅是缩短了阻塞的时间而已,到了要唤醒的时间,依旧会将任务唤醒

12.2 FreeRTOS启动流程

FreeRTOS有两种启动的流程:

12.2.1 “万事俱备只欠东风”法

在main函数中将硬件、RTOS系统初始化,所有任务创建完毕,此之谓“万事俱备”。“东风”即为启动RTOS的调度器,开始多任务调度

12.2.2 “小心翼翼十分谨慎”法

在main函数中将硬件和RTOS系统先初始化好,然后创建一个启动任务后就启动调度器。在启动任务中创建各种应用任务,当所有任务都创建好了之后,启动任务将自己删除。

12.3 任务启动与调度总结

如果我们要使用FreeRTOS的时候我们要怎么样开启任务? 我们以“万事俱备只欠东风”法来举例

12.3.1 静态创建
  1. 看看configSUPPORT_STATIC_ALLOCATION是否开启(置为1),如果没有,将其置为1

  2. 准备好一个TaskHandle_t类型变量来承接我们静态创建任务所返回的任务句柄

    static TaskHandle_t Task1_Handle = NULL;
    
  3. 定义任务栈

    static StackType_t	Task1_Stack[128];
    
  4. 定义任务控制块

    static StaticTask_t	Task1_TCB = NULL;
    
  5. 调用xTaskCreateStatic函数 静态创建任务

    Task1_Handle = xTaskCreateStatic(	(TaskFunction_t) Task1,						
    									(const char *) "Task1",					
    									(uint32_t) 128,				
    									(void *) NULL,					
    									(UBaseType_t) 3,						
    									(StackType_t *)  Task1_Stack,			
    									(StaticTask_t *) &Task1_TCB );	
    
  6. 调用vTaskStartScheduler()函数启动调度

    if(Task1_Handle!=NULL)
    {
    	vTaskStartScheduler();
    }
    
12.3.2 动态创建
  1. 查看宏定义 configSUPPORT_DYNAMIC_ALLOCATION 将其开启(置为1)

  2. 准备一个BaseType_t类型变量来承接动态创建函数的返回值,不创建也行,只是创建了以后可以更方便地知道是否创建成功

    static BaseType_t	xReturn;
    
  3. 准备任务句柄变量,这个经过动态创建函数后会指向我们要创建的任务

    static TaskHandle_t Task1_Handle = NULL;
    
  4. 调用xTaskCreateStatic()函数动态创建任务

    xReturn = xTaskCreate(		(TaskFunction_t) Task1,						
    							(const char *) "Task1",						
    							(uint16_t) 512,					
    							(void *) NULL,						
    							(UBaseType_t) 3,							
    							(TaskHandle_t *)  Task1_Handle )			
    
  5. 调用vTaskStartScheduler()启动调度

    if(xReturn == pdPASS)
    {
    	vTaskStartScheduler();
    }
    

12.4 任务延时

12.4.1 延时示例

绝对延时函数vTaskDelayUntil示例

void Task1(void * pvParameters)
{
	/* 用于保存上次时间,调用后系统自动更新 */
	static portTickType PreviousWakeTime;
	
	/* 设置延时时间,将时间转为节拍数 */(也可以不用这么麻烦)
	const portTickType TimeIncrement = pdMS_TO_TICKS(1000);
	
	/* 获取当前系统时间 */
	PreviousWakeTime = xTaskGetTickCount();
	while(1)
	{
		/* 调用绝对延时函数,任务时间间隔为1000个tick */
		vTaskDelayUntil(&PreviousWakeTime,TimeIncrement);
		//...
		//任务主体代码
	}
}
12.4.2 延时注意事项

任务执行的时间一般指两个方面,一是任务从开始到结束的时间,二是任务的周期。

在设计系统时对这两个时间我们都需要考虑,例如对于事件A对应的服务任务Ta,系统要切的实时响应指标是10ms,而Ta的最大运行时间是1ms,那么10ms就是任务Ta的周期,1ms则是任务的运行时间。简单来说,任务Ta在10ms内完成对事件A的响应即可。此时系统中还存在以50ms为周期的另一个任务Tb,他每次运行的最大时间长度是100us。在这种情况下,即使把任务Tb的优先级设置的比Ta还要高,对系统的实时性指标也没什么影响,因为即使在Ta的运行过程中,Tb抢占了Ta的资源,等到Tb执行完毕,消耗的时间也不过是100us,还是在事件A规定的响应时间内,Ta能够安全地完成对事件A 的相应。但是如果系统中还存在任务Tc,其运行时间为20ms,加入Tc的优先级比Ta高,那么在Ta运行时突然间被Tc打断,等到Tc执行完毕,Ta已经错过了对事件A的相应了,这是不允许的。

因此,在设计时必须要考虑任务的时间,一般来说处理时间更短的任务,其优先级应设置得更高一些。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值