FreeRTOS任务调度器

news2024/11/24 0:34:30

目录

1、什么是任务调度器

 2、FreeRTOS中的任务调度器

2.1 抢占式调度

2.2 时间片调度

2.3 协作式调度

3、任务调度案例分析

3.1 实验需求

3.2 CubeMX配置

3.3 代码实现

3.3.1 uart.c 重定向printf

3.3.2 打开freertos.c并添加代码

3.3.4 代码现象


1、什么是任务调度器

任务调度器是实时操作系统(RTOS)的一个关键组件,它负责决定在多个可运行任务中哪一个将获得CPU时间得以执行。它基于任务的优先级和状态来做出这些决定。

在一个RTOS中,可能会有多个任务同时运行,但是在任意时刻,CPU只能执行一个任务。任务调度器的主要目标是按照系统的需求合理分配CPU时间

调度器就是使用相关的调度算法来决定当前需要执行的哪个任务

基本功能

任务的选择任务调度器会根据预设的算法从所有可运行的任务中选择一个要执行的任务
任务的优先级任务通常会被分配一个优先级,优先级越高的任务在抢占式调度中会优先执行
任务状态管理任务可能处于就绪状态(可立即运行)、阻塞状态(等待某些条件满足)或者挂起状态(暂停执行)。
上下文切换任务调度器负责在不同任务之间进行上下文切换。这意味着将当前任务的状态保存起来,然后加载另一个任务的状态,以便它可以继续执行。
定时器管理任务调度器通常会关注系统中的定时器,以便能够在特定事件发生时唤醒相应的任务
中断处理任务调度器需要与系统的中断处理程序协同工作,以确保在中断上下文中也能够正常进行任务调度

 2、FreeRTOS中的任务调度器

FreeRTOS 是一个实时操作系统,它所奉行的调度规则:

1. 抢占式调度器:抢占式调度器是一种优先级基础的调度器,高优先级抢占低优先级任务,系统永远执行最高优先级的任务。

2. 时间片调度器:时间片轮转调度器是一种抢占式调度器,它将CPU时间划分成小的时间片段,每个任务在一个时间片段内运行

3. 协程式调度器:协作式调度器依赖于任务自行释放CPU,没有明确的任务优先级任务必须自愿放弃CPU控制权,以便其他任务能够运行。(但官方已明确表示不更新,主要是用在小容量的芯片上,用得也不多)

FreeRTOS中开启任务调度的函数是vTaskStartScheduler() ,但在CubeMX中被封装为osKernelStart() 。

2.1 抢占式调度

优点适用于实时要求严格的系统,可以确保高优先级任务及时响应。
缺点上下文切换的开销较大,可能会影响系统的性能。

        1. 任务优先级:每个任务都会被分配一个优先级。优先级较高的任务被认为更紧急,将会在可运行时抢占具有较低优先级的任务

        2. 抢占:当一个高优先级的任务准备好运行时,RTOS会暂停当前正在执行的低优先级任务,并将CPU的控制权转交给高优先级任务

        3. 上下文切换:在抢占发生时,RTOS会保存当前任务的上下文(包括寄存器状态等),然后加载高优先级任务的上下文,使其可以继续执行。这个过程称为上下文切换。

        4. 实时性:抢占式调度器可以保证高优先级任务能够及时响应紧急事件。这对于实时系统和需要快速响应的应用程序非常重要。

        5. 任务挂起:在抢占式调度中,可以随时挂起(暂停)一个任务,以便给更高优先级的任务让路。挂起(暂停)函数为vTaskSuspend(),恢复函数为vTaskResume()

        6. 任务阻塞:一个任务可以由于等待某些条件的发生而被阻塞。当这些条件满足时,RTOS会将其重新置为就绪状态

        7. 中断处理:抢占式调度需要能够在中断上下文中正确地处理任务的切换。

        8. 实时性保证:抢占式调度对于需要在严格的实时约束下工作的系统非常重要,因为它可以确保高优先级任务在预期的时间内得到处理。

总结:

  1. 高优先级任务,优先执行;
  2. 高优先级任务不停止,低优先级任务无法执行;
  3. 被抢占的任务将会进入就绪态。

2.2 时间片调度

