FreeRTOS多任务系统①

article/2025/7/29 18:20:19

多任务系统

回想一下我们以前在使用 51、STM32 单片机裸机(未使用实时操作系统)的时候一般都是在main 函数里面用 while(1)做一个大循环来完成所有的处理, 即应用程序是一个无限的循环, 循环中调用相应的函数完成所需的处理。 有时候我们也需要中断中完成一些处理。 相对于多任务系统而言, 这个就是单任务系统, 也称作前后台系统, 中断服务函数作为前台程序, 大循环while(1)作为后台程序。 

裸机开发缺点

前后台系统的实时性差, 前后台系统各个任务(应用程序)都是排队等着轮流执行,不管你这个程序现在有多紧急, 没轮到你就只能等着!相当于所有任务(应用程序)的优先级都是一样的。 但是前后台系统简单,资源消耗也少!在稍微大一点的嵌入式应用中前后台系统就明显力不从心了,此时就需要多任务系统出马了。

FreeRTOS优势 

多任务系统会把一个大问题(应用)“ 分而治之” , 把大问题划分成很多个小问题, 逐步的把小问题解决掉, 大问题也就随之解决了, 这些小问题可以单独的作为一个小任务来处理。 这些小任务是并发处理的。

注意并不是说同一时刻一起执行很多个任务, 而是由于每个任务执行的时间很短, 导致看起来像是同一时刻执行了很多个任务一样。 多个任务带来了一个新的问题, 究竟哪个任务先运行, 哪个任务后运行呢? 完成这个功能的东西在 RTOS 系统中叫做任务调度器

任务调度器

FreeRTOS 是一个抢占式的实时多任务系统, 那么其任务调度器也是抢占式的, 运行过程如图所示:

任务调度器类型

FreeRTOS 支持两种调度器模式,通过宏configUSE_PREEMPTION配置:

1. 抢占式调度器(Preemptive Scheduler)
  • 核心机制:
    • 高优先级任务可随时中断低优先级任务的执行,确保紧急任务优先运行。
    • 由系统滴答定时器(SysTick)触发周期性调度(如每 1ms 一次),或在中断后触发调度。
  • 应用场景:
    • 对实时性要求高的场景(如工业控制、传感器数据采集)。

就是高优先级的任务可以打断低优先级任务的运行而取得 CPU 的使用权, 这样就保证了那些紧急任务的运行。 抢占式调度,是最高优先级的任务一旦就绪, 总能得到CPU的执行权; 它抢占了低优先级的运行机会。 在抢占式调度系统中,总是运行最高优先级的任务。

2. 非抢占式调度器(Cooperative Scheduler)
  • 核心机制:
    • 任务主动释放 CPU 控制权(如调用vTaskDelay()),调度器才会切换到下一个任务。
    • 低优先级任务运行时,高优先级任务需等待当前任务主动让出 CPU。
  • 应用场景:
    • 对实时性要求较低,或需避免抢占导致资源竞争的场景(如简单的多任务协作)。
就是时间片轮转的调度

时间片轮转的调度方法:是让相同优先级的几个任务轮流运行, 每个任务运行一个时间片, 任务在时间片运行完之后,操作系统自动切换到下一个任务运行; 在任务运行的时间片中, 也可以提前让出CPU运行权,把它交给下一个任务运行。 FreeRTOS的时间片固定为一个时钟节拍,由configTICK_RATE_HZ这个宏设置

在FreeRTOS中,抢占式调度,与时间片轮转可以同时存在; 当有高优先级任务就绪时, 运行高优先级任务; 当最高优先级的任务有好几个时, 这几个任务可以以时间片轮转方式调度。

任务优先级

每 个 任 务 都 可 以 分 配 一 个 从 0~(configMAX_PRIORITIES-1) 的 优 先级 , configMAX_PRIORITIES 在文件 FreeRTOSConfig.h 中有定义, 一般不超过 32。

