FreeRTOS 从入门到精通-任务调度

news2025/1/23 10:29:49

初写FreeRTOS 从入门到精通系列文章之初,笔者只是当作可以随时回顾的学习笔记来写,并没有想到这些偏技术的文章收获了意料之外的阅读量和关注。首先当然很欣喜自己的文章能够得到了读者们的认可,但同时也有种使命感,既期望启迪并与大家共同提高嵌入式开发的技术,因此我会根据个人的体会和读者的反馈不时添加和补充理论篇文章的内容。相信读者通过系列文章只是了解理论的话都会有种意犹未尽的感觉吧。现在,笔者将结合自己的经验和所阅读的书籍内容,通过一些典型的代码来充分展示FreeRTOS操作系统的特性和能力。本人才疏学浅,这个实战篇系列也只是抛砖引玉。

读者须知

在实战篇系列的文章中,笔者的开发平台将采用ESP32平台。ESP32单片机相较传统的单片机多了WI-FI无线网和蓝牙的功能支持,同时具有更高的CPU处理速度和更大的SRAM存储空间,使之更适用于物联网(IoT),移动设备和可穿戴设备的应用场景。ESP32开发板可以使用Arduino IDE简单上手的开发环境,敏捷快速地用于产品原型机开发和功能验证,方便读者快速复现实战篇的内容。并且,ESP32是双核心芯片,可以用于测试验证FreeRTOS在多核心下的支持程度和性能表现。所有ESP32的代码经过简单修改适配都能运用在任意单片机平台上。

关于ESP32更多的内容以及如何搭建开发平台可以参考笔者的文章

奔腾的心:ESP32 IoT学习实战笔记1- 初识ESP32与搭建Arduino IDE开发环境3 赞同 · 0 评论文章​编辑

任务调度的概念

FreeRTOS对任务的调度采用基于时间片(time slicing)的方式。时间片,顾名思义,把一段时间等分成了很多个时间段,在每一个时间段保证优先级最高的任务能执行,同时如果几个任务拥有相等的优先级,则它们会轮流使用每个时间段占用CPU资源。调度器会在每个时间片结束的时候通过周期中断(tick interrupt)执行一次,调度器根据设置的抢占式还是合作式模式选择哪个任务在下一个时间片会运行。

时间片的大小由configTICK_RATE_HZ这个参数设置。如果configTICK_RATE_HZ设置为10HZ,则时间片的大小为100ms。configTICK_RATE_HZ的值由应用需求决定,通常设为100HZ(时间片大小相应为10ms)。

任务调度的演示

在上图任务调度的演示中,Kernel表示系统内核即调度程序,Task1和Task2是两个优先级相同的任务。t1到t2是一个时间片,t2到t3是另一个时间片。在每一个时间片快结束的时候,调度程序通过周期中断(tick interrupt)被调用并选择在下一个时间片要执行的任务(红色部分代表调度程序Kernel在运行)。此时因为两个任务的优先级相同,调度程序会让两个任务轮流占用时间片进行运行(蓝色部分代表Task1在运行,绿色部分代表Task2在运行)。

案例一

第一个案例将用于测量时间片(time slicing)的长度和看相同优先级的轮流调度

代码如下,可以直接复制到Arduino中运行

TaskHandle_t Task1;
TaskHandle_t Task2;
#define GPIO 16
#define PRIORITY 1 
#define APP_CPU 1

static void gpio_on(void *argp) {
  for (;;) {
    digitalWrite(GPIO,HIGH);
  }
}

static void gpio_off(void *argp) {
  for (;;) {
    digitalWrite(GPIO,LOW);
  }
}

void setup() {
  pinMode(GPIO,OUTPUT);
  delay(100);
  xTaskCreatePinnedToCore(
    gpio_on,
    "gpio_on",
    1024,
    NULL,
    PRIORITY,
    &Task1,
    APP_CPU
  );
  xTaskCreatePinnedToCore(
    gpio_off,
    "gpio_off",
    1024,
    NULL,
    PRIORITY,
    &Task2,
    APP_CPU
  );
}

void loop() {
  vTaskDelete(xTaskGetCurrentTaskHandle());
}

本例程创建了两个任务,gpio_on任务用于置IO16口为高,gpio_off任务用于置IO16口为低。ESP32有两个核心CPU0和CPU1, xTaskCreatePinnedToCore函数用把任务指定绑定某个核心运行。最后一个参数APP_CPU为1指定两个任务都在CPU1中运行。vTaskDelete函数用于删除任务,loop()循环中删除自身循环函数用于确保CPU1中只有gpio_on和gpio_off两个任务。因为两个任务的优先级PRIORITY都设置为1,所以调度器会轮流调度两个任务,调度的间隔便是时间片(time slicing)。

