前言:FreeRTOS内容较多,分篇发布,较为基础,旨在梳理知识,适合入门的同学
(基于正点原子STM32F103开发板V2)
(对于本篇,若有疑问,欢迎在评论区留言,作者将在两小时内解答)
(本篇参考B站正点原子FreeRTOS)
目录
前言:FreeRTOS内容较多,分篇发布,较为基础,旨在梳理知识,适合入门的同学
(基于正点原子STM32F103开发板V2)
(对于本篇,若有疑问,欢迎在评论区留言,作者将在两小时内解答)
(本篇参考B站正点原子FreeRTOS)
1.RTOS
1.1RTOS原理
1.2RTOS特点
2.FreeRTOS
2.1FreeRTOS
2.2FreeRTOS特点
2.3FreeRTOS的API函数
3.FreeRTOS基础知识
3.1任务调度
3.2抢占式调度
3.3时间片调度
3.5任务状态
3.6任务状态列表
3.8总结
4.FreeRTOS任务创建和删除
4.1任务控制块结构体
4.2动态创建任务
4.3静态创建任务
4.4任务删除函数
4.5空闲任务
4.6动态创建函数实战
4.7静态创建函数实战
4.8实战总结
5.总结
1.RTOS
1.1RTOS原理
RTOS全称为:Real Time OS,就是实时操作系统,强调的是:实时性,
宏观上是可多任务同时进行的操作系统,实际上是在规定的若干很小的时刻,交替进行各个任务的一个工作原理,从表面上看像是在同时进行多任务
1.2RTOS特点
1.多任务:实现功能划分为多个任务
2.延时函数:任务调度
3.抢占式:高优先级任务抢占低优先级任务
4.任务堆栈:每个任务都有自己的栈空间
注意1:中断可以打断任意任务
注意2:任务可以同等优先级
2.FreeRTOS
2.1FreeRTOS
FreeRTOS 可以分为两部分:“Free”和“RTOS”,“Free”就是免费的、 自由的、不受约束的意思因此,从 FreeRTOS 的名字中就 能看出,FreeROTS 是一款免费的实时操作系统2.2FreeRTOS特点
2.3FreeRTOS的API函数
FreeRTOS 是一个轻量级的实时操作系统内核,它提供了丰富的 API 函数,用于创建和管理任务、同步任务间的通信、调度任务以及进行系统配置等。以下是一些 FreeRTOS 中常见的 API 函数及其用途:
1.任务创建:
xTaskCreate
: 创建一个新的任务xTaskCreateStatic
: 创建一个静态分配的任务2.任务管理:
vTaskDelete
: 删除一个任务vTaskSuspend
: 暂停一个任务vTaskResume
: 恢复一个任务eTaskGetState
: 获取任务当前的状态3.任务同步:
xSemaphoreCreateBinary
: 创建一个二值信号量xSemaphoreCreateMutex
: 创建一个互斥量xSemaphoreGive
: 释放一个信号量xSemaphoreTake
: 获取一个信号量4.任务通信:
xQueueCreate
: 创建一个队列xQueueSend
: 向队列发送数据xQueueReceive
: 从队列接收数据5.定时器:
xTimerCreate
: 创建一个定时器vTimerStart
: 启动一个定时器vTimerStop
: 停止一个定时器6.任务调度:
vTaskDelay
: 延迟一个任务执行eTaskGetIdleTaskHandle
: 获取空闲任务句柄7.系统配置:
eKernelGetTickRateHz
: 获取系统滴答时钟的频率vApplicationGetIdleTaskMemory
: 获取空闲任务的内存8.内存管理:
pvPortMalloc
: 动态分配内存vPortFree
: 释放动态分配的内存这些只是 FreeRTOS API 的一部分。FreeRTOS 提供了全面的文档,详细介绍了每个函数的用法、参数和返回值。开发者在使用这些 API 时,需要根据具体的任务需求和环境配置来选择合适的函数
3.FreeRTOS基础知识
3.1任务调度
任务调度器就是使用相关的调度算法来决定当前需要执行的哪个任务
FreeRTOS 一共支持三种任务调度方式:
3.2抢占式调度
运行条件:
运行过程:
特点
1.高优先级任务,优先执行
2.高优先级任务不停止,低优先级任务无法执行
3.被抢占的任务将会进入就绪态
3.3时间片调度
时间片:同等优先级任务轮流地享有相同的 CPU 时间(可设置一个时间片的时间(SysTick 中断周期)),在FreeRTOS中,一个时间片就等于SysTick 中断周期,并且一个任务只能拥有一个时间片
运行条件:
运行过程:
特点:
1.同等优先级任务,轮流执行;时间片流转
2.一个时间片大小,取决为滴答定时器中断周期
3.注意没有用完的时间片不会再使用,下次任务Task3得到执行 还是按照一个时间片的时钟节拍运行
(在FreeRTOS中,当一个任务阻塞时,操作系统会立即停止该任务的执行,并将CPU的控制权切换给另一个就绪状态的任务。如果Task1已经准备好执行(即它处于就绪状态),那么它将会被调度器选中,并开始执行)
3.5任务状态
FreeRTOS中任务共存在4种状态:
四种任务状态之间的转换图:
特点:
1.仅就绪态可转变成运行态
2.其他状态的任务想运行,必须先转变成就绪态
3.6任务状态列表
FreeRTOS中无非就四种状态,运行态,就绪态、阻塞态、挂起态
这四种状态中,除了运行态,其他三种任务状态的任务都有其对应的任务状态列表
特点:
1. 32位的变量,当某个位,置一时,代表所对应的优先级就绪列表有任务存在
2. 列表跟链表很像,后续会讲到
3. 调度器总是在所有处于就绪列表的任务中,选择具有最高优先级的任务来执行
4. 相同优先级的任务会连接在同一个就绪列表上
3.8总结
4.FreeRTOS任务创建和删除
任务的创建和删除本质就是调用FreeRTOS的API函数
4.1任务控制块结构体
typedef struct tskTaskControlBlock {volatile StackType_t * pxTopOfStack; /* 任务栈栈顶,必须为TCB的第一个成员 */ListItem_t xStateListItem; /* 任务状态列表项 */ ListItem_t xEventListItem; /* 任务事件列表项 */ UBaseType_t uxPriority; /* 任务优先级,数值越大,优先级越大 */StackType_t * pxStack; /* 任务栈起始地址 */char pcTaskName[ configMAX_TASK_NAME_LEN ]; /* 任务名字 */ …省略很多条件编译的成员 } tskTCB;
4.2动态创建任务
动态创建任务:任务的任务控制块以及任务的栈空间所需的内存,均由 FreeRTOS 从
FreeRTOS 管理的堆中分配
动态创建任务函数:
BaseType_t xTaskCreate ( TaskFunction_t pxTaskCode, /* 指向任务函数的指针 */ const char * const pcName /* 任务名字,最大长度configMAX_TASK_NAME_LEN ,默认16个字符*/const configSTACK_DEPTH_TYPE usStackDepth, /* 任务堆栈大小,注意字为单位 */void * const pvParameters, /* 传递给任务函数的参数 */UBaseType_t uxPriority, /* 任务优先级,范围:0 ~ configMAX_PRIORITIES - 1(0~31) */TaskHandle_t * const pxCreatedTask /* 任务句柄,就是任务的任务控制块 */ )
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:一般是任务所需要的空间太大,FreeRTOS所管理的堆栈空间不够
实现动态创建任务流程
4.3静态创建任务
静态创建任务:任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供
静态创建任务函数
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 /* 任务控制块指针,由用户分配 */ );
实现静态创建任务流程
4.4任务删除函数
用于删除已被创建的任务,被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除
void vTaskDelete(TaskHandle_t xTaskToDelete);
注意:
1.当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)
2.2、空闲任务(下面会讲到)会负责释放被删除任务中由系统分配的内存(动态创建任务),但是由用户在任务删除前申请的内存, 则需要由用户在任务被删除前提前释放,否则将导致内存泄露(静态创建任务)
删除任务流程
4.5空闲任务
- 当一个任务调用
vTaskDelete()
删除自身时,它会被标记为删除状态,但它的内存不会被立即回收。- 空闲任务周期性地运行,它会检查系统中是否有任务被标记为删除状态
- 如果发现被删除的任务,空闲任务会释放该任务的堆栈空间和任务控制块,将其占用的内存归还给系统。
- 通过这种方式,空闲任务帮助维护系统的内存资源,确保不会有内存泄漏
4.6动态创建函数实战
(基于正点原子STM32F103开发板V2 a盘资料)
第一步:
将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1 (默认)
路径: \User\freertos_demo.c\FreeRTOSConfig.h
第二步:
配置任务task1、task2、task3、start_task以及屏幕显示
路径:User\freertos_demo.c
详细细节在代码中有解释(注释)
#include "freertos_demo.h" #include "./BSP/LCD/lcd.h" #include "./BSP/KEY/key.h" /*FreeRTOS*********************************************************************************************/ #include "FreeRTOS.h" #include "task.h"/******************************************************************************************************/ /*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/ #define START_TASK_PRIO 1 /* 任务优先级 */ #define START_STK_SIZE 128 /* 任务堆栈大小 128偏大定义*/ TaskHandle_t StartTask_Handler; /* 任务句柄 */ void start_task(void *pvParameters); /* 任务函数 *//* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/ #define TASK1_PRIO 2 /* 任务优先级 */ #define TASK1_STK_SIZE 128 /* 任务堆栈大小 */ TaskHandle_t Task1Task_Handler; /* 任务句柄 */ void task1(void *pvParameters); /* 任务函数 *//* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/ #define TASK2_PRIO 3 /* 任务优先级 */ #define TASK2_STK_SIZE 128 /* 任务堆栈大小 */ TaskHandle_t Task2Task_Handler; /* 任务句柄 */ void task2(void *pvParameters); /* 任务函数 *//* TASK3 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/ #define TASK3_PRIO 4 /* 任务优先级 */ #define TASK3_STK_SIZE 128 /* 任务堆栈大小 */ TaskHandle_t Task3Task_Handler; /* 任务句柄 */ void task3(void *pvParameters); /* 任务函数 *//******************************************************************************************************//* LCD刷屏时使用的颜色 */ uint16_t lcd_discolor[11] = {WHITE, BLACK, BLUE, RED,MAGENTA, GREEN, CYAN, YELLOW,BROWN, BRRED, GRAY};/*** @brief FreeRTOS例程入口函数* @param 无* @retval 无*/ void freertos_demo(void) {lcd_show_string(10, 10, 220, 32, 32, "STM32", RED);lcd_show_string(10, 47, 220, 24, 24, "Task Create & Del", RED);lcd_show_string(10, 76, 220, 16, 16, "ATOM@ALIENTEK", RED);lcd_draw_rectangle(5, 110, 115, 314, BLACK);lcd_draw_rectangle(125, 110, 234, 314, BLACK);lcd_draw_line(5, 130, 115, 130, BLACK);lcd_draw_line(125, 130, 234, 130, BLACK);lcd_show_string(15, 111, 110, 16, 16, "Task1: 000", BLUE);lcd_show_string(135, 111, 110, 16, 16, "Task2: 000", BLUE);xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */(const char* )"start_task", /* 任务名称 */(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */(void* )NULL, /* 传入给任务函数的参数 */(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */vTaskStartScheduler(); }/*** @brief start_task* @param pvParameters : 传入参数(未用到)* @retval 无*/ void start_task(void *pvParameters) {taskENTER_CRITICAL(); /* 进入临界区 *//* 创建任务1 */xTaskCreate((TaskFunction_t )task1, /* 任务函数 */(const char* )"task1", /* 任务名称 */(uint16_t )TASK1_STK_SIZE, /* 任务堆栈大小 */(void* )NULL, /* 传入给任务函数的参数 */(UBaseType_t )TASK1_PRIO, /* 任务优先级 */(TaskHandle_t* )&Task1Task_Handler); /* 任务句柄 *//* 创建任务2 */xTaskCreate((TaskFunction_t )task2, /* 任务函数 */(const char* )"task2", /* 任务名称 */(uint16_t )TASK2_STK_SIZE, /* 任务堆栈大小 */(void* )NULL, /* 传入给任务函数的参数 */(UBaseType_t )TASK2_PRIO, /* 任务优先级 */(TaskHandle_t* )&Task2Task_Handler); /* 任务句柄 *//* 创建任务3 */xTaskCreate((TaskFunction_t )task3, /* 任务函数 */(const char* )"task3", /* 任务名称 */(uint16_t )TASK3_STK_SIZE, /* 任务堆栈大小 */(void* )NULL, /* 传入给任务函数的参数 */(UBaseType_t )TASK3_PRIO, /* 任务优先级 */(TaskHandle_t* )&Task3Task_Handler); /* 任务句柄 */vTaskDelete(StartTask_Handler); /* 删除开始任务 */taskEXIT_CRITICAL(); /* 退出临界区 */ }/*** @brief task1* @param pvParameters : 传入参数(未用到)* @retval 无*/ void task1(void *pvParameters) {uint32_t task1_num = 0;while (1){lcd_fill(6, 131, 114, 313, lcd_discolor[++task1_num % 11]);lcd_show_xnum(71, 111, task1_num, 3, 16, 0x80, BLUE);vTaskDelay(500);} }/*** @brief task2* @param pvParameters : 传入参数(未用到)* @retval 无*/ void task2(void *pvParameters) {uint32_t task2_num = 0;while (1){lcd_fill(126, 131, 233, 313, lcd_discolor[11 - (++task2_num % 11)]);lcd_show_xnum(191, 111, task2_num, 3, 16, 0x80, BLUE);vTaskDelay(500);} }/*** @brief task3* @param pvParameters : 传入参数(未用到)* @retval 无*/ void task3(void *pvParameters) {uint8_t key = 0;while (1){key = key_scan(0);switch (key){case KEY0_PRES: /* 删除任务1 */{if (Task1Task_Handler != NULL){vTaskDelete(Task1Task_Handler);Task1Task_Handler = NULL;}break;}case KEY1_PRES: /* 删除任务2 */{if (Task2Task_Handler != NULL){vTaskDelete(Task2Task_Handler);Task2Task_Handler = NULL;}break;}default:{break;}}vTaskDelay(10);} }
实验现象:
每500ms,两块区域颜色变化,并计数+1
4.7静态创建函数实战
(基于正点原子STM32F103开发板V2 a盘资料)
第一步:
将宏configSUPPORT_STATIC_ALLOCATION 配置为 1(默认为0)
路径:\User\freertos_demo.c\FreeRTOSConfig.h
第二步:
定义空闲任务&定时器任务的任务堆栈及TCB
接口函数:vApplicationGetTimerTaskMemory ( ):这个函数用于获取计时器任务(Timer Task)的内存分配
目的:获取定时器服务任务的任务堆栈和任务控制块内存
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH]; /* 定时器服务任务堆栈 */ static StaticTask_t TimerTaskTCB; /* 定时器服务任务控制块 */* @brief 获取定时器服务任务的任务堆栈和任务控制块内存* @param ppxTimerTaskTCBBuffer:任务控制块内存ppxTimerTaskStackBuffer:任务堆栈内存pulTimerTaskStackSize:任务堆栈大小* @retval 无*/ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,StackType_t **ppxTimerTaskStackBuffer,uint32_t *pulTimerTaskStackSize) {*ppxTimerTaskTCBBuffer = &TimerTaskTCB;*ppxTimerTaskStackBuffer= TimerTaskStack;*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; }
第三步:
接口函数
vApplicationGetIdleTaskMemory( ):这个函数用于获取空闲任务(Idle Task)的内存分配
目的:获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的静态内存,因此空闲任务的任务堆栈和任务控制块的内存就应该由用户来提供,FreeRTOS提供了接口函数(上面的两个函数)
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE]; /* 空闲任务任务堆栈 */ static StaticTask_t IdleTaskTCB; /* 空闲任务控制块 */* @brief 获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的静态内存,因此空闲任务的任务堆栈和任务控制块的内存就应该由用户来提供,FreeRTOS提供了接口函数vApplicationGetIdleTaskMemory()实现此函数即可。* @param ppxIdleTaskTCBBuffer:任务控制块内存ppxIdleTaskStackBuffer:任务堆栈内存pulIdleTaskStackSize:任务堆栈大小* @retval 无*/ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) {*ppxIdleTaskTCBBuffer = &IdleTaskTCB;*ppxIdleTaskStackBuffer = IdleTaskStack;*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; }
第四步:
配置任务task1、task2、task3、start_task以及屏幕显示
路径:User\freertos_demo.c
详细细节在代码中有解释(注释)
完整代码(包括二三步):
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE]; /* 空闲任务任务堆栈 */ static StaticTask_t IdleTaskTCB; /* 空闲任务控制块 */ static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH]; /* 定时器服务任务堆栈 */ static StaticTask_t TimerTaskTCB; /* 定时器服务任务控制块 *//*** @brief 获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的静态内存,因此空闲任务的任务堆栈和任务控制块的内存就应该有用户来提供,FreeRTOS提供了接口函数vApplicationGetIdleTaskMemory()实现此函数即可。* @param ppxIdleTaskTCBBuffer:任务控制块内存ppxIdleTaskStackBuffer:任务堆栈内存pulIdleTaskStackSize:任务堆栈大小* @retval 无*/ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) {*ppxIdleTaskTCBBuffer = &IdleTaskTCB;*ppxIdleTaskStackBuffer = IdleTaskStack;*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; }/*** @brief 获取定时器服务任务的任务堆栈和任务控制块内存* @param ppxTimerTaskTCBBuffer:任务控制块内存ppxTimerTaskStackBuffer:任务堆栈内存pulTimerTaskStackSize:任务堆栈大小* @retval 无*/ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,StackType_t **ppxTimerTaskStackBuffer,uint32_t *pulTimerTaskStackSize) {*ppxTimerTaskTCBBuffer = &TimerTaskTCB;*ppxTimerTaskStackBuffer= TimerTaskStack;*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; }/* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/ #define START_TASK_PRIO 1 /* 任务优先级 */ #define START_STK_SIZE 128 /* 任务堆栈大小 */ StackType_t StartTaskStack[START_STK_SIZE]; /* 任务堆栈 */ StaticTask_t StartTaskTCB; /* 任务控制块 */ TaskHandle_t StartTask_Handler; /* 任务句柄 */ void start_task(void *pvParameters); /* 任务函数 *//* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/ #define TASK1_PRIO 2 /* 任务优先级 */ #define TASK1_STK_SIZE 128 /* 任务堆栈大小 */ StackType_t Task1TaskStack[TASK1_STK_SIZE]; /* 任务堆栈 */ StaticTask_t Task1TaskTCB; /* 任务控制块 */ TaskHandle_t Task1Task_Handler; /* 任务句柄 */ void task1(void *pvParameters); /* 任务函数 *//* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/ #define TASK2_PRIO 3 /* 任务优先级 */ #define TASK2_STK_SIZE 128 /* 任务堆栈大小 */ StackType_t Task2TaskStack[TASK2_STK_SIZE]; /* 任务堆栈 */ StaticTask_t Task2TaskTCB; /* 任务控制块 */ TaskHandle_t Task2Task_Handler; /* 任务句柄 */ void task2(void *pvParameters); /* 任务函数 *//* TASK3 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/ #define TASK3_PRIO 4 /* 任务优先级 */ #define TASK3_STK_SIZE 128 /* 任务堆栈大小 */ StackType_t Task3TaskStack[TASK3_STK_SIZE]; /* 任务堆栈 */ StaticTask_t Task3TaskTCB; /* 任务控制块 */ TaskHandle_t Task3Task_Handler; /* 任务句柄 */ void task3(void *pvParameters); /* 任务函数 *//******************************************************************************************************//* LCD刷屏时使用的颜色 */ uint16_t lcd_discolor[11] = {WHITE, BLACK, BLUE, RED,MAGENTA, GREEN, CYAN, YELLOW,BROWN, BRRED, GRAY};/*** @brief FreeRTOS例程入口函数* @param 无* @retval 无*/ void freertos_demo(void) {lcd_show_string(10, 10, 220, 32, 32, "STM32", RED);lcd_show_string(10, 47, 220, 24, 24, "Task Create & Del", RED);lcd_show_string(10, 76, 220, 16, 16, "ATOM@ALIENTEK", RED);lcd_draw_rectangle(5, 110, 115, 314, BLACK);lcd_draw_rectangle(125, 110, 234, 314, BLACK);lcd_draw_line(5, 130, 115, 130, BLACK);lcd_draw_line(125, 130, 234, 130, BLACK);lcd_show_string(15, 111, 110, 16, 16, "Task1: 000", BLUE);lcd_show_string(135, 111, 110, 16, 16, "Task2: 000", BLUE);StartTask_Handler = xTaskCreateStatic((TaskFunction_t )start_task, /* 任务函数 */(const char* )"start_task", /* 任务名称 */(uint32_t )START_STK_SIZE, /* 任务堆栈大小 */(void* )NULL, /* 传递给任务函数的参数 */(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */(StackType_t* )StartTaskStack, /* 任务堆栈 */(StaticTask_t* )&StartTaskTCB); /* 任务控制块 */vTaskStartScheduler(); }/*** @brief start_task* @param pvParameters : 传入参数(未用到)* @retval 无*/ void start_task(void *pvParameters) {taskENTER_CRITICAL(); /* 进入临界区 *//* 创建任务1 */Task1Task_Handler = xTaskCreateStatic((TaskFunction_t )task1, /* 任务函数 */(const char* )"task1", /* 任务名称 */(uint32_t )TASK1_STK_SIZE,/* 任务堆栈大小 */(void* )NULL, /* 传递给任务函数的参数 */(UBaseType_t )TASK1_PRIO, /* 任务优先级 */(StackType_t* )Task1TaskStack,/* 任务堆栈 */(StaticTask_t* )&Task1TaskTCB);/* 任务控制块 *//* 创建任务2 */Task2Task_Handler = xTaskCreateStatic((TaskFunction_t )task2, /* 任务函数 */(const char* )"task2", /* 任务名称 */(uint32_t )TASK2_STK_SIZE,/* 任务堆栈大小 */(void* )NULL, /* 传递给任务函数的参数 */(UBaseType_t )TASK2_PRIO, /* 任务优先级 */(StackType_t* )Task2TaskStack,/* 任务堆栈 */(StaticTask_t* )&Task2TaskTCB);/* 任务控制块 *//* 创建任务3 */Task3Task_Handler = xTaskCreateStatic((TaskFunction_t )task3, /* 任务函数 */(const char* )"task3", /* 任务名称 */(uint32_t )TASK3_STK_SIZE,/* 任务堆栈大小 */(void* )NULL, /* 传递给任务函数的参数 */(UBaseType_t )TASK3_PRIO, /* 任务优先级 */(StackType_t* )Task3TaskStack,/* 任务堆栈 */(StaticTask_t* )&Task3TaskTCB);/* 任务控制块 */vTaskDelete(StartTask_Handler); /* 删除开始任务 */taskEXIT_CRITICAL(); /* 退出临界区 */ }/*** @brief task1* @param pvParameters : 传入参数(未用到)* @retval 无*/ void task1(void *pvParameters) {uint32_t task1_num = 0;while (1){lcd_fill(6, 131, 114, 313, lcd_discolor[++task1_num % 11]);lcd_show_xnum(71, 111, task1_num, 3, 16, 0x80, BLUE);vTaskDelay(500);} }/*** @brief task2* @param pvParameters : 传入参数(未用到)* @retval 无*/ void task2(void *pvParameters) {uint32_t task2_num = 0;while (1){lcd_fill(126, 131, 233, 313, lcd_discolor[11 - (++task2_num % 11)]);lcd_show_xnum(191, 111, task2_num, 3, 16, 0x80, BLUE);vTaskDelay(500);} }/*** @brief task3* @param pvParameters : 传入参数(未用到)* @retval 无*/ void task3(void *pvParameters) {uint8_t key = 0;while (1){key = key_scan(0);switch (key){case KEY0_PRES: /* 删除任务1 */{if (Task1Task_Handler != NULL){vTaskDelete(Task1Task_Handler);Task1Task_Handler = NULL;}break;}case KEY1_PRES: /* 删除任务2 */{if (Task2Task_Handler != NULL){vTaskDelete(Task2Task_Handler);Task2Task_Handler = NULL;}break;}default:{break;}}vTaskDelay(10);} }
除了定义接口函数外,其余与动态创建的函数相同
实验现象:
每500ms,两块区域颜色变化,并计数+1
4.8实战总结
注意:
1.动态创建相对简单,在实际的应用中,动态方式创建任务是比较常用的,除非有特殊的需求,一般都会使用动态方式创建任务2.静态创建:可将任务堆栈放置在特定的内存位置,并且无需关心对内存分配失败的处理
5.总结
FreeRTOS官网:https://www.freertos.org/
正点原子STM32F103开发板V2 a盘资料: https://pan.baidu.com/s/1iebOVd87jBVtoudMijboIg 提取码:1ypa
FreeRTOS内容较多,内容分篇发布,感谢大家观看
连载中...
作者留言:本人学生,大多数为网络资源,如有侵权,及时联系
创作时间:2024.10.22