优点适用于多个任务优先级相近的场景,可以避免某个任务长时间占用CPU。
缺点会引入一定的上下文切换开销。

        1. 时间片段:CPU的执行时间被划分成固定长度的时间片段。每个时间片段可以是几毫秒或者更短的时间,具体取决于系统的配置。

        2. 任务优先级:每个任务都被分配一个优先级。在一个时间片段内,具有相同优先级的任务会依次轮流执行。

        3. 抢占:当一个时间片段结束时,RTOS会暂停当前执行的任务,并将CPU的控制权转交给具有相同优先级的下一个任务。

        4. 上下文切换:在每个时间片段结束时,RTOS会进行上下文切换,将当前任务的状态保存起来,并加载下一个任务的状态,以便其可以继续执行。

        5. 公平分配CPU时间:时间片调度确保了每个任务在一定时间段内都有机会执行,从而实现了相对公平的CPU时间分配。

        6. 避免任务长时间占用CPU:时间片调度可以防止某个任务长时间占用CPU,从而保证了其他任务也有机会执行。

        7. 适用于优先级相近的任务:时间片调度特别适用于具有相近优先级的任务集,因为它可以确保它们在相对公平的条件下执行。

        8. 降低实时性:相比于抢占式调度,时间片调度可能会引入一定的上下文切换开销,从而降低了系统的实时性。

总结:

  1. 同等优先级任务,轮流执行,时间片流转;
  2. 一个时间片大小,取决为滴答定时器中断周期;
  3. 注意没有用完的时间片不会再使用,下次任务Task3得到执行,还是按照一个时间片的时钟节拍运行。

2.3 协作式调度

        1. 任务自主控制:在协作式调度中,任务负责自己的执行时间任务在需要让出CPU时,会主动调用RTOS提供的让出控制权的函数

        2. 没有明确的任务优先级:协作式调度中通常没有明确的任务优先级概念。所有的任务被视为平等,没有任务可以强制其他任务停止执行。

        3. 低上下文切换开销:相比抢占式调度,协作式调度通常具有更低的上下文切换开销,因为任务只有在愿意让出CPU时才会发生切换

        4. 任务合作:任务之间需要合作以确保系统的正常运行。如果一个任务长时间占用CPU,其他任务可能会受到影响。

        5. 适用于资源受限的系统:协作式调度适用于资源有限的嵌入式系统,因为它减少了抢占式调度中的上下文切换开销。

        6. 可能导致响应性降低:如果一个任务不合作,即使有更高优先级的任务需要执行,也可能导致响应性降低,因为任务不会主动让出CPU。

        7. 任务挂起和任务阻塞:虽然没有抢占,但任务仍然可以被挂起(暂停)或者阻塞,等待某些条件的发生。

3、任务调度案例分析

3.1 实验需求

创建 4 个任务:taskLED1,taskLED2,taskKEY1,taskKEY2,任务要求如下:

taskLED1:间隔 500ms 闪烁 LED1;

taskLED2:间隔 1000ms 闪烁 LED2;

taskKEY1:如果 taskLED1 存在,则按下 KEY1 后删除 taskLED1 ,否则创建 taskLED1 ;

taskKEY2:如果 taskLED2 正常运行,则按下 KEY2 后挂起 taskLED2 ,否则恢复 taskLED2。

3.2 CubeMX配置

查看原理图配置按键跟LED灯引脚

这里已经将FreeRTOS移植到STM32F103C8T6,具体操作流程看前面的文章。

串口配置

创建任务

点击add即可添加任务并修改参数配置,注意:其中任务的优先级从上往下越来越高,设置成Normal即可,同时Entry Fuction为函数指针,固定格式是Start+函数名字(函数名字首个字母需要大写)

3.3 代码实现

3.3.1 uart.c 重定向printf
#include "stdio.h"
int fputc(int ch,FILE *f)
{
	unsigned char temp[1] = {ch};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);
	return ch;
}

需要打开魔术棒勾上红框内选项实现串口打印

3.3.2 打开freertos.c并添加代码
void StartTaskLED1(void const * argument)
{
  for(;;)
  {
		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
    osDelay(500);
  }
}
 
void StartTask02(void const * argument)
{
  for(;;)
  {
		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9);
    osDelay(1000);
  }
}
 