我们把IO16口接在示波器,在程序运行时可以关注到如下的波形图

案例一波形图

波形图中间隔为500微秒。可以观察到gpio_on的任务执行时间为1毫秒,gpio_off的任务执行时间为1毫秒,两个任务交替执行,调度器的执行时间可以忽略不计。由此可以推断FreeRTOS在ESP32的Arduino开发环境下时间片为1毫秒,这个又称为滴答周期(tick period)。理论上调度器在1秒至少可以执行1000次任务调度(如果任务在一个时间片内提前结束的话任务调度次数还会更多)

案例二

案例二相较于案例一稍微修改了gpio_on的任务内容,允许在任务内调用调度器直接进行任务切换

TaskHandle_t Task1;
TaskHandle_t Task2;
#define GPIO 16
#define PRIORITY 1 
#define APP_CPU 1

static void gpio_on(void *argp) {
  for ( short x=0; x<1000; ++x ){
    digitalWrite(GPIO,HIGH);
  }
  taskYIELD();
}

static void gpio_off(void *argp) {
  for (;;) {
    digitalWrite(GPIO,LOW);
  }
}

void setup() {
  pinMode(GPIO,OUTPUT);
  delay(100);
  xTaskCreatePinnedToCore(
    gpio_on,
    "gpio_on",
    1024,
    NULL,
    PRIORITY,
    &Task1,
    APP_CPU
  );
  xTaskCreatePinnedToCore(
    gpio_off,
    "gpio_off",
    1024,
    NULL,
    PRIORITY,
    &Task2,
    APP_CPU
  );
}

void loop() {
  vTaskDelete(xTaskGetCurrentTaskHandle());
}

案例二中gpio_on在执行1000次循环后通过taskYIELD函数调用调度器直接进行任务切换到gpio_off任务。

观察到的波形图如下

案例二波形图

波形图中间隔为200微秒,可以看到IO16口下降沿到上升沿之间的间隔小于时间片1毫秒。下降沿发生的时刻在gpio_on通过taskYIELD函数切换到gpio_off任务,然后gpio_off会在gpio_on所在时间片的剩余时间内进行执行直到下次时间片开始调度器重新进行调度。由此可以看出来,每个任务无法保证一定拥有一个完整的时间片。当一个任务在时间片内进行任务调度时,剩余相同优先级的任务会通过“Round Robin”轮流调度,直到下一个时间片开始重新调度。这是应该值得关注的一个现象。

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

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

相关文章

模型评估的常用指标

模型评估的指标 模型是在大量的数据集上训练而来的,无论一个模型是从零训练的还是基于某一个模型,通过微调方法得到的,靠人工评价模型的效果都是异常困难的。那么要想客观的、自动化的评价一个LLM模型,就需要能够选择正确评估模型效果的指标或者基准测试,来客观和自动化的…

C语言刷题指南(二)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

腾讯开启2024校招,主要招聘5大类岗位

近日&#xff0c;腾讯的大动作一个接一个&#xff0c;前脚刚公布2023上半年财报&#xff0c;后脚就开启了2024校招&#xff0c;不得不让人感叹腾讯真速度&#xff01; 此次招聘对象为毕业时间在2023年9月至2024年8月期间的2024届应届毕业生&#xff0c;覆盖北上广深等多个城市…

Python中定时任务APScheduler库用法详解

在日常工作中&#xff0c;常常会用到需要周期性执行的任务&#xff0c;一种方式是采用 Linux 系统自带的 crond 结合命令行实现。另外一种方式是直接使用Python。 当每隔一段时间就要执行一段程序&#xff0c;或者往复循环执行某一个任务&#xff0c;这就需要使用定时任务来执…

如何搭建游戏服务器?有哪些操作步骤

​  选择游戏服务器提供商 为确保游戏服务器的稳定运行和及时响应问题&#xff0c;选择一个正规、靠谱的游戏服务器提供商非常重要。 选择服务器操作系统 根据不同游戏的需求&#xff0c;选择适合的操作系统&#xff0c;通常可选择Linux或WindowsServer操作系统。 上传、安装…

智安网络|零信任安全框架:保障数字化时代网络安全的最佳实践

随着数字化时代的快速发展&#xff0c;网络安全问题变得越来越突出。传统的安全防御模式已经不再适用于现代复杂的网络环境中。为了应对日益增长的网络威胁&#xff0c;零信任安全模式应运而生。 一、什么是零信任&#xff1f; 零信任是一种安全框架和哲学&#xff0c;它基于…

【使用教程】在Ubuntu下运行CANopen通信PMM伺服电机使用教程(NimServoSDK_V2.0.0)

