上一期配置完FreeRTOS的环境后,这一期记录自己关于任务创建的学习过程。
官方的API手册中有这些函数,xTaskCreate和xTaskCreateStatic分别是利用动态方法和静态方法创建任务。(动态和静态的区别之后再研究)vTaskDelete是删除任务,因为freeRTOS的任务内存空间存储在堆区,所以很像C语言的动态内存分配,任务使用和结束我们都应该创建和删除这些任务防止占用过多空间。
xTaskCreate的函数模型如下,参数内容总共有六项:任务函数的函数指针,任务函数的名称,任务函数所需堆栈空间,任务函数的类型,任务函数的优先级,以及任务函数的函数句柄
vTaskDelete的函数模型如下,参数内容为函数句柄,如果为NULL则删除该任务本身。
因此我们创建任务的步骤是:首先定义一个启动任务,该任务是为了启动我们的真正任务,因此在调用完一遍后要用vTaskDelete 中输入NULL删除启动函数本身。
任务函数编写
/*
LED1翻转
*/
void LED_TOG(void * pvParameters)//参数为 void * pvParameters
{
while(1)
{
printf("LED_TOG runningrn");//串口打印运行信息
HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10);//LED1翻转
vTaskDelay(500);//延迟500ms
}
}
要注意的是vTaskDelay是FreeRTOS用来延时的函数。
之后我们要创建任务函数的启动函数
TaskHandle_t Start_LED_Handler;
void Start_LED(void * pvParameters)
{
xTaskCreate((TaskFunction_t )LED_TOG,//任务函数
(char * )"LED_TOG",//任务名称
(configSTACK_DEPTH_TYPE) 128,//堆栈空间128Byte
(void* ) NULL,//无返回
(UBaseType_t ) 1,//优先级1
(TaskHandle_t * )LED_TOG_Handler);//任务函数句柄
vTaskDelete(NULL);
}
我们创建启动任务的函数,将 任务函数的函数指针,任务函数的名称,任务函数所需堆栈空间,任务函数的类型,任务函数的优先级,以及任务函数的函数句柄 ,填入vTaskCreate函数中,其中每个参数都使用了强制类型转换防止出现错误。
同样的方法,我们创建启动 启动函数的任务(有点绕口因为启动函数本身是一个任务)
void FreeRTOS_Init()
{
xTaskCreate((TaskFunction_t )Start_LED,
(char * )"Start_LED",
(configSTACK_DEPTH_TYPE) 128,
(void* ) NULL,
(UBaseType_t ) 0,
(TaskHandle_t * )Start_LED_Handler);
vTaskStartScheduler();//启动运行函数
}
这样子我们在主函数中添加刚刚定义的启动启动函数
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
KEY_Init();
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
FreeRTOS_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
我们的代码就可以正常运行啦!
我们在用上述的方法实现两个灯一起翻转
还是先编辑任务函数如下,并且定义其相关句柄
TaskHandle_t LED_TOG2_Handler;
void LED_TOG2(void * pvParameters)//参数为 void * pvParameters
{
while(1)
{
printf("LED_TOG runningrn");//串口打印运行信息
HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_9);//LED0翻转
vTaskDelay(500);//延迟500ms
}
}
在任务启动函数中加入我们新建的任务。
void Start_LED(void * pvParameters)
{
xTaskCreate((TaskFunction_t )LED_TOG,//任务函数
(char * )"LED_TOG",//任务名称
(configSTACK_DEPTH_TYPE) 128,//堆栈空间128Byte
(void* ) NULL,//无返回
(UBaseType_t ) 1,//优先级1
(TaskHandle_t * )LED_TOG_Handler);//任务函数句柄
xTaskCreate((TaskFunction_t )LED_TOG2,//任务函数
(char * )"LED_TOG2",//任务名称
(configSTACK_DEPTH_TYPE) 128,//堆栈空间128Byte
(void* ) NULL,//无返回
(UBaseType_t ) 2,//优先级2
(TaskHandle_t * )LED_TOG2_Handler);//任务函数句柄
vTaskDelete(NULL);
}
再次运行我们的代码。
麦克阿瑟将军曾说过:点灯对于嵌入式来说,就像Hello World对于程序员一样重要。我们不能不去点灯,就像西方不能失去耶路撒冷。