void StartTaskKey1(void const * argument)
{
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET)
			{
				printf("KEY1被按下!!!\r\n");
				if(task_LED1Handle == NULL)	//在上面任务创建会返回一个句柄,判断句柄是否为NULL																				
				{
					printf("任务1不存在,准备创建任务1\r\n");	//为NULL说明任务1不存在												
					osThreadDef(task_LED1, StartTask_LED1, osPriorityNormal, 0, 128); //调用上面任务创建函数
					task_LED1Handle = osThreadCreate(osThread(task_LED1), NULL);
					if(task_LED1Handle != NULL)	//此时任务1创建成功,句柄不为NULL																			
						printf("任务1创建完成!\r\n");
				}
				else
				{
					printf("删除任务1!\r\n");
					osThreadTerminate(task_LED1Handle);	//调用删除任务函数,参数为任务返回的句柄															
					task_LED1Handle = NULL;	//手动将句柄置为NULL,否则后面调用到此句柄会有意外					 																
				}
			}
			while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET);	//若按键一直处于按下状态则处于死循环,即松手检测									
		}
    osDelay(10);
  }
 
void StartTaskKey2(void const * argument)
{
	static int flag = 0;	
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
		{
			osDelay(20); // 延时消抖
            if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
            {
    			printf("Key2 被按下\r\n");
		    	if(flag == 0)
		    	{
			    	osThreadSuspend(TaskLED2Handle);//调用任务挂起函数
			    	printf("任务2被挂起暂停\r\n");
			    	flag = 1;
			    }
			    else
			    {
			    	osThreadResume(TaskLED2Handle);//调用任务恢复函数
			    	printf("任务2重新恢复\r\n");
			    	flag = 0;
		    	}
           }
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET);
		}
        osDelay(10);
  }
}

上述代码中:

osThreadTerminate()为删除函数,osThreadSuspend()为挂起函数,osThreadResume()为恢复函数。(这些函数与前面所学的不一样,因为他们都是CubeMX的内置函数)

下图为创建任务后各个任务的句柄和CubeMX创建任务函数。

3.3.4 代码现象

按下KEY1任务1删除(LED1保持不变),再次按下任务1创建(LED1闪烁);按下KEY2任务2挂起(LED2保持不变),再次按下任务2恢复(LED2闪烁)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1660853.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

苹果电脑免费第三方软件CleanMyMac X2025电脑版垃圾清理软件神器

Mac电脑用户在长时间使用电脑之后,时常会看到“暂存盘已满”的提示,这无疑会给后续的电脑使用带来烦恼,那么苹果电脑暂存盘已满怎么清理呢,下面将给大家带来一些干货帮你更好地解决这个问题。 CleanMyMac X2024全新版下载如下: h…

【C++】list的使用与模拟实现

🔥个人主页:北辰水墨 🔥专栏:C学习仓 本节内容我们来讲解list的使用和模拟实现。 本节难点:list迭代器的模拟实现。 一、list的介绍: 列表 列表是一种序列容器,允许在序列的任何位置进行时间复…

winform植物大战僵尸

winform植物大战僵尸 植物大战僵尸源码 半成品 需要的拿去学习 登陆注册选择关卡 向日葵 豌豆射手 双枪豌豆射手 项目获取: 项目获取:typora: typora/img (gitee.com) 备用项目获取链接1:yifeiyixiang/kamo: 源码下载 (github.com) 备用…

Python图形复刻——绘制母亲节花束

各位小伙伴,好久不见,今天学习用Python绘制花束。 有一种爱,不求回报,有一种情,无私奉献,这就是母爱。祝天下妈妈节日快乐,幸福永远! 图形展示: 代码展示: …

一定行:从零起步进入Java世界

郑重声明:本篇博客唯一目的就是带你从零起步,成功编写并运行你的第一个Java应用。 零:先给祖师爷来上柱香 Java之父简介 英文名:James Gosling中文名:詹姆斯高斯林祖籍:加拿大出生年:1955照片…

INS 论文分享:一种用于交通流预测的多通道时空Transformer模型

本文主要介绍了我们在长期交通流预测方面的最新研究成果,该成果已发表在信息学领域的顶级期刊《Information Sciences》上,论文题目为《A Multi-Channel Spatial-Temporal Transformer Model for Traffic Flow Forecasting》。该论文的第一作者及通讯作者…

Android项目转为鸿蒙,真就这么简单?

最近做了一个有关Android转换成鸿蒙的项目。经不少开发者的反馈;许多公司的业务都增加了鸿蒙板块。 对此想分享一下这个项目转换的流程结构,希望能够给大家在工作中带来一些帮助。转换流程示意图如下: 下面我就给大家介绍,Android…

Android 屏幕适配全攻略(上)-掌握屏幕单位,应对千变万化的设备

