FreeRTOS学习(二)

FreeRTOS的任务创建和删除

任务的创建和删除本质就是调用FreeRTOS的API函数。

  • xTaskCreate():动态方式创建任务
  • xTaskCreateStatic():静态方式创建
  • vTaskDelete():删除任务

动态创建任务:任务的控制块以及任务的栈空间所需的内存,均由FreeRTOS从FreeRTOS管理的堆中分配。——由FreeRTOS自动实现分配内存。

静态创建任务:任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供。

动态创建任务函数

BaseType_t xTaskCreate
(
	TaskFunction_t pxTaskCode,//执行任务函数的指针
	const char* const pcName;//任务名字,最大长度configMAX_TASK_NAME_LEN,默认16
	const configsSTACK_DEPTH_TYPE usStackDepth;//任务堆栈大小,注意字为单位
	void *const pvParameter; //传递给任务函数的参数
	UBaseType_t uxPriority;//任务优先级,范围:0~configMAX_PRIORITIES-1
	TaskHandle_t *const pxCreatedTask; //任务句柄,就是任务的控制块
)

//返回值:pdPASS-任务创建成功
//errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:任务创建失败

实现动态创建任务流程

  1. 将宏configSUPPORT_DYNAMIC_ALLOCATION配置为1
  2. 定义函数入口参数
  3. 编写任务函数

使用动态创建函数xTaskCreate()创建的任务会立刻进入就绪态,由任务调度器调度运行。

动态创建任务函数内部实现

  1. 申请堆栈内存&任务控制块内存
  2. TCB结构体成员赋值
  3. 添加新任务到就绪列表

任务控制块结构体成员介绍

typedef struct tskTaskControlBlock
{
	volatile StackType_t *pxTopOfStack; //任务栈栈顶,必须为TCB的第一个成员,与任务切换,任务上下文保存以及任务恢复有关
	ListItem_t xStateListItem; //任务状态列表项
	ListItem_t xEventListItem; //任务事件列表项
	UBaseType_t uxPriority; //任务优先级,数值越大,优先级越大
	StackType_t *pxStack; //任务栈起始地址
	char pxTaskName[configMAX_TASK_NAME_LEN];//任务名字
}tskTCB;

任务栈栈顶,在任务切换时的任务上下文保存、任务恢复息息相关
每个任务都有属于自己的任务控制块

静态创建任务函数

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;//任务控制块指针,用户分配
)
//返回值NULL:用户没有提供相应的内存,任务创建失败
//其他值:任务句柄,任务创建成功

静态创建任务使用流程

  1. 需要将宏configSUPPORT_STATIC_ALLOCATION配置为1
  2. 定义空闲任务&定时器任务的任务堆栈及TCB
  3. 实现两个接口函数:vApplicationGetDleTaskMemory()、vApplicationGetTimerTaskMemory()
  4. 定义函数入口参数
  5. 编写任务函数

静态创建内部实现

  1. TCB结构体成员赋值
  2. 添加新任务到就绪列表

任务删除函数

void vTaskDelete(TaskHandle_t xTaskToDelete)

xTaskToDelete待删除任务的句柄
被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除。

当传入的参数为NULL,则表示删除任务自身(当前正在运行的任务)

空闲任务会负责释放被删除任务中由系统分配的内存(只针对动态创建的任务,vTaskDelete(NULL))
由用户在任务删除前申请的内存,需要由用户在任务被删除前提前释放,否则将导致内存泄露。

删除任务流程

  1. 使用删除任务函数,需要将宏INCLUDE_vTaskDelete配置为1
  2. 入口参数输入需要删除的任务句柄(NULL代表删除本身)

内部实现过程

  1. 获取所要删除的任务的控制块:通过传入的任务句柄,判断所需要删除哪个任务,NULL代表删除自身
  2. 将被删除任务,移除所在列表:包括就绪、阻塞、挂起、事件等列表。
  3. 判断所需要删除的任务:1.删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务中执行。2.删除其他任务,直接释放内存,任务数量–
  4. 更新下个任务的阻塞时间:以防被删除的任务就是下一个阻塞超时的任务。

