FreeRTOS学习-创建任务

  在上一篇文章中我们进行了FreeRTOS的移植,创建好了FreeRTOS工程模板,这一篇文章,我们讲解FreeRTOS的创建任务。创建任务的时候,分静态内存创建任务和动态内存创建任务。上一篇文章中,我们使用的是动态任务创建,来验证FreeRTOS的移植是否正确。

1.SRAM静态内存创建任务

使用静态内存创建任务的时候,任务使用的栈和任务控制块都使用静态内存,即预先定义好全局变量,这些预先定义好的全局变量都存放在内部的SRAM中。在静态内存任务创建,需要将FreeRTOS.h中的configSUPPORT_STATIC_ALLOCATION设置为1.

#ifndef configSUPPORT_STATIC_ALLOCATION
    /* Defaults to 0 for backward compatibility. */
    #define configSUPPORT_STATIC_ALLOCATION    1
#endif

1.1 静态创建任务函数xTaskCreateStatic

#include “FreeRTOS.h”
#include “task.h”
TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode,
								const char * const pcName,
								uint32_t ulStackDepth,
								void *pvParameters,
								UBaseType_t uxPriority,
								StackType_t * const puxStackBuffer,
								StaticTask_t * const pxTaskBuffer );
参数名/返回值描述
pvTaskCode任务只是一个永远不会退出的C函数,因此通常是一个循环函数。pvTaskCode只是一个的指向实现任务的函数的指针(实际上就是函数名)
pcName任务的描述性名称,在FreeRTOS中没有使用,仅仅只是用在调试目的。识别一个任务通过一个任务名称比尝试用任务句柄来识别任务简单
usStackDepth每个任务都有自己唯一的堆栈,由内核分配给创建任务时的任务。usStackDepth值告诉内核堆栈的大小。
pvParameters任务函数接收一个指向void *类型指针的参数,分配给pvParameters的值是传递给任务的值
uxPriority定义了任务将要执行的优先级,优先级可以被设置为0到configMAX_PRIORITIES – 1,其中0 是最低优先级
puxStackBuffer必须指向一个数组的StackType_t变量,至少有ulStackDepth索引,参见上面的ulStackDepth参数
pxTaskBuffer必须指向StaticTask_t类型的变量。该变量将用于保存已创建任务的数据结构(TCB)
Returned valueNULL表示任务没有被创建因为puxStackBuffer或者pxTaskBuffer是NULL,如果没有返回空值,表明任务被创建和返回的值是创建任务的句柄值

例如:

  /* 创建LED_Task任务 */
LED_Task_Handle = xTaskCreateStatic(        (TaskFunction_t	)LED_Task,		//任务函数
											(const char* 	)"LED_Task",		//任务名称
											(uint32_t 		)128,					//任务堆栈大小
											(void* 		  	)NULL,				//传递给任务函数的参数
											(UBaseType_t 	)4, 				//任务优先级
											(StackType_t*   )LED_Task_Stack,	//任务堆栈
											(StaticTask_t*  )&LED_Task_TCB);	//任务控制块 

1.2定义任务函数

void LED_Task()
{
    while(1)
    {
        LED1( ON );	
        vTaskDelay(1000);
        LED1( OFF );	
        vTaskDelay(1000);  
    }
}

1.3定义全局变量

  目前我们只创建了一个任务,当任务进行延时的时候,没有其他就绪的用户任务,系统会进入空闲任务。空闲任务是FreeRTOS系统自己启动的一个任务,优先级最低。整个系统没有就绪任务的时候,系统必须保证有一个任务运行,空闲任务就是为这个设计的。当用户任务延时到期,又会从空闲任务切换到用户任务。
  在FreeRTOS系统中,每一个任务都是独立的,运行时环境都单独保存在相应的栈空间。我们使用的时静态内存创建任务,定义任务的栈大小的时候,需要定义一个独立的全局变量。任务的栈占用的是MCU的RAM,当任务越多的时候,需要使用的栈空间越大,需要的RAM也就越多。

/* LED 任务堆栈 */
static StackType_t LED_Task_Stack[128];
/*LED任务控制块 */
static StaticTask_t LED_Task_TCB;		
 /* LED 任务句柄 */
static TaskHandle_t LED_Task_Handle;

1.4 启动任务调度

  当任务创建好后,是处于任务就绪(Ready) ,在就绪态的任务可以参与操作系统的调度。但是此时任务仅仅是创建了,还未开启任务调度器,也没创建空闲任务与定时器任务(如果使能了 configUSE_TIMERS 这个宏定义),那这两个任务就是在启动任务调度器中实现, 每个操作系统, 任务调度器只启动一次,之后就不会再次执行了, FreeRTOS 中启动任务调度器的函数vTaskStartScheduler(),并且启动任务调度器的时候就不会返回,从此任务管理都由FreeRTOS管理,此时才是真正进入实时操作系统中的第一步。

/* 启动任务,开启调度 */
 vTaskStartScheduler();

2.SRAM动态内存创建任务

  动态内存创建任务和静态内存创建任务相似,少了一些参数。区别在于使用动态内存创建任务的时候,其实使用的是堆内存,也属于SRAM。FreeRTOS在SRAM里面定义了一个大数组,也就是堆内存,供FreeRTOS的动态内存分配函数使用。在第一次使用的时候,与其他操作系统不同,FreeRTOS会自动对定义的堆内存进行初始化,内存初始化的方式在内存管理方案中实现(heap_1.c heap_2.c heap_3.c heap_4.c heap_5.c),一般使用是heap_4.c 。在动态内存任务创建,需要将FreeRTOS.h中的configSUPPORT_STATIC_ALLOCATION设置为1.

