一、FreeRTOS任务基础知识

一、前言
RTOS系统的核心就是任务管理,而学习RTOS系统的工程师最重要的目的就是为了使用RTOS的多任务处理功能。

二、初级要求
初步上手RTOS系统首先必须掌握的是任务的创建、删除、挂起和恢复等操作。

三、什么是多任务系统
在裸机系统中,程序都是在main函数里面用while(1)做一个大循环来完成所有的处理,即应用程序是一个无限的循环,循环中调用相应的函数完成所需的处理。当然有时候也需要中断来完成一些处理,像这样的就是单任务系统,也被称为前后台系统。中断服务函数作为前台程序,大循环while(1)作为后台程序。
优点是简单,资源消耗少!
缺点是实时性差,在大的嵌入式应用中明显力不从心!

多任务系统就是“分而治之”,把大问题划分成很多个小问题,逐步地把小问题解决掉。
这些小问题可以单独地作为一个小任务来处理。
需要注意的是这些小问题是并发处理的,而并发是指每个任务执行的时间很短,看起来就像是同一时刻执行了很多个任务一样。
任务调度器决定哪一个任务先运行。
总结一句话:FreeRTOS是一个抢占式的实时多任务系统,任务调度器也是抢占式的。
抢占式的实时多任务系统基本原理:高优先级的任务执行完成以后重新把CPU的使用权归还给低优先级的任务。比如自动驾驶中的障碍物检测任务。

四、FreeRTOS任务与协程
在FreeRTOS中应用可以使用任务和协程,或者两者混合使用,协程是为那些资源很少的MCU准备的,其开销很小,但FreeRTOS官方已经不打算更新协程了。

五、初次使用
任务(Task)的特性:
①、每个任务都是独立的,都有属于自己的运行环境!
②、任何一个时间点只能有一个任务运行。
③、具体运行哪一个任务由RTOS调度器来决定。RTOS调度器的职责及时确保一个任务开始执行的时候都有其上下文环境(寄存器值,堆栈内容等)和任务上一次退出的时候相同(前后两次一样),任务能够正常恢复运行!
④、总结起来就是:简单、没有使用限制、支持抢占、支持优先级等。

六、任务状态:
**运行态:**当前正在执行的任务,单核处理器在任何时刻都只有一个任务处于运行态。
**就绪态:**已经准备就绪的任务(这些任务没有被阻塞或者挂起),处于就绪态的任务还没有运行,因为有一个同优先级或者更高优先级的任务正在运行!
**阻塞态:**当前正在等待某个外部事件的任务,比如调用了vTaskDelay()的任务就处于阻塞态,直到延时周期完成。任务在等待队列、信号量、事件组、通知或互斥信号量的时候也会进入阻塞态。任务在进入阻塞态会有一个超时时间,当超过这个超时时间就会退出阻塞态,即使说等待的事件还没有来临!
**挂起态:**任务进入挂起态以后不能被调度器调用进入运行态,但是挂起态没有超时时间。
任务进入和退出挂起态通过调用vTaskSuspend()和xTaskResume()。

运行态通过vTaskSuspend()进入挂起态
挂起态通过xTaskResume()进入就绪态
就绪态通过vTaskSuspend()进入挂起态

阻塞态通过vTaskSuspend()进入挂起态

七、任务优先级
①、configMAX_PRIORITIES在FreeRTOSConfig.h中定义,优先级的范围为0~(configMAX_PRIORITIES - 1)。
②、优先级数字越低表示任务的优先级越低,0的优先级最低,configMAX_PRIORITIES - 1最高,空闲任务的优先级最低,为0。
③、FreeRTOS调度器保证就绪态或运行态的高优先级的任务获取处理器使用权。

八、任务实现
**①、**xTaskCreate()和xTaskCreateStatic()创建任务,第一个参数pxTaskCode就是这个任务的任务函数,而任务函数是指完成本任务的工作的函数。
②、任务创建模板:
void vATaskFunction(void *pvParameters)
{
for( ; ; )
{
任务应用程序
vTaskDelay();
}
/不能从人物函数中返回或者退出,从任务函数中返回或退出的话就会调用configASSERT(),前提是你定义了configASSERT()。如果一定要从任务函数中退出的话一定要调用vTaskDelete(NULL)来删除此任务。/
vTaskDelete(NULL);
}