本教程将指导您在Ubuntu操作系统下使用NimServoSDK_V2.0.0来运行CANopen通信的PMM系列一体化伺服电机。我们将介绍必要的步骤和命令&#xff0c;以确保您能够成功地配置和控制PMM系列一体化伺服电机。 NimServoSDK_V2.0.0是一款用于PMM一体化伺服电机的软件开发工具包。它提供了…

第八章LVS中的DR模式详解

1&#xff0c;LVS-DR数据包的流向分析 总结&#xff1a; &#xff08;1&#xff09;客户端发送请求到 Director Server&#xff08;负载均衡器&#xff09;&#xff0c;请求的数据报文&#xff08;源 IP 是 CIP,目标 IP 是 VIP&#xff09;到达内核空间。 &#xff08;2&#…

机器学习基础之《分类算法(3)—模型选择与调优》

作用是如何选择出最好的K值 一、什么是交叉验证&#xff08;cross validation&#xff09; 1、定义 交叉验证&#xff1a;将拿到的训练数据&#xff0c;分为训练和验证集。以下图为例&#xff1a;将数据分成5份&#xff0c;其中一份作为验证集。然后经过5次(组)的测试&#x…

「UG/NX」Block UI 体收集器BodyCollector

✨博客主页何曾参静谧的博客📌文章专栏「UG/NX」BlockUI集合📚全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C+&#

springboot引入druid解析sql

一、前言 在开发中&#xff0c;有时我们可能会需要获取SQL中的表名&#xff0c;那么因为不同的数据源类型SQL会存在部分差异&#xff0c;那么我们就可以使用alibaba 的druid包实现不同的数据源类型的sql解析。 二、引入相关maven依赖 <dependency><groupId>com.a…

Python基础语法入门(第二十二天)——并发编程

在Python中&#xff0c;并发编程的实现有多种方式&#xff0c;包括多线程、多进程和异步编程。每一种方式都有其使用的场景和特点。那么如何去选择多线程、多进程和多协程呢&#xff1f;要知道如何选择的话就要了解一下什么是CPU密集型计算、什么是I/O密集型计算&#xff1b;多…

selenium +Jmeter 的性能测试

通过Jmeter快速将已有的Selenium 代码以性能测试的方式组织起来&#xff0c;并使用JMeter 丰富的报表展示测试结果 from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By driver …

JAVA基础知识(三)——数组

数组 数组一、数组的概述1.1 数组的定义1.2 数组的常见概念1.3 数组的特点1.4 数组的分类 二、一维数组的使用2.1 一维数组的声明和初始化2.2 数组的基本使用2.3 数组元素的默认初始化值2.4 数组的内存解析 三、多维数组的使用3.1 二维数组的理解3.2 二维数组的声明3.3 二维数组…

多家企业加入即将在2024年发射的量子卫星SpeQtral-1任务

近日&#xff0c;总部位于新加坡的量子通信技术公司SpeQtral宣布将与纳米航空电子公司NanoAvionics和卫星光子学公司Mbryonics合作执行即将到来的SpeQtral-1量子密钥分发&#xff08;Quantum Key Distribution, QKD&#xff09;卫星任务。NanoAvionics被选为卫星平台提供商&…

算法题面试实战收集

回文数字 2023-08-18 美团 一面 在不使用额外的内存空间的条件下判断一个整数是否是回文。 回文指逆序和正序完全相同。 数据范围&#xff1a; 进阶&#xff1a; 空间复杂度O(1) &#xff0c;时间复杂度 O(n) 提示&#xff1a; 负整数可以是回文吗&#xff1f;&#xff08;比如…

Python数据分析实战-多进程并发处理列表(附源码和实现效果)

实现功能 有15个列表&#xff0c;尝试多进程并发处理&#xff0c;每个列表一个进程&#xff0c;进程数和 CPU 核数一致 实现代码 import multiprocessing有15个列表&#xff0c;尝试多进程并发处理&#xff0c;每个列表一个进程&#xff0c;进程数和 CPU 核数一致def sum_li…

第P1周:实现mnist手写数字识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 我的环境&#xff1a; 语言环境&#xff1a;Python3.10.7编译器&#xff1a;VScode深度学习环境&#xff1a;TensorFlow 2.13.0 一、前期工作&#xff1a; …

Element Plus el-table 数据为空时自定义内容【默认为 No Data】

1. 通过 Table 属性设置 <div class"el-plus-table"><el-table empty-text"暂无数据" :data"tableData" style"width: 100%"><el-table-column prop"date" label"Date" width"180" /&g…

VR数字工厂多元化展现,打造数字企业工厂名片

5G时代&#xff0c;各种营销都在走数字化的路子&#xff0c;VR数字工厂用VR赋能工厂数字升级&#xff0c;将企业环境、工厂生产、产品研发、质检运输等流程&#xff0c;无死角720度的展示在客户面前&#xff0c;不仅可以提升自身企业的实力&#xff0c;还可以提高客户的信任感。…