//系统所有总的堆大小
#define configTOTAL_HEAP_SIZE					((size_t)(36*1024))   
//支持动态内存申请
#define configSUPPORT_DYNAMIC_ALLOCATION        1 

2.1 动态创建任务函数xTaskCreate

#include “FreeRTOS.h”
#include “task.h”
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
						const char * const pcName,
						unsigned short usStackDepth,
						void *pvParameters,
						UBaseType_t uxPriority,
						TaskHandle_t *pxCreatedTask );
参数名/返回值描述
pvTaskCode任务只是一个永远不会退出的C函数,因此通常是一个循环函数。pvTaskCode只是一个的指向实现任务的函数的指针(实际上就是函数名)
pcName任务的描述性名称,在FreeRTOS中没有使用,仅仅只是用在调试目的。识别一个任务通过一个任务名称比尝试用任务句柄来识别任务简单
usStackDepth每个任务都有自己唯一的堆栈,由内核分配给创建任务时的任务。usStackDepth值告诉内核堆栈的大小。
pvParameters任务函数接收一个指向void *类型指针的参数,分配给pvParameters的值是传递给任务的值
uxPriority定义了任务将要执行的优先级,优先级可以被设置为0到configMAX_PRIORITIES – 1,其中0 是最低优先级
pxCreatedTaskpxCreatedTask 是用来在任务创建的时候分发一个句柄。这个句柄可以在在API调用的时候引用这个任务,举个例子,改变任务的优先级和删除任务。如果应用程序没有使用到这个任务句柄,pxCreatedTask 可以设置为NULL
Return Values返回值有两个。一个是pdPASS,表示任务已经创建成功;一个是errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY,表示任务不能被创建因为FreeRTOS无法给任务数据结构体和栈分配足够的内存

例如:

  /* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED_Task, /* 任务入口函数 */
                        (const char*    )"LED_Task",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )2,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LED_Task_Handle);/* 任务控制块指针 */

2.2 定义任务函数

void LED_Task()
{
    while(1)
    {
        LED1( ON );	
        vTaskDelay(1000);
        LED1( OFF );	
        vTaskDelay(1000);  
    }
}

2.3定义全局变量

和静态创建任务一样,这里需要定义一个任务句柄

 /* LED 任务句柄 */
static TaskHandle_t LED_Task_Handle;

2.4 启动任务调度

和静态创建任务一样,在创建任务后,需要开启任务调度。

/* 启动任务,开启调度 */
 vTaskStartScheduler();

3.举例创建多任务

  在编译的时候,会产生两个错误没有定义vApplicationGetIdleTaskMemory函数和没有定义vApplicationGetTimerTaskMemory函数,这是由于使用静态创建任务的时候,需要人为分配空闲任务和定时器任务的TCB大小、任务栈大小。这里直接在main.c文件中实现。
再次编译,无错误,两个任务来回切换,LED不停闪烁。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

例程代码:

#include "stm32f4xx.h"
#include "./led/bsp_led.h"
#include "FreeRTOS.h"
#include "task.h"

/* 空闲任务任务堆栈 */
static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE];
/* 定时器任务堆栈 */
static StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH];

/* 空闲任务控制块 */
static StaticTask_t Idle_Task_TCB;	
/* 定时器任务控制块 */
static StaticTask_t Timer_Task_TCB;

/* LED1 任务堆栈 */
static StackType_t LED1_Task_Stack[128];
/*LED1任务控制块 */
static StaticTask_t LED1_Task_TCB;		
 /* LED1 任务句柄 */
static TaskHandle_t LED1_Task_Handle;

 /* LED2 任务句柄 */
TaskHandle_t LED2_TaskHandle = NULL;

void LED1_Task()
{
    while(1)
    {
        LED1( ON );	
        vTaskDelay(1000);
        LED1( OFF );	
        vTaskDelay(1000);  
    }
}

void LED2_Task()
{
    while(1)
    {
        LED2( ON );	
        vTaskDelay(500);
        LED2( OFF );	
        vTaskDelay(500);  
    }
}

int main(void)
{
    BaseType_t xReturn = pdPASS;
	/* LED 端口初始化 */
	LED_GPIO_Config();
    
    //create led1 task
  /* 创建LED_Task任务 */
    LED1_Task_Handle = xTaskCreateStatic(        (TaskFunction_t	)LED1_Task,		
                                                (const char* 	)"LED1_Task",		
                                                (uint32_t 		)128,					
                                                (void* 		  	)NULL,				
                                                (UBaseType_t 	)4, 				
                                                (StackType_t*   )LED1_Task_Stack,	
                                                (StaticTask_t*  )&LED1_Task_TCB);	   
    //create led2 task
    xReturn = xTaskCreate(  LED2_Task,
                            "LED2_Task",
                            128,
                            NULL,
                            4,
                            &LED2_TaskHandle);
    

    vTaskStartScheduler();

}

void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
								   StackType_t **ppxIdleTaskStackBuffer, 
								   uint32_t *pulIdleTaskStackSize)
{
	*ppxIdleTaskTCBBuffer=&Idle_Task_TCB;/* 任务控制块内存 */
	*ppxIdleTaskStackBuffer=Idle_Task_Stack;/* 任务堆栈内存 */
	*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;/* 任务堆栈大小 */
}


void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, 
									StackType_t **ppxTimerTaskStackBuffer, 
									uint32_t *pulTimerTaskStackSize)
{
	*ppxTimerTaskTCBBuffer=&Timer_Task_TCB;/* 任务控制块内存 */
	*ppxTimerTaskStackBuffer=Timer_Task_Stack;/* 任务堆栈内存 */
	*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;/* 任务堆栈大小 */
}
  • 25
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值