FreeRTOS复习笔记(二) —— 任务

FreeRTOS复习笔记(二) —— 任务

一、创建任务

1.本例程思路:

1). 调用 xTaskCreateStatic 函数静态创建任务 LED_Task;
LED_Task 控制 LED 每间隔一段时间翻转一次
2). 调用 xTaskCreate 函数动态创建任务 AppTaskCreate_Task;
AppTaskCreate_Task 动态创建任务 LED_Task 与 LED2_Task;
LED_Task 与 LED2_Task 分别控制 LED 与 LED2 每隔一段时间翻转一次

本篇将静态创建与动态创建写入同一段代码,使用 _USE_STATIC_MODE 与 _USE_DYNAMIC_MODE 进行区分

其中,
动态创建方式,初始化相关资源(中断, GPIO等)后,直接调用任务创建函数 xTaskCreate 创建任务,随后开启任务调度器即可(任务函数执行的内容自行实现);
而静态创建方式,需要手动开辟存储空间(任务堆栈, 任务控制块,包括IdleTask与TimerTask),随后可以直接调用 xTaskCreateStatic 函数创建任务,调用 vTaskStartScheduler 函数开启任务调度器

启动任务调度器后,任务调度器会自动创建一个IdleTask任务,以保证始终能有一个任务在运行,所以使用静态方式创建任务时需要手动为IdleTask分配空间(实现 vApplicationGetIdleTaskMemory 函数)

2.代码编写

/**
  ******************************************************************************
  * @文件名: xxx.c
  * @作  者: author
  * @版  本: v1.0.0
  * @日  期: 2021.12.21
  * @简  介: 无
  * @注  意: 无
  ******************************************************************************
  */
#include "stm32f10x.h"

#include "dr_usart.h"
#include "dr_led.h"

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

/**
  * #define _USE_STATIC_MODE  //使用[静态]方式创建任务
  * #define _USE_DYNAMIC_MODE //使用[动态]方式创建任务
  */

#if defined(_USE_STATIC_MODE)
	#define USER_DEFAULT_STACK_SIZE  ((unsigned short)128) //任务堆栈大小
	
	/* IdleTask 任务堆栈 任务控制块 */
	StackType_t  Idle_Task_Stack[USER_DEFAULT_STACK_SIZE];                  //
	StaticTask_t Idle_Task_TCB;                                             //
	
	/* TimerTask */
	StackType_t  Timer_Task_Stack[USER_DEFAULT_STACK_SIZE];                 //
	StaticTask_t Timer_Task_TCB;                                            //
	
	/* LED_Task 任务堆栈 任务控制块 任务句柄 任务函数 */
	StackType_t  LED_Task_Stack[USER_DEFAULT_STACK_SIZE];                   //
	StaticTask_t LED_Task_TCB;                                              //
	TaskHandle_t LED_Task_Handle;
	void LED_Task(void *);
#endif

#if defined(_USE_DYNAMIC_MODE)
	/* 任务函数 */
	void AppTaskCreate_Task(void *);
	void LED_Task(void *);
	void LED2_Task(void *);
#endif

/**
  * @简  介: 无
  * @参  数: 无
  * @返回值: 无
  */
int main(void)
{
	/* --------- --------- --------- --------- --------- --------- ---------  */
	
	/* 中断分组4 */
	NVIC_Priority_Group_Config();                                        /* * */
	
	/* 串口1配置 */
	USART1_Config();                                                     /* * */
	
	/* LED(PA8, PA6)配置 */
	LED_GPIO_Config();                                                   /* * */
	
	/* --------- --------- --------- --------- --------- --------- ---------  */

	/* 创建LED_Task */
#if defined(_USE_STATIC_MODE)
	LED_Task_Handle = xTaskCreateStatic( LED_Task,        //指向任务函数
										 "LED_Task",      //任务名称
										 USER_DEFAULT_STACK_SIZE, //任务堆栈大小
										 (void *)NULL, 1, //任务参数, 任务优先级
										 LED_Task_Stack,  //任务堆栈地址
										 &LED_Task_TCB ); //任务控制块地址
#endif

	/* 创建AppTaskCreate_Task */
#if defined(_USE_DYNAMIC_MODE)
	/* 任务函数 任务名称 堆栈大小 任务参数(无) 任务优先级 任务句柄(未用到) */
	xTaskCreate(AppTaskCreate_Task, "AppTaskCreate_Task", 128, NULL, 1, NULL);
#endif

	/* 开启任务调度 */
	vTaskStartScheduler();
	
	while(1);
}

