FreeRTOS动态创建和删除任务
FreeRTOS
首先来了解一下什么是FreeRTOS。FreeRTOS全称Free Real Time Operating System,即免费的实时操作系统。 相比于计算机中用到的Windows,MacOS,Linux等操作系统,实时操作系统(RTOS)是一种轻量级的操作系统,适用于嵌入式硬件中,用于解决单片机类裸机轮询方式在处理多个任务时的实时性不高的问题。
STM32CubeMX配置
使用STM32CubeMX进行配置将省去系统移植这一步骤,只需要配置用户用需的参数即可,非常方便,在本实验中将实现首先创建一个开始任务,然后在开始任务中在创建三个任务,功能实现分别如下:
- 任务一,实现LED0每500ms翻转
- 任务二,实现LED1每500ms翻转
- 任务三,判断key0是否按下,若按下,删除任务一
具体配置如下:
选中FreeRTOS选项,然后打开任务和队列,进行任务配置,配置如下:
需要注意红色框框选中Dynamic则是使用动态的方式,选择Static则为静态,这里配置为动态,其余选项等会将会结合代码一起讲解。
剩下的配置则是配置LED以及KEY的对应IO口,以及打开串口通讯方便调试,自行设置即可,配置完成后则可以生成工程代码了。
工程生成及代码编写
工程生成
工程生成之后可以看到左边有了相关的代码:
我们打开freertos.c查看里面的内容:
可以看到这里简单的两行就已经帮我们生成了我们刚刚配置的StartTask这个任务,那我们来查看一下这两个函数,第一个函数是刚刚配置的任务函数,目前是空的,需要用户自己编写,那就着重来看一下第二个函数:
这里点击osThreadDef可以看出其实这个本身是一个宏定义:
再跳转到定义的内容则是这样一个结构体:
看到这里是不是有点眼熟,这里就是我们一开始STM32CubeMX配置的内容,所以在CubeMX中的配置就是在配置这个结构体,可以看出来在这个结构体中包含了任务的名称、入口、优先级、传递参数以及堆栈大小,剩下两个则是静态创建任务的内容,这里暂时先不看,所以这里就可以看出通过这个宏定义则完成了StartTask任务的配置。
接下来一行的操作则是获取任务的句柄,后续通过这个句柄我们也可以实现任务的删除,这个句柄则是一开始就定义在了开头:
代码编写
那么从这个.c文件中就可以看出创建一个任务的基本流程是怎样实现的,接下来照葫芦画瓢实现我们需要的三个任务,首先我们需要在开始任务中创建我们的三个任务,代码如下:
首先在用户代码区创建三个任务句柄:
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
osThreadId Start_Task1Handle;
osThreadId Start_Task2Handle;
osThreadId Start_Task3Handle;
/* USER CODE END Variables */
接下来创建三个任务入口,即任务函数:
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
void StartTask1(void const * argument);
void StartTask2(void const * argument);
void StartTask3(void const * argument);
/* USER CODE END FunctionPrototypes */
接着就在我们的开始任务函数中进行任务创建:
/* USER CODE BEGIN Header_StartTask */
/**
* @brief Function implementing the Start_Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask */
void StartTask(void const * argument)
{
/* USER CODE BEGIN StartTask */
/* definition and creation of Task1 */
osThreadDef(Task1, StartTask1, osPriorityLow, 0, 128);
Start_Task1Handle = osThreadCreate(osThread(Task1), NULL);
/* definition and creation of Task2 */
osThreadDef(Task2, StartTask2, osPriorityBelowNormal, 0, 128);
Start_Task2Handle = osThreadCreate(osThread(Task2), NULL);
/* definition and creation of Task3 */
osThreadDef(Task3, StartTask3, osPriorityNormal, 0, 128);
Start_Task3Handle = osThreadCreate(osThread(Task3), NULL);
vTaskDelete(NULL);
/* USER CODE END StartTask */
}
创建完成后则删除开始任务:
这里的任务优先级选择可以查看以下枚举:
接下来则是编写三个任务函数:
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void StartTask1(void const * argument)
{
while(1)
{
printf("LED0 work!\r\n");
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);
osDelay(500);
}
}
void StartTask2(void const * argument)
{
while(1)
{
printf("LED1 work!\r\n");
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
osDelay(500);
}
}
void StartTask3(void const * argument)
{
uint8_t key = 0;
while(1)
{
printf("task3 work!\r\n");
key = key_scan();
if(key == KEY0_PRESS)
{
if(Start_Task1Handle != NULL)
{
vTaskDelete(Start_Task1Handle);
Start_Task1Handle = NULL;
}
}
osDelay(10);
}
}
/* USER CODE END Application */
这里需要注意一点,如果创建完函数却并没有创建入口函数,则会出现报错,即在调用完这两个函数后
osThreadDef(Task1, StartTask1, osPriorityLow, 0, 128);
Start_Task1Handle = osThreadCreate(osThread(Task1), NULL);
需要在下面定义一个空函数放着先
void StartTask1(void const * argument)
{
}
至此功能就实现完毕了。