**③、**任务函数也是函数,无返回值,即void,任务参数为void指针类型的。
**④、**不一定非要用延时函数,其他的能够发生任务切换的API含糊都可以。
**⑤、**任务函数一般不允许跳出循环,如果一定要从任务函数中退出的话一定要调用vTaskDelete(NULL)来删除此任务。

九、任务控制块
FreeRTOS每个任务都有一些属性要存储,这些属性集合在一起就是一个任务控制块结构体。在使用xTaskCreate()创建任务时就会自动给每个任务分配一个任务控制块。叫做TCB_t。在task.c中定义。
typedef struct tskTaskControlBlock
{
volatile StackType_t *pxTopOfStack; //任务堆栈栈顶

#if ( portUSING_MPU_WRAPPERS == 1 )
	xMPU_SETTINGS	xMPUSettings;		//MPU相关设置
#endif

ListItem_t			xStateListItem;	//状态列表项
ListItem_t			xEventListItem;		//事件列表项
UBaseType_t			uxPriority;			//任务优先级
StackType_t			*pxStack;			//任务堆栈起始地址
char				pcTaskName[ configMAX_TASK_NAME_LEN ];//任务名字

#if ( portSTACK_GROWTH > 0 )
	StackType_t		*pxEndOfStack;		/*< Points to the end of the stack on architectures where the stack grows up from low memory. */
#endif

#if ( portCRITICAL_NESTING_IN_TCB == 1 )
	UBaseType_t		uxCriticalNesting;	/*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
#endif

#if ( configUSE_TRACE_FACILITY == 1 )
	UBaseType_t		uxTCBNumber;		/*< Stores a number that increments each time a TCB is created.  It allows debuggers to determine when a task has been deleted and then recreated. */
	UBaseType_t		uxTaskNumber;		/*< Stores a number specifically for use by third party trace code. */
#endif

#if ( configUSE_MUTEXES == 1 )
	UBaseType_t		uxBasePriority;		/*< The priority last assigned to the task - used by the priority inheritance mechanism. */
	UBaseType_t		uxMutexesHeld;
#endif

#if ( configUSE_APPLICATION_TASK_TAG == 1 )
	TaskHookFunction_t pxTaskTag;
#endif

#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
	void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
#endif

#if( configGENERATE_RUN_TIME_STATS == 1 )
	uint32_t		ulRunTimeCounter;	/*< Stores the amount of time the task has spent in the Running state. */
#endif

#if ( configUSE_NEWLIB_REENTRANT == 1 )
	/* Allocate a Newlib reent structure that is specific to this task.
	Note Newlib support has been included by popular demand, but is not
	used by the FreeRTOS maintainers themselves.  FreeRTOS is not
	responsible for resulting newlib operation.  User must be familiar with
	newlib and must provide system-wide implementations of the necessary
	stubs. Be warned that (at the time of writing) the current newlib design
	implements a system-wide malloc() that must be provided with locks. */
	struct	_reent xNewLib_reent;
#endif

#if( configUSE_TASK_NOTIFICATIONS == 1 )
	volatile uint32_t ulNotifiedValue;
	volatile uint8_t ucNotifyState;
#endif

/* See the comments above the definition of
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
	uint8_t	ucStaticallyAllocated; 		/*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
#endif

#if( INCLUDE_xTaskAbortDelay == 1 )
	uint8_t ucDelayAborted;
#endif

} tskTCB;
typedef tskTCB TCB_t;

十、任务堆栈
FreeRTOS之所以能正确运行就是因为有任务堆栈,任务调度器会将任务切换时的当前任务现场(如CPU寄存器值等)保存在任务堆栈中,等下次恢复运行时用它来恢复现场。
用xTaskCreate()创建任务(动态方法),任务堆栈由xTaskCreate()自动创建。
用xTaskCreateStatic()创建任务(静态方法),任务堆栈由程序员自行定义。
堆栈大小数据类型为StackType_t,本质上是uint32_t,在portmacro.h中定义。
StackType_t类型的变量为4个字节,实际堆栈大小是定义的4倍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值