本文从 Android 开发中常见的长度单位 px、dp、sp 入手,详细介绍了它们的特点及转换关系。 接着深入探讨了屏幕尺寸、分辨率、像素密度等重要的屏幕指标,帮助读者全面理解它们之间的联系。最后,通过实例代码演示了如何在代码中进行单位转换&…

UE4\UE5 调试源代码流程(重点讲不去Github装源代码情况)

UE4\UE5 调试源代码流程 前言: 很多写UE C代码的小伙伴,肯定发现了,在虚幻源代码里面是没办法打断点进行调试的,就算走Debug调试流程,也依旧不能正常打断点调试,今天我们来分享一下不装Github源代码情况下…

Python语言基础学习(上)

目录 一、常量和表达式 二、变量和类型 2.1 认识变量 2.2 定义变量 2.3 变量类型 1、整数 int 2、浮点数(小数)float 3、字符串 str 4、布尔类型 2.4 类型转换 三、注释 3.1 单行注释 3.2 文档注释(或者多行注释) …

五金建材微信小程序商城系统开发搭建指南

如今,随着移动互联网的发展,小程序成为了商家们开拓新市场、增加收益的重要途径。特别是对于五金店这类实体店铺来说,通过小程序开设线上商城,不仅可以提升品牌影响力,还能够实现线上线下的无缝对接,为店家…

二、SPI协议

文章目录 总述1.SPI接口2. SPI工作模式3. SPI通信时序4. SPI协议 对比 UART协议(上一篇文章刚介绍过uart协议,这里来对比一下) 总述 SPI(Serial Peripheral Interface)是一种高速的、全双工、同步的串行通信总线&…

2024智能投影仪怎么选?大眼橙C1D,高清高亮高性价比

在这个科技飞速发展的时代,家庭智能化已经成为一种趋势。大眼橙C1D,2024年最新上市的一款智能投影仪,正以其独特的魅力,引领着智能家居的新潮流。 一、外观设计:简约而不简单 大眼橙C1D的外观设计采用了简约风格&…

pdffactory pro8.0虚拟打印机(附注册码)

PdfFactory pro是一款非常受欢迎的PDF虚拟打印机,可以帮助用户将你的其他文档保存为PDF格式。请为用户提供打印/发送/加密等多种实用功能,以及一套完善的PDF打印方案。 使用说明 下载pdfFactory Pro压缩包,解压后,双击exe文件&am…

2024数维杯A题可运行思路代码文章成品

为了能够精确地确定飞行器在三维空间中的位置,理论上至少需要从三个不同位置的发射源接收TOA数据。下面是使用TOA数据确定位置所需的计算基础和原理: 单个TOA数据: 单个TOA测量可以确定接收器与发射源之间的距离,这在三维空间中形…

error C2039: “NotifySeverity“: 不是 “osg“ 的成员 问题分析

程序从osg3.6.5Qt5.9osgearth2.10环境中移植到osg3.7.0Qt5.15.2osgearth3.3环境中,出现了无尽的错误。 有些错误很莫名奇妙,比如下述错误: D:\OsgEarth3.3\include\osgEarth\Notify(34,53): error C2039: "NotifySeverity": 不是 &…

Vue3专栏项目 -- 二、自定义From组件(下)

需求分析: 现在我们还需要一个整体的表单在单击某个按钮的时候可以循环的验证每个input的值,最后我们还需要有一个事件可以得到最后验证的结果,从而进行下一步的操作 如下,我们应该有一个form表单包裹着全部的input表单&#xf…

分布式模式让业务更高效、更安全、更稳定

​🌈 个人主页:danci_ 🔥 系列专栏:《设计模式》 💪🏻 制定明确可量化的目标,坚持默默的做事。 🚀 转载自热榜文章🔥:探索设计模式的魅力:分布式模…

ICode国际青少年编程竞赛- Python-4级训练场-while语句入门

ICode国际青少年编程竞赛- Python-4级训练场-while语句入门 1、 while Flyer.disappear():wait() Dev.step(2)2、 Dev.step(1) while Flyer.disappear():wait() Dev.step(5)3、 while Flyer[0].disappear():wait() Dev.step(3) Dev.step(-1) while Flyer[0].disappear():…

VM虚假机联网(无代码,超简单)NAT模式

1、左边顶上编辑里面最下面找到虚拟网络编辑器2.启用管理员特权3.重新创建一个NAT模式的网络(名称随便一个) 4.打开这两个设置里面的东西进行拍照并记住IP区间和网关,等下要用; 5.打开虚拟机,右上角,下标点…