跟着野火从零开始手搓FreeRTOS(3.1)任务的了解与创建

本文详细介绍了在FreeRTOS中如何创建任务,包括任务栈的定义、任务控制块的作用,以及静态和动态任务创建的区别。重点讲解了任务栈的管理,如栈顶指针的计算和异常处理中的栈内容加载。

什么是任务

任务,可以说是FreeRTOS的重中之重,是实现操作系统的根本。

        这里套用野火的例子:创建两个任务TASK1和TASK2,任务的内容都是让一个变量按一定的频率不断翻转,并让单片机将两个任务不断切换。

        这个例子用裸机系统写的话,只用简单的delay延时加翻转标志位就能实现。在实现过程中,CPU是在按顺序执行每个任务,也就是轮询。如果我们使用软件仿真可以看到,两个任务是交替进行的。

        而当我们采用多任务系统的方式去完成这个例子,仿真的效果是两个任务同时进行,就像两件事情在同时被处理。

        为什么会有这样的差别呢?通过对任务的掌握,我们就能理解了。

        任务,就是在多任务系统中,所有功能都分割成独立的且无法返回的函数。

        在裸机系统中,比如全局变量,子函数,函数返回地址等环境参数,他们统统放在一个叫栈的地方(一般称为主栈)。栈是单片机 RAM 里面一段连续的内存空间,栈的大小一般在启动文件或者链接脚本里面指定,最后由 C 库函数_main 进行初始化。

        简单来说,就是我们不需要管它存放在哪,只需要知道它大概是干什么的,给它分配空间就行。

         对于操作系统来说,每个任务都是独立的,有多少个任务就需要定义多少个任务栈。因此要为每个任务分配独立的栈空间,通常是一个全局数组或者是动态分配的内存空间,存在于RAM中。

创建任务

定义任务栈

      我们要实现两个变量按照一定的频率轮流的翻转,每个变量对应一个任务,所以需要定义两个任务栈。

        任务栈其实就是一个预先定义好的全局数据,我们可以直接在main.c中定义,也可以放在FreeROS.h中。我这里是放在了main.c中。

#include "FreeRTOS.h"
#include "task.h"

#define TASK1_STACK_SIZE                    128
StackType_t Task1Stack[TASK1_STACK_SIZE];

#define TASK2_STACK_SIZE                    128
StackType_t Task2Stack[TASK2_STACK_SIZE];

        任务栈(TaskxStack)数据类型为StackType_t,大小由 TASK1_STACK_SIZE 这个宏来定义,默认为 128,单位为字,即 512字节,这也是 FreeRTOS 推荐的最小的任务栈。

        前面提到过,在 FreeRTOS 中,凡是涉及到数据类型的地方,FreeRTOS 都会将这些数据类型用 typedef 重新取一个类型名,目的是为了适配不同位的单片机。这些经过重定义的数据类型都放在 portmacro.h里,之后有重定义的地方将默认都在这个头文件里面定义。

 创建任务和延时

       接下来定义两个任务,在多任务系统中,每个任务都是一个独立的、无限循环的且无法返回跳出的函数,在main.c的主函数中定义他们。先准备一个简单的延时函数,然后完成两个任务的创建。

/* main.c中函数声明 */
void delay (uint32_t count);
void Task1_Entry( void *p_arg );
void Task2_Entry( void *p_arg );


/* 软件延时 */
void delay (uint32_t count)
{
	for(; count!=0; count--);
}

/* 任务1 */
void Task1_Entry( void *p_arg )
{
	for( ;; )
	{
		flag1 = 1;
		delay( 100 );		
		flag1 = 0;
		delay( 100 );
	}
}

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

任务控制块

       在裸机系统中,程序的主体是由 CPU 按照顺序执行的。而在多任务系统中,任务的执行是由系统调度的。系统为了顺利的调度任务,为每个任务都额外定义了一个任务控制块,这个任务控制块存有任务的所有信息,比如任务的栈指针,名称,形参等。系统对任务的全部操作都可以通过任务控制块来实现。
        定义任务控制块的结构体,使用它可以为每个任务都定义一个任务控制块实体。在task.h中定义。

typedef struct tskTaskControlBlock
{
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pQAQqa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值