FreeRTOS学习(二)_第1张图片
#define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持动态内存申请

#define START_TASK_PRIO 1
#define START_STK_SIZE 128 //定义任务堆栈大小
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameter);

#define LED0_TASK_PRIO 2
#define LED0_STK_SIZE 50 //定义任务堆栈大小
TaskHandle_t LED0Task_Handler;
void led0_task(void *pvParameter);

#define LED1_TASK_PRIO 2
#define LED1_STK_SIZE 50 //定义任务堆栈大小
TaskHandle_t LED1Task_Handler;
void led1_task(void *pvParameter);

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组为4
	delay_init();
	uart_init(115200);
	LED_Init();

	//创建开始任务
	xTaskCreate((TaskFunction_t)start_task,
				(const char*)"start_task",
				(uint16_t)START_STK_SIZE,
				(void*)NULL,
				(UBaseType_t)START_TASK_PRIO,//
				(TaskHandler_t *)&StartTask_Handler);
	vTaskStartScheduler();
}

void start_task(void *pvParameter)
{
	taskENTER_CRITICAL();//进入临界区,关闭中断,避免被中断,切换任务
	//创建LED0任务
	xTaskCreate((TaskFunction_t)led0_task,
				(const char*)"led0_task",
				(uint16_t)LED0_STK_SIZE,
				(void*)NULL,
				(UBaseType_t)LED0_TASK_PRIO,//
				(TaskHandler_t *)&LED0Task_Handler);
	//创建LED1任务
	xTaskCreate((TaskFunction_t)led1_task,
				(const char*)"led1_task",
				(uint16_t)LED1_STK_SIZE,
				(void *)NULL,
				(UBaseType_t)LED1_TASK_PRIO,
				(TaskHandle_t*)&LED1Task_Handler);
	vTaskDelete(StartTask_Handler);
	taskEXTI_CRITICAL();
}

void led0_task(void *pvParameter)
{
	while(1)
	{
		LED0=~LED0;
		vTaskDelay(500);
	}
}

void led1_task(void *pvParameter)
{
	while(1)
	{
		LED1=0;
		vTaskDelay(500);
		LED1=1;
		vTaskDelay(500);
	}
}

void task3(void *pvParameters)
{
	uint8_t key = 0;
	while(1)
	{
		printf("task3正在运行");
		key = key_scan(0);
		if(key == KEY0_PRES)
		{
			if(task1_handler != NULL)
			{
				printf("删除task1\r\n");
				vTaskDelete(task1_handler);
				task1_handler = NULL;
			}
			vTaskDelay(10);
		}
	}
}

在32位的计算机中,一个字等于四字节。

INCLUDE_uxTaskGetStackHighWaterMark:获取任务堆栈历史剩余最小值,如果大很多,我们可以将任务改小。

portSTACK_GROWTH:栈的生长方向,STM32是高地址向低地址生长的,也就是向下生长的。堆是从低地址向高地址生长(向上生长)

动态创建任务其内部实现

  1. 申请堆栈内存(返回首地址)pxStack=pvPortMallocStack(((size_t)usStackDepth)*sizeof(StackType_t));
  2. 申请任务控制块内存pxNewTCB=(TCB_t *)pvPortMalloc(sizeof(TCB_t));
  3. 把前面申请的堆栈地址,赋值给控制块的堆栈成员pxNewTCB->pxStack=pxStack;
  4. 调用prvInitialiseNewTask,初始化任务控制块中的成员
  5. 调用prvAddNewTaskToReadyList 添加新创建任务到就绪列表中.

#define tskSTACK_FILL_BYTE ( 0xa5U )
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
把分配的堆栈内存全部赋值为a5,当值不是a5时,就表示被用了。

pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
获取栈顶地址

if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
{
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
}
任务优先级最大,赋值为31

#if ( configUSE_MUTEXES == 1 )
{
pxNewTCB->uxBasePriority = uxPriority;
pxNewTCB->uxMutexesHeld = 0;
}
互斥量有优先级继承问题,所以先将基优先级保存下来。

vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
初始化列表项

你可能感兴趣的:(FreeRTOS,学习,c++,开发语言,FreeRTOS)