#if defined(_USE_DYNAMIC_MODE)

/**
  * @简  介: 无
  * @参  数: 无
  * @返回值: 无
  */
void AppTaskCreate_Task(void *pvParameters)
{
	/* 进入临界 */
	taskENTER_CRITICAL();
	
	/* 创建LED_Task */
	xTaskCreate(LED_Task, "LED_Task", 128, NULL, 2, NULL);
	
	/* 创建LED2_Task */
	xTaskCreate(LED2_Task, "LED2_Task", 128, NULL, 3, NULL);
	
	/* 删除AppTaskCreate_Task */
	vTaskDelete(NULL);
	
	/* 退出临界 */
	taskEXIT_CRITICAL();
}

#endif

/**
  * @简  介: 无
  * @参  数: 无
  * @返回值: 无
  */
void LED_Task(void *pvParameters)
{
	for(;;)
	{
		/* 翻转LED */
		GPIOA->ODR ^= ((uint16_t)0x0100);
		
		/* 任务切换 */
		vTaskDelay(50);
	}
}

#if defined(_USE_DYNAMIC_MODE)

/**
  * @简  介: 无
  * @参  数: 无
  * @返回值: 无
  */
void LED2_Task(void *pvParameters)
{
	for(;;)
	{
		/* 翻转LED2 */
		GPIOA->ODR ^= ((uint16_t)0x0040);
		
		/* 任务切换 */
		vTaskDelay(50);
	}
}

#endif

#if defined(_USE_STATIC_MODE)

/**
  * @简  介: 分配IdleTask空间
  * @参  数: TCB Stack StackSize
  * @返回值: 无
  */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
									StackType_t **ppxIdleTaskStackBuffer,
									uint32_t *pulIdleTaskStackSize )
{
	*ppxIdleTaskTCBBuffer = &Idle_Task_TCB;          //指向任务控制块
	*ppxIdleTaskStackBuffer = Idle_Task_Stack;       //指向任务堆栈
	*pulIdleTaskStackSize = USER_DEFAULT_STACK_SIZE; //任务堆栈大小
}

/**
  * @简  介: 分配TimerTask空间
  * @参  数: TCB Stack StackSize
  * @返回值: 无
  */
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
									 StackType_t **ppxTimerTaskStackBuffer,
									 uint32_t *pulTimerTaskStackSize )
{
	*ppxTimerTaskTCBBuffer = &Timer_Task_TCB;
	*ppxTimerTaskStackBuffer = Timer_Task_Stack;
	*pulTimerTaskStackSize = USER_DEFAULT_STACK_SIZE;
}

#endif

3.调用逻辑分析仪观察(动态时,两个LED应同时翻转)

静态创建(任务:LED_Task)

FreeRTOS复习笔记(二) —— 任务
动态创建(任务:LED_Task,LED2_Task)
FreeRTOS复习笔记(二) —— 任务
经验证,程序运行结果与预想一致

二、任务挂起与恢复

1.本例程思路:

分别创建两个任务,LEDTask 与 KEYTask,LEDTask 控制 LED 每隔一段时间翻转一次,KEYTask 检测 KEY_GPIO(PA0) 的状态,第一次出现下降沿时调用 vTaskSuspend 函数挂起 LEDTask,第二次出现下降时调用 vTaskResume 函数沿恢复 LEDTask,依次循环

2.代码编写

/**
  ******************************************************************************
  * @文件名: xxx.c
  * @作  者: author
  * @版  本: v1.0.0
  * @日  期: 2021.12.23
  * @简  介: 无
  * @注  意: 无
  ******************************************************************************
  */
