当前位置: 首页 > news >正文

freeRTOS 任务的创建、挂起、恢复

freeRTOS

  1. FreeRTOS 是一个开源的实时操作系统(RTOS),专为嵌入式系统特别是微控制器设计。
  2. 它是轻量级的,提供了一个多任务环境,允许多个任务在单个处理器上并发运行。
  3. 主要特性:抢占式多任务、任务调度、可移植性,任务间通信,内存管理
  4. 虽然 FreeRTOS 使用了“任务”这一术语,但它们在功能和概念上类似于传统操作系统中的“线程”。这两个术语都表示了并行执行的基本单位,并且都涉及到优先级、堆栈管理、调度等关键概念。
  5. 在 FreeRTOS 中,任务的管理和调度是通过 FreeRTOS 提供的 API 实现的,而在传统操作系统中,线程的管理则是由操作系统的线程库或内核提供的。

常用函数解析

TaskHandle_t 创建任务句柄
TaskHandle_t 实际上是一个指向任务控制块(TCB)的指针,TCB 是 FreeRTOS 内部用于存储任务状态的数据结构。用法
保存任务句柄: 在调用 xTaskCreate 创建任务时,可以将任务句柄传递到一个 TaskHandle_t 变量中。这个句柄可以用来引用任务,以便后续对任务进行操作。// 定义任务句柄
TaskHandle_t taskFlushled;// 任务函数
void task_fun_flushled(void *args) {while (1) {// 切换 GPIO 状态HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8);osDelay(1000);  // 延迟 1 秒}
}void setup() {// 创建任务并将句柄存储在 taskFlushled 中BaseType_t ret = xTaskCreate(task_fun_flushled,      // 任务函数"taskFlushled",         // 任务名称128,                    // 堆栈大小NULL,                   // 任务参数osPriorityNormal,       // 优先级&taskFlushled           // 任务句柄);// 检查任务创建是否成功if (ret == pdFALSE) {printf("任务创建失败\n");}
}
xTaskCreate() 任务创建函数
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,const char * const pcName,const configSTACK_DEPTH_TYPE usStackDepth,void *pvParameters,UBaseType_t uxPriority,TaskHandle_t *pxCreatedTask);
参数TaskFunction_t pvTaskCode: 指向任务执行的函数,这个函数需要符合 void func(void *) 的形式。const char * const pcName: 任务的名字,用于调试。const configSTACK_DEPTH_TYPE usStackDepth: 任务的堆栈大小,以字为单位。void *pvParameters: 传递给任务的参数。UBaseType_t uxPriority: 任务的优先级,数值越大,优先级越高。TaskHandle_t *pxCreatedTask: 用于传出任务句柄的指针,可以用于后续的任务引用或删除等操作。即为任务本身返回值pdFALSE:表示任务创建失败
-------------------优先级--------------------------
typedef enum {osPriorityIdle          = -3,          ///< 优先级:空闲(最低优先级)osPriorityLow           = -2,          ///< 优先级:低osPriorityBelowNormal   = -1,          ///< 优先级:低于正常osPriorityNormal        =  0,          ///< 优先级:正常(默认优先级)osPriorityAboveNormal   = +1,          ///< 优先级:高于正常osPriorityHigh          = +2,          ///< 优先级:高osPriorityRealtime      = +3,          ///< 优先级:实时(最高优先级)osPriorityError         =  0x84        ///< 优先级:错误(系统无法确定优先级或线程具有非法优先级)
} osPriority;
-------------------------------------------------------------具体用法xTaskCreate(task_fun_printf,"taskPrintf",128,NULL,osPriorityNormal,&taskPrintHandle);
-----以下是具体执行函数----------
任务不是只执行一次所以有一个函数体
并且不能光是你一个人执行,故有osDelay函数void task_fun_printf(void *args)
{while(1){printf("%s-%d\r\n",__func__,__LINE__);osDelay(1000);}
}
----------以下是任务句柄,当然它应该放在最前面----------------
TaskHandle_t taskPrintHandle;
portSET_INTERRUPT_MASK_FROM_ISR() 禁用中断
这个宏在中断服务例程(ISR)中使用。
确保操作的原子性和数据的一致性。
防止中断处理过程中被其他中断打断。portSET_INTERRUPT_MASK_FROM_ISR(): 设置中断掩码,禁用中断。
portCLEAR_INTERRUPT_MASK_FROM_ISR(): 恢复中断掩码,重新启用中断。用法int __io_putchar(int ch)
{UBaseType_t vxx;vxx = portSET_INTERRUPT_MASK_FROM_ISR();HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1);portCLEAR_INTERRUPT_MASK_FROM_ISR(vxx);return ch;
}
defaultTask 默认任务
defaultTask 在系统中扮演了多个角色,包括初始化系统、**保持**系统运行(占位)、优化任务调度、处理异常和调试开发。该任务由STM32CubeIDE自动创建,代码如下
// 定义 defaultTask
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
// 创建 defaultTask 任务
osThreadId defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
// 任务函数
void StartDefaultTask(void const * argument)
{// 执行系统初始化或其他必要操作for(;;){// 空循环,保持任务在运行状态osDelay(1);  // 延迟以允许其他任务执行}
}
osKernelStart() 启动内核调度器
osKernelStart() 是 FreeRTOS 中的一个函数,用于启动 RTOS 内核的调度器。
在调用 osKernelStart() 后,系统的控制权将转交给 RTOS 内核。通常,main() 函数中的 while (1) 循环会继续存在,但它不会执行任何操作,因为控制权已交给内核调度。
vTaskResume 恢复(激活)被挂起的任务
函数原型
void vTaskResume(TaskHandle_t xTaskToResume);它的作用是将任务从挂起状态重新设置为就绪状态,使得该任务可以被调度和执行。升级版
xTaskResumeFromISR()
允许在 ISR 中将任务的状态从挂起变为就绪,从而使任务能够在 ISR 处理完后尽快被调度执行。
vTaskSuspend 挂起任务
函数原型:void vTaskSuspend(TaskHandle_t xTaskToSuspend);用于将一个正在运行或就绪的任务挂起。挂起的任务将不会被调度或执行,直到它被恢复。升级版
vTaskSuspendFromISR
vTaskDelete 删除任务
函数原型:
void vTaskDelete(TaskHandle_t xTaskToDelete);
用于删除一个任务。调用这个函数会释放与任务相关的所有资源,并将任务从系统中移除。xTaskToDelete: 要删除的任务的句柄。如果句柄为 NULL,则当前正在运行的任务将被删除。如果要删除的任务不是当前任务,传入任务句柄即可。
注意,删除任务的时候要注意同步问题;一般是 自我删除;void task_test_fun(void *args){while(1){干活; if(干完了){break;}}vTaskDelete(NULL);  //删除自己}
疑问为什么删除osDelay后,其它函数也会执行
  • 各个任务在 FreeRTOS 中是独立的,除非有显式的同步机制(如信号量、互斥量等),一个任务的执行状态不会直接影响其他任务。
osDelay和HAL_Delay的区别
osDelay
  • osDelay 是 FreeRTOS 提供的延迟函数
  • osDelay 会将当前任务挂起一段指定的时间,在这段时间内,调度器可以将 CPU 分配给其他任务执行。等延迟时间结束后,当前任务会被重新放入就绪队列,等待调度器再次调度。
HAL_Delay
  • HAL_Delay 是 STM32 HAL 库中的一个延迟函数。它的工作原理是利用 SysTick 定时器,通过轮询计数器来产生延迟。在调用 HAL_Delay() 时,程序会进入一个忙等待循环(也叫阻塞等待),直到指定的时间过去。这意味着在这段延迟时间内,微控制器不会执行其他任务,完全被阻塞住了。
在freeRTOS中禁止使用HAL_Delay
  • 在多任务环境中使用 HAL_Delay 会阻塞整个系统,导致其他任务无法执行,系统无法实现真正的并发。

代码示例

1.RCC设置Crystal
2.USART1设置为异步通信
3.FREERTOS 的interface选择CMSIS_C1(简单但功能有限)
4.配置测试管脚,我用的是PC6,7,8作为LED灯管脚具体代码如下 功能:交替打印连续数
#include "main.h"  // 引入项目主头文件,包含系统配置和外设定义。
#include "cmsis_os.h"  // 引入CMSIS-RTOS API库,用于FreeRTOS的任务管理。UART_HandleTypeDef huart1;  // 声明一个UART句柄,用于管理USART1外设。
osThreadId defaultTaskHandle;  // 声明一个线程句柄,用于默认任务管理。void SystemClock_Config(void);  // 声明系统时钟配置函数。
static void MX_GPIO_Init(void);  // 声明GPIO初始化函数。
static void MX_USART1_UART_Init(void);  // 声明USART1初始化函数。
void StartDefaultTask(void const * argument);  // 声明默认任务的实现函数。int __io_putchar(int ch)  // 定义一个输出函数,用于重定向printf的输出到UART。
{UBaseType_t vxx;  // 声明一个变量,用于保存中断状态。vxx = portSET_INTERRUPT_MASK_FROM_ISR();  // 禁止中断,确保原子性操作。HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1);  // 通过UART发送单个字符。portCLEAR_INTERRUPT_MASK_FROM_ISR(vxx);  // 恢复中断。return ch;  // 返回发送的字符。
}int cnt = 0;  // 定义一个全局计数器变量。
TaskHandle_t taskOuHandle;  // 定义一个任务句柄,用于管理 "task_fun_ou" 任务。
TaskHandle_t taskJiHandle;  // 定义一个任务句柄,用于管理 "task_fun_ji" 任务。void task_fun_ou(void *args)  // 定义一个名为 "task_fun_ou" 的任务函数。
{int Acnt = 0;  // 定义局部计数变量。while (1)  // 无限循环,任务主循环。{printf(" %d \r\n", Acnt);  // 打印当前计数值。Acnt += 2;  // 每次循环计数器加2。vTaskResume(taskJiHandle);  // 恢复 "task_fun_ji" 任务。vTaskSuspend(taskOuHandle);  // 挂起当前任务(task_fun_ou)。}
}void task_fun_ji(void *args)  // 定义一个名为 "task_fun_ji" 的任务函数。
{vTaskSuspend(taskJiHandle);  // 首先挂起自己,等待 "task_fun_ou" 任务恢复。int Bcnt = 1;  // 定义局部计数变量。while (1)  // 无限循环,任务主循环。{printf(" %d \r\n", Bcnt);  // 打印当前计数值。Bcnt += 2;  // 每次循环计数器加2。vTaskResume(taskOuHandle);  // 恢复 "task_fun_ou" 任务。vTaskSuspend(taskJiHandle);  // 挂起当前任务(task_fun_ji)。osDelay(1000);  // 延时1秒(1000毫秒)。}
}int main(void)  // 主程序入口点。
{HAL_Init();  // 初始化硬件抽象层(HAL库),配置外设和中断。SystemClock_Config();  // 配置系统时钟。MX_GPIO_Init();  // 初始化GPIO引脚。MX_USART1_UART_Init();  // 初始化USART1外设。osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);  // 定义默认任务属性。defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);  // 创建并启动默认任务。BaseType_t ret;  // 定义任务创建的返回值变量。ret = xTaskCreate(task_fun_ou, "taskPrintfOU", 128, NULL, osPriorityNormal, &taskOuHandle);  // 创建并启动 "task_fun_ou" 任务。if (ret == pdFALSE)  // 检查任务创建是否成功。{printf("xTaskCreate for print err\r\n");  // 打印错误信息。return -34;  // 返回错误代码。}ret = xTaskCreate(task_fun_ji, "taskPrintfODD", 128, NULL, osPriorityNormal, &taskJiHandle);  // 创建并启动 "task_fun_ji" 任务。if (ret == pdFALSE)  // 检查任务创建是否成功。{printf("xTaskCreate for flushled err\r\n");  // 打印错误信息。return -34;  // 返回错误代码。}osKernelStart();  // 启动FreeRTOS调度器,开始多任务运行。while (1)  // 主循环,实际上不会执行到这里,因为控制权交给了FreeRTOS调度器。{}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 使用PyTorch进行图像风格迁移:基于VGG19实现
  • 多目标优化算法求解LSMOP(Large-Scale Multi-Objective Optimization Problem)测试集,MATLAB代码
  • Windows和Mac命令窗快速打开文件夹
  • vue 项目自适应 配置 px转rem 的插件postcss-pxtorem
  • 数据中台建设(六)—— 数据开发-提取数据价值
  • Java实现建造者模式和源码中的应用
  • 大棚分割数据集,40765对影像,16.9g数据量,0.8米高分二,纯手工标注(arcgis标注)的大规模农业大棚分割数据集。
  • 使用Flux以文生图
  • 【QT】常用类
  • php AEAD_AES_256_GCM算法 解密
  • 38. 如何在Spring Boot项目中集成MyBatis-Plus?
  • 读构建可扩展分布式系统:方法与实践04应用服务
  • 低功耗蓝牙模块在健身器材中的应用,让健身体验更智能
  • 【GoMate框架案例】讯飞大模型RAG智能问答挑战赛top10 Baseline
  • vue3常见的bug 修复bug
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • 《深入 React 技术栈》
  • 【翻译】babel对TC39装饰器草案的实现
  • 345-反转字符串中的元音字母
  • codis proxy处理流程
  • Java读取Properties文件的六种方法
  • JS学习笔记——闭包
  • leetcode388. Longest Absolute File Path
  • PHP的类修饰符与访问修饰符
  • rc-form之最单纯情况
  • Spring Cloud中负载均衡器概览
  • 前嗅ForeSpider采集配置界面介绍
  • 深入浅出Node.js
  • 探索 JS 中的模块化
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  • 鱼骨图 - 如何绘制?
  • 原生 js 实现移动端 Touch 滑动反弹
  • # centos7下FFmpeg环境部署记录
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • (2024.6.23)最新版MAVEN的安装和配置教程(超详细)
  • (6) 深入探索Python-Pandas库的核心数据结构:DataFrame全面解析
  • (C语言)共用体union的用法举例
  • (SERIES12)DM性能优化
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (层次遍历)104. 二叉树的最大深度
  • (分布式缓存)Redis哨兵
  • (区间dp) (经典例题) 石子合并
  • (三十)Flask之wtforms库【剖析源码上篇】
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (贪心 + 双指针) LeetCode 455. 分发饼干
  • (一)SpringBoot3---尚硅谷总结
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • .axf 转化 .bin文件 的方法
  • .bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别
  • .NET CORE Aws S3 使用
  • .net core 控制台应用程序读取配置文件app.config
  • .NET MAUI Sqlite程序应用-数据库配置(一)
  • .Net 中Partitioner static与dynamic的性能对比