优先级数字越低表示任务的优先级越低,0 的优先级最低,configMAX_PRIORITIES-1 的优先级最高。空闲任务的优先级最低,为 0。( 注意和中断的优先级区分,任务和中断不一样,中断一般是数字越小优先级越大)

当宏 configUSE_TIME_SLICING 定义为 1 的时候多个任务可以共用一个优先级, 数量不限。 

任务状态 

FreeRTOS 中的任务永远处于下面几个状态中的某一个: 

运行态

当一个任务正在运行时,那么就说这个任务处于运行态,处于运行态的任务就是当前正在使用处理器的任务。如果使用的是单核处理器的话那么不管在任何时刻永远都只有一个任务处于运行态。

就绪态 

处于就绪态的任务是那些已经准备就绪(这些任务没有被阻塞或者挂起), 可以运行的任务,但是处于就绪态的任务还没有运行,因为有一个同优先级或者更高优先级的任务正在运行。

挂起态 

像阻塞态一样,任务进入挂起态以后也不能被调度器调用进入运行态,但是进入挂起态的任务没有超时时间。任务进入和退出挂起态通过调用函数vTaskSuspend()和 xTaskResume()。

注意: 

① 一个更高优先级的任务进入了就绪状态,就可以替换在cpu里比自己优先级低的。

② cpu执行的任务调用系统时间等待,或者等待事件,从而进入阻塞态退出cpu,从就绪状态的任务挑选最高优先级的进入cpu。

③ 你设置了时间片调度,然后就绪状态里最高优先级的任务和正在cpu里的任务优先级一样, 也发生调度任务。

以下代码就是用抢占式调度器实现两个任务,led0_task()函数抢占优先级是3,led1_task()函数抢占优先级是2,所以函数会一直执行led0_task()函数。

如果将 vTaskDelay(500); 打开注释那就会两个任务交替执行,就是用到了时间片轮转的调度方法。led0_task()函数比led1_task()函数抢占优先级高,所以先执行led0_task()函数,然后进入vTaskDelay(500)阻塞,阻塞期间会执行led1_task()函数,一旦vTaskDelay(500)阻塞时间到了led0_task()就会马上抢占led1_task()函数进入cpu执行led0_task(),这就体现了高优先级抢占低优先级,而且抢占式调度,与时间片轮转可以同时存在。