#include "stm32f10x.h"

#include "dr_usart.h"
#include "dr_led.h"
#include "dr_key.h"

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

/* 任务句柄 */
TaskHandle_t LEDTask_Handle = NULL;

/* 任务函数 */
void AppTaskCreateTask(void *);
void LEDTask(void *);
void KEYTask(void *);

/**
  * @简  介: 无
  * @参  数: 无
  * @返回值: 无
  */
int main(void)
{
	/* --------- --------- --------- --------- --------- --------- ---------  */
	
	/* 中断分组4 */
	NVIC_Priority_Group_Config();                                        /* * */
	
	/* 串口1配置 */
	USART1_Config();                                                     /* * */
	
	/* LED(PA8, PA6)配置 */
	LED_GPIO_Config();                                                   /* * */
	
	/* KEY(PA0)配置 */
	KEY_GPIO_Config();
	
	/* --------- --------- --------- --------- --------- --------- ---------  */

	/* 创建任务AppTaskCreateTask */
	xTaskCreate(AppTaskCreateTask, "AppTaskCreateTask", 128, NULL, 1, NULL);

	/* 开启任务调度 */
	vTaskStartScheduler();
	
	while(1);
}

/**
  * @简  介: 无
  * @参  数: 无
  * @返回值: 无
  */
void AppTaskCreateTask(void *pvParameters)
{
	/* 临界保护 */
	taskENTER_CRITICAL();
	
	/* 创建任务 */
	xTaskCreate(LEDTask, "LEDTask", 128, NULL, 2, &LEDTask_Handle);
	
	xTaskCreate(KEYTask, "KEYTask", 128, NULL, 3, NULL);
	
	vTaskDelete(NULL);
	
	taskEXIT_CRITICAL();
}

/**
  * @简  介: 无
  * @参  数: 无
  * @返回值: 无
  */
void LEDTask(void *pvParameters)
{
	for (;;)
	{
		/* LED翻转 */
		GPIOA->ODR ^= ((uint16_t)0x0100);
		
		/* 信息打印:LED点亮, LED is running.; LED熄灭, LED stops running. */
		printf("LED %s\r\n", ((GPIOA->IDR & 0x0100) != 0) ? "is running." : "stops running.");
		
		/* 任务切换 */
		vTaskDelay(50);
	}
}

/**
  * @简  介: 无
  * @参  数: 无
  * @返回值: 无
  */
void KEYTask(void *pvParameters)
{
	uint8_t level_high = 0;
	uint8_t level_low  = 0;
	uint8_t edge_fall  = 0;
	uint8_t edge_rise  = 0;
	
	uint8_t _switch = 0;
	
	for (;;)
	{
		if ( (GPIOA->IDR & 0x0001) != 0 ) /* level_high */
		{
			if(level_low == 1)
				edge_rise = 1; /* edge_rise */
				
			level_low  = 0;
			level_high = 1;
		} /* --- 高电平/上升沿检测 --- */
		
		if ( (GPIOA->IDR & 0x0001) == 0 ) /* level_low */
		{
			if(level_high == 1)
				edge_fall  = 1; /* edge_fall */
				
			level_high = 0; 
			level_low  = 1;
		} /* --- 低电平/下降沿检测 --- */
		
		if(edge_fall)
		{
			if(_switch == 0) /* 第一次下降沿 */
			{
				_switch = 1;
				
				printf("--- Suspend ---.\n");
			
				/* 挂起LEDTask */
				vTaskSuspend(LEDTask_Handle);
			}
			else
			{
				_switch = 0;
			
				printf("--- Resume ---.\n");
				
				/* 恢复LEDTask */
				vTaskResume(LEDTask_Handle);
			}
		}
	
		edge_fall = 0;
		edge_rise = 0;
		
		(void)edge_rise;
	
		/* 任务切换 */
		vTaskDelay(20);
	}
}

3.调用逻辑分析仪观察
FreeRTOS复习笔记(二) —— 任务
经验证,程序运行结果与预想一致

上一篇:入门级Python多线程学习笔记


下一篇:RTX51_TINY 学习笔记