FreeRTOS入门基础

RTOS是为了更好地在嵌入式系统上实现多任务处理和时间敏感任务而设计的系统。它能确保任务在指定或预期的时间内得到处理。FreeRTOS是一款免费开源的RTOS,它广泛用于需要小型、预测性强、灵活系统的嵌入式设备。

创建第一个任务

  1. 任务函数:任务是通过函数来定义的。函数通常看起来像这样的无限循环
       void vTaskFunction( void * pvParameters ){for( ;; ){// 任务代码}}

  2. 创建任务:使用xTaskCreate()函数来创建一个任务。
       xTaskCreate(vTaskFunction,       // 任务函数"TaskName",          // 任务名称STACK_SIZE,          // 堆栈大小NULL,                // 参数TASK_PRIORITY,       // 任务优先级NULL );              // 用来传回创建的任务的句柄

  3. 启动调度器:创建任务后,需要启动调度器,这样RTOS就能开始管理这些任务了。
       vTaskStartScheduler();

freertos基本组件

FreeRTOS作为一个实时操作系统(RTOS),提供了多种基础组件来组织代码并有效地管理任务。以下是一些FreeRTOS的基本组件:

  1. 任务 (Tasks):

    • 任务是FreeRTOS中的基本执行单位,相当于一个独立的线程。每个任务都有自己的优先级,调度器根据这些优先级来决定运行哪个任务。
  2. 队列 (Queues):

    • 队列用于在任务之间发送和接收数据。它们可以帮助实现任务同步,并提供一种安全传递消息的方法,如事件、内存块等。
      #include "FreeRTOS.h"
      #include "queue.h"// 队列句柄,用于后续的队列操作如发送和接收
      QueueHandle_t xQueue;// main() 或者任何初始化函数中
      void main() {// 创建一个可以存储10个元素的队列,每个元素大小为sizeof( BaseType_t )xQueue = xQueueCreate(10, sizeof(BaseType_t));if (xQueue == NULL) {// 队列创建失败,可能是由于内存不足// 错误处理代码} else {// 队列成功创建// 可以继续使用队列}// ... 其余初始化代码 ...// 启动任务,开始调度器vTaskStartScheduler();// ... 其余代码 ...
      }

      在这个例子中:

    • xQueueCreate 函数的第一个参数(10)指定了队列能够存储的元素的数量。
    • 第二个参数(sizeof(BaseType_t))指定了队列中每个元素的大小。
    • 注意,在使用 xQueueCreate() 创建队列之前,必须确保已经调用了 vTaskStartScheduler(),因为队列的使用依赖于FreeRTOS的内存管理函数,它们在调度器启动时初始化。此外,创建队列通常在系统的初始化阶段进行,然后各个任务可以通过队列句柄进行数据的发送和接收。

       

      创建队列后,可以使用 xQueueSend()xQueueReceive() 等函数来在任务之间传递数据。如果队列创建成功,xQueueCreate() 将返回一个非NULL的 QueueHandle_t 句柄,用于后续的队列操作。如果内存不足或者有其他原因导致队列创建失败,则返回NULL。

  3. 信号量 (Semaphores):

    • 信号量是一种同步机制,可以用来控制对共享资源的访问,或者在任务之间同步操作。在FreeRTOS中有两种主要类型的信号量:二进制信号量和计数信号量。
      #include "FreeRTOS.h"
      #include "semphr.h"SemaphoreHandle_t xSemaphore = NULL;void main_demo( void )
      {// 二进制信号量创建xSemaphore = xSemaphoreCreateBinary();if (xSemaphore != NULL){// 信号量创建成功,可以被使用}else{// 信号量创建失败,处理错误情况}// ...// 后续代码,如启动调度器和任务等// ...
      }
      #include "FreeRTOS.h"
      #include "semphr.h"SemaphoreHandle_t xCountingSemaphore;void main_demo( void )
      {// 计数信号量创建,最大计数和初始计数xCountingSemaphore = xSemaphoreCreateCounting(maxCount, initialCount);if (xCountingSemaphore != NULL){// 信号量创建成功}else{// 信号量创建失败,处理错误情况}// ...// 后续代码,如启动调度器和任务等// ...
      }

      在计数信号量的创建中, maxCount 表示信号量能够达到的最大计数值,而 initialCount 是信号量的初始计数值。

       

      信号量通常用于同步任务或中断服务程序 (ISR),例如,保护共享资源,协调任务的执行,任务通知等。创建后的信号量句柄可以通过任务和中断服务程序进行给出 (Give) 和取得 (Take) 操作。

  4. 互斥量 (Mutexes):

    • 互斥量是特殊类型的信号量,专门用于管理资源访问。与二元信号量不同,互斥量具有所有权的概念,使其在处理优先级反转问题时更加有效。
  5. 定时器 (Timers):

    • 定时器可以在一个定义好的时间之后运行一个函数。FreeRTOS支持一次性定时器和周期性定时器。
      #include "FreeRTOS.h"
      #include "timers.h"TimerHandle_t xTimer;void vTimerCallback(TimerHandle_t xTimer)
      {// 这里处理定时器到期时的逻辑
      }void main_demo( void )
      {const TickType_t xTimerPeriod = pdMS_TO_TICKS( 1000 ); // 定时周期1000毫秒// 创建软件定时器xTimer = xTimerCreate("Timer",                // 定时器的文本名称,用于调试xTimerPeriod,           // 定时器的周期,以tick计数pdTRUE,                 // pdFALSE为单次定时器,pdTRUE为周期性定时器( void * ) 0,           // 可用于传递给回调函数的标识符,通常是NULLvTimerCallback          // 定时器到期时调用的回调函数);if (xTimer == NULL){// 定时器创建失败,可能是由于内存不足}else{// 定时器创建成功,可以启动定时器if (xTimerStart(xTimer, 0) != pdPASS){// 定时器启动失败}}// ...// 后续代码,如启动调度器和任务等// ...
      }

      在这个例子中:

    • 第一个参数("Timer")是定时器名称。
    • 第二个参数(xTimerPeriod)设置定时器周期,通过pdMS_TO_TICKS宏转换了毫秒到tick。
    • 第三个参数指定了定时器是单次的 (pdFALSE) 还是自动重载的周期性定时器 (pdTRUE)。
    •  

      定时器创建后,你需要调用xTimerStart()函数来启动定时器,此后定时器将按照设定的周期运行。在资源有限的嵌入式系统里,软件定时器是一种资源节约的实现定时功能的方式,因为你可以在一个定时服务中管理多个定时器,而无需为每个定时任务创建单独的线程。

    • 第四个参数是指针,它会被传递给定时器回调函数,可以用作计数器或存储状态信息。
    • 第五个参数是定时器到期时调用的回调函数。
  6. 事件组 (Event Groups):

    • 事件组是一种可以等待或设置一组事件标志的机制。这允许任务在多种事件中等待任意组合的事件。
      #include "FreeRTOS.h"
      #include "event_groups.h"EventGroupHandle_t xEventGroup;void main_demo( void )
      {// 创建事件组xEventGroup = xEventGroupCreate();if(xEventGroup == NULL){// 事件组创建失败,通常是因为内核没有足够的可用堆空间// 错误处理代码}else{// 事件组成功创建,可以使用xEventGroup来设置、清除和等待事件标志}// ...// 启动任务和调度器等// ...
      }

      在这个例子中,xEventGroupCreate 用于创建一个新的事件组,并返回一个 EventGroupHandle_t 类型的句柄,以供后续的事件组操作使用。如果事件组创建失败,则返回 NULL,通常是由于内存不足。

       

      成功创建事件组后,可以使用如下函数操作事件标志:

    • xEventGroupSetBits:设置事件组中的一个或多个事件标志。
    • xEventGroupClearBits:清除事件组中的一个或多个事件标志。
    • xEventGroupWaitBits:等待事件组中的一个或多个特定事件标志变为设置状态。
    • 事件组是处理多个任务和中断共享状态或事件同步时的一个非常有用的工具,能够以线程安全的方式进行复杂的事件标志操作。
  7. 任务通知 (Task Notifications):

    • 任务通知是一种轻量级的信号量替代方式,可以快速地向任务发送信号。
    • 发送任务通知

      // 取得需要通知的任务的句柄,可以在任务创建时获取
      TaskHandle_t xTaskToNotify = ...;// 发送通知给任务,'ulValue' 是通知值
      uint32_t ulValue = 10;
      BaseType_t xHigherPriorityTaskWoken = pdFALSE; // 仅在中断服务程序中使用// 任务级代码
      xTaskNotify(xTaskToNotify, ulValue, eSetValueWithOverwrite);// 或者在 ISR 中
      xTaskNotifyFromISR(xTaskToNotify, ulValue, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
      portYIELD_FROM_ISR( xHigherPriorityTaskWoken );

      在上面的代码中,xTaskToNotify 是要接收通知的任务的句柄。ulValue 是要发送的通知值。eSetValueWithOverwrite 指示即使之前的通知未被任务接收,也将覆盖通知值。

    • 等待任务通知

      // 该变量将接收通知值
      uint32_t ulNotificationValue;
      BaseType_t xResult;// 等待通知
      xResult = xTaskNotifyWait(0x00,          // 在进入等待时不清除任何位ULONG_MAX,     // 在退出等待时将清除所有位&ulNotificationValue,  // 存储接收到的通知值portMAX_DELAY); // 一直等待直到接收到通知if(xResult == pdPASS)
      {// 任务接收到通知,`ulNotificationValue` 包含收到的值
      }

      在上面的等待通知代码中,xTaskNotifyWait 第一个参数为零表示调用任务进入等待通知状态时,不清除任务的任何通知状态位。第二个参数 ULONG_MAX 表示调用任务在接收到通知时将清除任务的所有通知状态位。第四个参数是阻塞时间,这个例子中使用 portMAX_DELAY,任务会无限期地等待直到收到通知。

       

      通过 xTaskNotifyGive 和 ulTaskNotifyTake 的组合,任务通知机制也可以模仿二进制信号量的行为。任务通知作为一种轻量级的同步机制,在许多场合可以替代信号量和事件组,以节省系统资源。

资源地址

FreeRTOS - Market leading RTOS (Real Time Operating System) for embedded systems with Internet of Things extensions

 Free RTOS Book and Reference Manual

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

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

相关文章

python的集合应用

在Python中,集合是一种无序、可变的数据类型,用于存储不重复的元素。Python提供了内置的集合类型 set,以及 frozenset(不可变的集合)。以下是一些Python集合的常见应用场景: 去重: 集合是存储唯…

ChatGPT:论文写作的新潮解决方案

ChatGPT无限次数:点击直达 摘要: 本文介绍了一种新潮的论文写作解决方案——ChatGPT。ChatGPT是基于模型的自然语言处理技术,它通过生成人类般的语言来帮助用户撰写高质量的论文。本文通过多个示例演示了ChatGPT的强大功能,并探讨了其在论文写…

Spark 用AnyFunSuite单元测试Scala详细教程

在用java开发时&#xff0c;通过用Junit框架来测试&#xff0c;在用spark开发scala时&#xff0c;除了可以用Junit&#xff0c;还可以用AnyFunSuite&#xff0c;无需依赖AnyFunSuite。 步骤一&#xff1a;设置项目依赖 确保您的项目中包含了以下必要的依赖&#xff1a; <d…

【HTML】HTML表单8.2(表单标签2)

目录 接上期&#xff0c;大致实现效果 文章简要 注释&#xff1a;这一次介绍的很多效果需要后期与服务器配合&#xff0c;但我们这里先只介绍效果 ①提交按钮 ②获取验证码 ③上传文件 ④还原所有表单内容 ⑤下拉表单 ⑥文字域 接上期&#xff0c;大致实现效果 文章简要 注…

matlab中Signal Editor定义梯形信号输出矩形信号

matlab中Signal Editor定义梯形信号输出矩形信号&#xff0c;可以通过如下勾选差值数据实现梯形信号输出。

GPT-1, GPT-2, GPT-3, InstructGPT / ChatGPT and GPT-4 总结

1. GPT-1 What the problem GPT-1 solve? 在 GPT-1 之前&#xff0c;NLP 通常是一种监督模型。 对于每个任务&#xff0c;都有一些标记数据&#xff0c;然后根据这些标记数据开发监督模型。 这种方法存在几个问题&#xff1a;首先&#xff0c;需要标记数据。 但 NLP 不像 CV&…

云原生部署手册02:将本地应用部署至k8s集群

&#xff08;一&#xff09;部署集群镜像仓库 1. 集群配置 首先看一下集群配置&#xff1a; (base) ➜ ~ multipass ls Name State IPv4 Image master Running 192.168.64.5 Ubuntu 22.04 LTS1…

栈队列数组试题(四)——数组和特殊矩阵

01&#xff0e;对特殊矩阵采用压缩存储的主要目的是( D ). A.表达变得简单 B.对矩阵元素的存取变得简单 C.去掉矩阵中的多余元素 D.减少不必要的存储空间解析&#xff1a;特殊矩阵中含有很多相同元素…

Pyqt5专栏目录索引

文章目录 安装 Pyqt5 和 DesignerQt Designer教程Qt 官方文档及阅读方法主窗口按键&#xff08;Buttons&#xff09;项目视图&#xff08;Item Views&#xff09;输入控件&#xff08;Input Widgets&#xff09;显示控件&#xff08;Display Widgets&#xff09;弹出框音频播放…

iOS——【Blocks】

Blocks概要 Blocks是C语言的扩充功能&#xff0c;即带有自动变量的匿名函数。匿名函数就是不带函数名的函数。这一概念同样被称为“闭包”&#xff0c;lambda计算等。 自动变量是在函数内部声明的变量&#xff0c;其作用域仅限于声明它的函数内部。这意味着它们只能在其声明的…

一. 并行处理与GPU体系架构-GPU并行处理

目录 前言0. 简述1. 这个小节会涉及到的关键字2. CPU与GPU在并行处理的优化方向3. Summary总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习下课程第一章——并行处理与GPU体…

Google云计算原理与应用(三)

目录 五、分布式存储系统Megastore&#xff08;一&#xff09;设计目标及方案选择&#xff08;二&#xff09;Megastore数据模型&#xff08;三&#xff09;Megastore中的事务及并发控制&#xff08;四&#xff09;Megastore基本架构&#xff08;五&#xff09;核心技术——复制…

pom.xml中的配置无法被yaml读取

问题描述 项目中指定了多个profiles, 但是application.yaml读取报错&#xff0c;报错信息如下 Standard Commons Logging discovery in action with spring-jcl: please remove commons-logging.jar from classpath in order to avoid potential conflicts 12:41:52.325 [mai…

数值分析复习:Newton插值

文章目录 牛顿&#xff08;Newton&#xff09;插值插值条件基函数插值多项式差商差商的基本性质差商估计差商的Leibniz公式 余项估计 本篇文章适合个人复习翻阅&#xff0c;不建议新手入门使用 牛顿&#xff08;Newton&#xff09;插值 插值条件 n1个插值节点 x 0 , x 1 , ……

使用 pnpm 搭建 monorepo 项目

引言 在我之前的开发经历中&#xff0c;并没有实际使用过 Monorepo 管理项目&#xff0c;尽管之前对此有所了解&#xff0c;但并未深入探究。然而&#xff0c;如今许多开源项目都采纳了 Monorepo 方式&#xff0c;对于不熟悉它的开发者来说&#xff0c;阅读和理解这些项目的源…

【HarmonyOS】ArkUI - 向左/向右滑动删除

核心知识点&#xff1a;List容器 -> ListItem -> swipeAction 先看效果图&#xff1a; 代码实现&#xff1a; // 任务类 class Task {static id: number 1// 任务名称name: string 任务${Task.id}// 任务状态finished: boolean false }// 统一的卡片样式 Styles func…

C语言快速入门之内存函数的使用和模拟实现

1.memcpy 它可以理解为memory copy的组合&#xff0c;memory有记忆的意思&#xff0c;这里指的是内存&#xff0c;copy是拷贝&#xff0c;这个函数是针对内存块进行拷贝的 函数原型 void* memcpy(void* destination,const void* source, size_t num); 从source位置开始&am…

ChatGPT国内镜像站大全

#今天在知乎看到一个问题&#xff1a;“平民不参与内测的话没有账号还有机会使用ChatGPT吗&#xff1f;” 从去年GPT大火到现在&#xff0c;关于GPT的消息铺天盖地&#xff0c;真要有心想要去用&#xff0c;途径很多&#xff0c;别的不说&#xff0c;国内GPT的镜像站到处都是&…

基于sortablejs实现拖拽element-ui el-table表格行进行排序

可以用原生的dragstart、drag、dragend、dragover、drop、dragleave实现这个效果&#xff0c;但是有现成的轮子就不要重复造了&#xff0c;看效果&#xff1a; <template><el-table :class"$options.name" :data"tableData" ref"table"…

Docker进阶教程 - 1 Dockerfile

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; 1 Dockerfile Dockerfile 是做什么的&#xff1f; 我们前面说到&#xff0c;制作镜像的方法主要有两种方式&#xff1a; 使用 docker commit 命令&#xff1b;使用 Dockerfile 文件。 但是…