//ÈÎÎñÓÅÏȼ¶
#define LED0_TASK_PRIO		3
//ÈÎÎñ¶ÑÕ»´óС	
#define LED0_STK_SIZE 		50  
//ÈÎÎñ¾ä±ú
TaskHandle_t LED0Task_Handler;
//ÈÎÎñº¯Êý
void led0_task(void *pvParameters);//ÈÎÎñÓÅÏȼ¶
#define LED1_TASK_PRIO		2
//ÈÎÎñ¶ÑÕ»´óС	
#define LED1_STK_SIZE 		50  
//ÈÎÎñ¾ä±ú
TaskHandle_t LED1Task_Handler;
//ÈÎÎñº¯Êý
void led1_task(void *pvParameters);int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//ÉèÖÃϵͳÖжÏÓÅÏȼ¶·Ö×é4	 delay_init();	    				//ÑÓʱº¯Êý³õʼ»¯	  uart_init(115200);					//³õʼ»¯´®¿ÚLED_Init();		  					//³õʼ»¯LED//´´½¨LED0ÈÎÎñxTaskCreate((TaskFunction_t )led0_task,   //ÈÎÎñº¯Êý  	(const char*    )"led0_task", //ÈÎÎñÃû³Æ  	(uint16_t       )LED0_STK_SIZE,//ÈÎÎñ¶ÑÕ»´óС (void*          )NULL,				//´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý(UBaseType_t    )LED0_TASK_PRIO,//ÈÎÎñÓÅÏȼ¶	(TaskHandle_t*  )&LED0Task_Handler); //ÈÎÎñ¾ä±ú   //´´½¨LED1ÈÎÎñxTaskCreate((TaskFunction_t )led1_task,     (const char*    )"led1_task",   (uint16_t       )LED1_STK_SIZE, (void*          )NULL,(UBaseType_t    )LED1_TASK_PRIO,(TaskHandle_t*  )&LED1Task_Handler);         vTaskStartScheduler();          //¿ªÆôÈÎÎñµ÷¶È
}//LED0ÈÎÎñº¯Êý 
void led0_task(void *pvParameters)
{while(1){LED0=~LED0;// vTaskDelay(500);//freertosϵͳµÈ´ýº¯Êýdelay_xms(500);}
}   //LED1ÈÎÎñº¯Êý
void led1_task(void *pvParameters)
{while(1){LED1=0;//    vTaskDelay(200);delay_xms(500);LED1=1;//   vTaskDelay(800);delay_xms(500);}
}

http://www.hkcw.cn/article/wsmMixVagZ.shtml

相关文章

Celery简介

一、什么是异步任务队列 异步任务队列是指一种用于管理和调度异步执行任务的机制。具体来说,它允许将任务放入队列中,然后由后台进程异步处理这些任务,而不会阻塞主线程的执行。这种设计使得系统能够高效地处理耗时操作,同时保持…

【Livox雷达使用】

记录 目前livox雷达型号较多,适用范围广泛。后来出的雷达需要使用使用第二代SDK和驱动,如Mid360、HAP。之前在github上看有人问是否能一起安装,官方回答是可以的,我把livox SDK、livox_ros_driver和SDK2、driver2都下载了进行比较…

RS232转Profinet网关在检漏仪与西门子PLC里的应用

RS232转Profinet网关在检漏仪与西门子PLC里的应用 在工业自动化和控制领域,设备间的高效通信至关重要。RS232转Profinet网关作为一种关键的转换工具,能够将传统的RS232接口设备接入现代化的Profinet网络,从而实现数据的无缝传输和设备的远程…

公链地址生成曲线和算法

在区块链公链中,除了 ECDSA(基于 secp256k1 曲线) 和 EdDSA(基于 Ed25519 曲线) 之外,还有其他一些加密算法和椭圆曲线被用于生成公私钥对、签名验证或地址生成。这些算法和曲线的选择通常基于安全性、性能…

⭐ Unity AVProVideo插件自带播放器 脚本重构 实现视频激活重置功能

一、功能概述 本笔记记录直接修改插件自带的场景播放其中 原始的 MediaPlayerUI 脚本,实现激活时自动重置播放器的功能。 我用的插件版本是 AVPro Video - Ultra Edition 2.7.3 修改后的脚本将具备以下特性: 激活 GameObject 时自动重置播放位置到开头 可配置是否在重置后自…

C#命名类型前缀习惯改进

我这几天有一个疑惑,我之前用过一些变量命名,有些混乱,如string sql,string strSql,string sqlStr, string strName,string nameStr,bool boValid,stringbuilder sbFileN…

生成式AI如何重塑设计思维与品牌创新?从工具到认知革命的跃迁

当MidJourney生成的视觉方案出现在国际设计奖项的决赛名单,当Adobe Firefly成为设计师的标配工具,一个问题正从行业边缘走向中心:生成式人工智能(GAI)究竟在解构还是重构创意领域?作为深度参与AI与设计融合…

零知开源——STM32F407VET6驱动Flappy Bird游戏教程

简介 本教程使用STM32F407VET6零知增强板驱动3.5寸TFT触摸屏实现经典Flappy Bird游戏。通过触摸屏控制小鸟跳跃,躲避障碍物柱体,挑战最高分。项目涉及STM32底层驱动、图形库移植、触摸控制和游戏逻辑设计。 目录 简介 一、硬件准备 二、软件架构 三、…

超高频RFID读写器天线分类及应用场景

超高频RFID(Radio Frequency Identification,射频识别)技术作为一种先进的自动识别技术,已经在多个领域得到了广泛应用。作为RFID系统的重要组成部分,超高频RFID读写器天线不仅影响着系统的读取距离、读取速度和准确性,还决定了RFID系统的适应性和灵活性。本文将详细介绍…

第J2周:ResNet50V2算法实战与解析

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 batch_size32:每次训练取32张图像组成一个 batch img_size(224, 224):图像输入大小匹配 ResNet50 的输入要求 epochs10:训练…

界面控件DevExpress WinForms中文教程:Banded Grid View - 如何固定Bands?

DevExpress WinForms拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜…

安全帽检测

通过百度网盘分享的文件:工地项目 链接:https://pan.baidu.com/s/1pVxriAKKodwrcf_4Ou-OZg?pwdn2rv 提取码:n2rv --来自百度网盘超级会员V2的分享 YOLOv5训练自定义模型 YOLOv5需要安装pytorch、cuda、cudnn,可以参考我的环…

晨控CK-UR08与欧姆龙PLC配置Ethernet/IP通讯连接操作手册

晨控CK-UR08与欧姆龙PLC配置Ethernet/IP通讯连接操作手册 晨控CK-UR08系列作为晨控智能工业级别RFID读写器,支持大部分工业协议如RS232、RS485、以太网。支持工业协议Modbus RTU、Modbus TCP、Profinet、EtherNet/lP、EtherCat以及自由协议TCP/IP等。 本期主题:围绕…

windows无法安装到这个磁盘,选中的磁盘采用gpt分区仪式

解决办法: 我才用的是一个网友分享的微软官方解决办法,成功了,但是不知道会不会i有什么影响。将所有分区删掉,这时磁盘变成为分配的空间。我个人是两块固态,一块m.2,一块sata;所以我直接将500g…

JVM内存模型

JVM内存模型 说明: 1、JVM由装载子系统、运行时数据区(jvm内存模型)、字节码执行引擎; 2、运行时数据区包含堆、元空间、栈、本地方法栈和程序计数器; 3、堆、元空间是线程共享;方法栈、程序计数器是线程…

【Python】第一弹:对 Python 的认知

目录 一、Python 的背景 1.1. Python 的由来 1.2 Python 的作用 1.3 Python 的优缺点 1.4 Python 的开发工具 一、Python 的背景 1.1. Python 的由来 Python 由荷兰数学和计算机科学研究学会的吉多・范罗苏姆 (Guido van Rossum)在 20 世纪 80 年代…

动态规划基础

动态规划是一种算法思想,关键是理解思想和什么时候用。 算法思想 动态规划用于解决多阶段决策最优化问题,这类问题类似递推。 1.阶段 将问题分为多个阶段,每个阶段之间有联系,即可递推。一般可按问题求解次序或问题的递归性质划…

WEB3——什么是ABI

怎么获得ABI? 在编译完合约后,可以在左边下面点击复制ABI ABI(Application Binary Interface,应用二进制接口)是用来让前端或服务端 JavaScript 代码与智能合约进行交互的桥梁,它描述了合约的函数、事件和…

本地部署Ollama DeepSeek-R1:8B,接入Cherry Studio

本地部署Ollama DeepSeek-R1:8B,接入Cherry Studio 本教程为本地部署ollama 环境,运行deepseek-r1:8B 模型,并完成cherry studio接入调用。 实现无网环境也可提问模型 一、ollama 环境安装 通过网盘分享的文件:OllamaSetup.ex…

彻底解决Win11文件资源管理器预览窗格无法预览问题

国内某几个流氓软件(W*S、*狗PDF...),耗子尾之!!! (转载)Windows中PDF TXT Excel Word PPT等Office文件在预览窗格无法预览的终级解决方法大全 https://zhuanlan.zhihu.com/p/4542…