FreeRTOS入门(07):流缓冲区 & 消息缓冲区

2023-11-12

目的

缓冲区是操作系统中常见的一种用于任务间数据传递的机制。这篇文章将对FreeRTOS中相关内容做个介绍。

本文代码测试环境见前面的文章:《FreeRTOS入门(01):基础说明与使用演示》

基础说明

FreeRTOS中的缓冲区是v10.0.0新加入的功能,可能该功能还在调整中,部分内容官方文档和实际的库中有些出入。

缓冲区相当于一片共享的内存,一方面中断和任务中都可以向里面写输入,另一方面中断和任务也可以从里面读数据。这在一些现有的机制不能满足或者大数据传输时比较有用。不过需要注意的是目前FreeRTOS中的缓冲区并不是完全是线程安全的,使用是需要特别注意。

流缓冲区 有一个叫做 触发等级 的参数,只有当向流缓冲区写入数据后,缓冲区中可读数据大于等于触发等级时,才可以从中读取数据,否则将阻塞。但是只要可读取后便可多次读取直到没有数据可读为止。

消息缓冲区 是建立在流缓冲区之上的,但是提供了另外一种机制。每次向消息缓冲区发送的消息都会成为一个消息包。当消息缓冲区中有消息包便可以读取。每次触发读取都是以包为单位读取的。

使用消息缓冲区需要特别注意两点:1、每次向消息缓冲区发送数据时都会额外占用一定空间用于记录这条消息的长度(对于32架构来说将额外占用4字节);读取时以完整的包形式读取,如果接收缓存的长度不足,则一个字节都不会接受,也不会阻塞,会直接返回接收0字节,并且消息缓冲区这条消息还存在,等待下一次接收。

FreeRTOS的缓冲区有 sbSEND_COMPLETED()sbRECEIVE_COMPLETED() 两个宏用来处理发送和接收完成后的额外操作,你可以自行定义这两个宏具体的功能,也可以不管,FreeRTOS默认已经封装了一些基础的操作。

流缓冲区

相关函数

// 创建流缓冲区
// xBufferSizeBytes表示流缓冲区容量(字节)
// xTriggerLevelBytes读取等待字节数(触发等级),如果写0会被重置为1
StreamBufferHandle_t xStreamBufferCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes );

// 删除流缓冲区
void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer );

// 向流缓冲区写数据,如果空间不足无法写入将阻塞直至超时
// pvTxData为要写入的消息首指针
// xDataLengthBytes为要写入的消息长度,写入时会额外占用sizeof(size_t)字节空间,对于32架构来说将额外占用4字节
// 返回写入字节数
size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t xDataLengthBytes, TickType_t xTicksToWait );
// 写数据中断版本,不会阻塞
size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t xDataLengthBytes, BaseType_t *pxHigherPriorityTaskWoken );

// 从流缓冲区读数据,如果没有数据可读取将阻塞直至超时
// pvRxData为要接收数据的数组首指针
// xBufferLengthBytes接收消息的数组长度
// 返回读取字节数
size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t xBufferLengthBytes, TickType_t xTicksToWait );
// 读数据中断版本,不会阻塞
size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t xBufferLengthBytes, BaseType_t *pxHigherPriorityTaskWoken );

// 返回缓冲区可读字节数
size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer );
// 返回缓冲区可写字节数
size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer );
// 查看缓冲区是否为空
BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer );
// 查看缓冲区是否已满
BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer );

// 设置缓冲区触发等级
BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel );
// 将缓冲区重置为空,只有缓冲区没有在使用时才可设置
BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer );

使用演示

#include "debug.h"
#include "FreeRTOS.h"      // 引入头文件
#include "task.h"          // 引入头文件
#include "stream_buffer.h" // 引入头文件

StreamBufferHandle_t xStreamBuffer; // 流缓冲区句柄

void task1(void *pvParameters) {
    uint8_t data[4] = {1, 2, 3, 4};
    while(1) {
        vTaskDelay(500);
        xStreamBufferSend(xStreamBuffer, data, 4, portMAX_DELAY); // 发送数据
    }
}

void task2(void *pvParameters) {
    while(1) {
        uint8_t data[5] = {0};
        size_t len = xStreamBufferReceive(xStreamBuffer, data, 5, portMAX_DELAY); // 等待数据可接收
        printf("%u task2 len: %u  data: %u %u %u %u %u \r\n", xTaskGetTickCount(), len, data[0], data[1], data[2], data[3], data[4]);
    }
}

int main(void) {
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    SystemCoreClockUpdate();
    Delay_Init();
    USART_Printf_Init(115200);

    xStreamBuffer = xStreamBufferCreate(128, 5); // 这里设置触发等级为5

    xTaskCreate(task1, "task1", 256, NULL, 5, NULL);
    xTaskCreate(task2, "task2", 256, NULL, 5, NULL);

    vTaskStartScheduler(); // 任务调度,任务将在这里根据情况开始运行,程序将在这里无序循环

    while(1) {} // 程序不会运行到这里
}

在这里插入图片描述

消息缓冲区

相关函数

// 创建消息缓冲区
MessageBufferHandle_t xMessageBufferCreate( size_t xBufferSizeBytes );

// 删除消息缓冲区
void vMessageBufferDelete( MessageBufferHandle_t xMessageBuffer );

// 向消息缓冲区写数据,如果空间不足无法写入将阻塞直至超时
// pvTxData为要写入的消息首指针
// xDataLengthBytes为要写入的消息长度,每次写入时会额外占用sizeof(size_t)字节空间,对于32架构来说将额外占用4字节
size_t xMessageBufferSend( MessageBufferHandle_t xMessageBuffer, const void *pvTxData, size_t xDataLengthBytes, TickType_t xTicksToWait );
// 写数据中断版本,不会阻塞
size_t xMessageBufferSendFromISR( MessageBufferHandle_t xMessageBuffer, const void *pvTxData, size_t xDataLengthBytes, BaseType_t *pxHigherPriorityTaskWoken );

// 从消息冲区读数据,如果没有数据可读取将阻塞直至超时
// pvRxData为要接收数据的数组首指针
// xBufferLengthBytes接收消息的数组长度
// 返回读取字节数
// 从消息缓冲区中读取数据是以一个个消息为单位进行读取的
size_t xMessageBufferReceive( MessageBufferHandle_t xMessageBuffer, void *pvRxData, size_t xBufferLengthBytes, TickType_t xTicksToWait );
// 读数据中断版本,不会阻塞
size_t xMessageBufferReceiveFromISR( MessageBufferHandle_t xMessageBuffer, void *pvRxData, size_t xBufferLengthBytes, BaseType_t *pxHigherPriorityTaskWoken );

// 返回缓冲区可写字节数
size_t xMessageBufferSpacesAvailable( MessageBufferHandle_t xMessageBuffer );
// 查看缓冲区是否为空
BaseType_t xMessageBufferIsEmpty( MessageBufferHandle_t xMessageBuffer );
// 查看缓冲区是否已满
BaseType_t xMessageBufferIsFull( MessageBufferHandle_t xMessageBuffer );

// 将缓冲区重置为空,只有缓冲区没有在使用时才可设置
BaseType_t xMessageBufferReset( MessageBufferHandle_t xMessageBuffer );

使用演示

#include "debug.h"
#include "FreeRTOS.h"       // 引入头文件
#include "task.h"           // 引入头文件
#include "message_buffer.h" // 引入头文件

MessageBufferHandle_t xMessageBuffer; // 消息缓冲区句柄

void task1(void *pvParameters) {
    uint8_t data[5] = {1, 2, 3, 4, 5};
    while(1) {
        vTaskDelay(500);
        xMessageBufferSend(xMessageBuffer, data, 5, portMAX_DELAY); // 发送数据,长度为5
    }
}

void task2(void *pvParameters) {
    uint8_t data[3] = {7, 7, 7};
    while(1) {
        vTaskDelay(1000);
        xMessageBufferSend(xMessageBuffer, data, 3, portMAX_DELAY); // 发送数据,长度为3
    }
}

void task3(void *pvParameters) {
    while(1) {
        uint8_t data[5] = {0};
        size_t len = xMessageBufferReceive(xMessageBuffer, data, 5, portMAX_DELAY); // 等待数据可接收
        printf("%u task3 len: %u  data: %u %u %u %u %u \r\n", xTaskGetTickCount(), len, data[0], data[1], data[2], data[3], data[4]);
    }
}

int main(void) {
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    SystemCoreClockUpdate();
    Delay_Init();
    USART_Printf_Init(115200);

    xMessageBuffer = xMessageBufferCreate(128); // 创建消息缓冲区

    xTaskCreate(task1, "task1", 256, NULL, 5, NULL);
    xTaskCreate(task2, "task2", 256, NULL, 5, NULL);
    xTaskCreate(task3, "task3", 256, NULL, 5, NULL);

    vTaskStartScheduler(); // 任务调度,任务将在这里根据情况开始运行,程序将在这里无序循环

    while(1) {} // 程序不会运行到这里
}

在这里插入图片描述

总结

流缓冲区和消息缓冲区的使用都比较简单,其实就有点像是一个公共的先进先出的队列,这种结构在传输数据流或是不定长数据时是比较常用的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS入门(07):流缓冲区 & 消息缓冲区 的相关文章

  • 基于java的学生成绩在线管理系统设计与实现

    基于java的学生成绩在线管理系统设计与实现 I 引言 A 研究背景和动机 基于Java的学生成绩在线管理系统设计与实现的研究背景和动机是设计一个可以方便管理学生成绩的系统 该系统可以方便地记录学生的成绩 并为老师和学生提供查询和统计功能
  • 【C++】__declspec含义

    目录 一 declspec dllexport 如果这篇文章对你有所帮助 渴望获得你的一个点赞 一 declspec dllexport declspec dllexport 是 Microsoft Visual C 编译器提供的一个扩展
  • 【gee】下载modis土地利用类型

    var china ee FeatureCollection projects assets china boundary var lc dataset ee ImageCollection MODIS 061 MCD12Q1 filter
  • 【卡尔曼滤波】具有梯度流的一类系统的扩散映射卡尔曼滤波器研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 数据 文章
  • 华为OD机试2024年最新题库(Java)

    我是一名软件开发培训机构老师 我的学生已经有上百人通过了华为OD机试 学生们每次考完试 会把题目拿出来一起交流分享 重要 2024年1月 5月 考的都是OD统一考试 C卷 题库已经整理好了 命中率95 以上 这个专栏使用 Java 解法 问
  • 一台java服务器可以跑多少个线程?

    一台java服务器可以跑多少个线程 一台java服务器能跑多少个线程 这个问题来自一次线上报警如下图 超过了我们的配置阈值 打出jstack文件 通过IBM Thread and Monitor Dump Analyzer for Java
  • tcpdump抓包

    tcpdump抓包 基本概念 1 类型的关键字 host 指明一台主机 如 host 10 1 110 110 net 指明一个网络地址 如 net 10 1 0 0 port 指明端口号 如 port 8090 2 确定方向的关键字 sr
  • 计算机Java项目|尤文图斯足球俱乐部网上商城系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 计算机Java项目|springboot校园台球厅人员与设备管理系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • Python 文件的复制重命名以及xlsx文件中表格分开保存

    1 需要的头文件 import shutil import os import openpyxl 2 复制文件以及重命名 直接使用shutil库复制 重命名 移动即可 函数封装示例 source path 为全局变量被复制文件路径 dest
  • APP开发毕业设计|ssm爱心小屋公益机构智慧管理APP

    作者主页 编程指南针 作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智
  • 2024史上最全Java面试八股文(带全部答案)

    今天要谈的主题是关于求职 求职是在每个技术人员的生涯中都要经历多次 对于我们大部分人而言 在进入自己心仪的公司之前少不了准备工作 有一份全面细致 面试题 将帮助我们减少许多麻烦 在跳槽季来临之前 特地做这个系列的文章 一方面帮助自己巩固下基
  • 【自适应滤波】一种接近最佳的自适应滤波器,用于突发系统变化研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码及文章
  • 详解toLowerCase(判断字符串相等)

    一 toLowerCase 函数简介 toLowerCase 是一个在多个编程语言中都存在的字符串方法 它的作用是将字符串中的所有大写字母转换为对应的小写字母 常用于文本处理 搜索和比较等情况 以确保字符串的一致性和非大小写敏感的操作 二
  • 【心电图基线估计和去噪方法的群稀疏正则化】带有群稀疏正则化的心电图基线估计和去噪(Matlab实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码及文章
  • 网络安全(黑客)自学启蒙

    一 什么是网络安全 网络安全是一种综合性的概念 涵盖了保护计算机系统 网络基础设施和数据免受未经授权的访问 攻击 损害或盗窃的一系列措施和技术 经常听到的 红队 渗透测试 等就是研究攻击技术 而 蓝队 安全运营 安全运维 则研究防御技术 作
  • 2024年华为OD机试真题-靠谱的车-Python-OD统一考试(C卷)

    题目描述 程序员小明打了一辆出租车去上班 出于职业敏感 他注意到这辆出租车的计费表有点问题 总是偏大 出租车司机解释说他不喜欢数字4 所以改装了计费表 任何数字位置遇到数字4就直接跳过 其余功能都正常 比如 1 23再多一块钱就变为25 2
  • 为什么我强烈推荐大学生打CTF!

    前言 写这个文章是因为我很多粉丝都是学生 经常有人问 感觉大一第一个学期忙忙碌碌的过去了 啥都会一点 但是自己很难系统的学习到整个知识体系 很迷茫 想知道要如何高效学习 这篇文章我主要就围绕两点 减少那些罗里吧嗦的废话 直接上干货 CTF如
  • sychnorized积累

    sychnorized 1 对象锁 包括方法锁 默认锁对象为this 当前实例对象 和同步代码块锁 自己指定锁对象 2 类锁 指synchronize修饰静态的方法或指定锁对象为Class对象 3 加锁和释放锁的原理 现象 时机 内置锁th
  • 网工内推 | 上市公司同程、科达,五险一金,年终奖,最高12k*15薪

    01 同程旅行 招聘岗位 网络工程师 职责描述 1 负责职场 门店网络规划 建设 维护 2 负责网络安全及访问控制 上网行为管理和VPN设备的日常运维 3 负责内部相关网络自动化和系统化建设 4 优化与提升网络运行质量 制定应急预案 人员培

随机推荐

  • Jenkins持续集成demo

    1 下载Jenkins的war包 官网地址 https jenkins io 点击下载 将jenkins war 部署到Tomcat中 本文使用的是Tomcat8 5 35 注意Tomcat需要配置账号密码 Tomcat7 是 manage
  • MySQL、Oracle中去重并保留最新的一条数据

    MySQL select from my table where id in select id from select id name group code max create time mt from my table group b
  • IDEA的设置

    terminal wsl2 setting gt tools gt Termianl gt shell path 填写wsl exe的绝对路 绝对路径的查找 wsl2 安装 https docs microsoft com en us wi
  • LA@向量组线性相关性

    文章目录 向量组线性相关性 线性相关 线性无关 多向量向量组线性相关 单向量向量组的线性相关性 单位向量向量组线性相关性 双向量向量组的线性相关性 双向量线性相关的几何意义 三向量线性相关的几何意义 包含零向量的向量组线性相关 概念迁移 线
  • STC89C51——中断系统

    前言 本文介绍基于常见的51单片机 即如下图的芯片 STC89C51具备5个中断源 中断源 优先级 中断请求标志位 中断允许控制位 外部中断0 0 IE0 EX0 定时器中断0 1 TF0 ET0 外部中断1 2 IE1 EX1 定时器中断
  • 2021 Web 前端热点笔试面试题总结【更新版】

    提醒 我只是答案的搬运工 如果在浏览中发现有错误 欢迎评论中提出来 我好修改 谢谢 简述异步和同步的区别 同步 浏览器访问服务器请求 用户看得到页面刷新 重新发请求 等请求完 页面刷新 新内容出现 用户看到新内容 进行下一步操作 异步 浏览
  • 指定岗位

    一 背景介绍 这里我们选择的是目前求职和招聘最常用的网站Bxxx 在采用其它方法的试验中 我们可能会遇到如下问题 不知道该怎么解析网址 自定义城市和岗位的搜索词 不知道怎么样批量爬取 这里指的是自动切页 不知道该怎么破解动态cookie的问
  • K8S 安装 Ingress Controller

    版本介绍 版本1 NGINX Ingress Controller nginx公司的nginx ingress NGINX Ingress Controller 由 F5 NGINX 开发和维护 docs nginx com 可在 GitH
  • Ubuntu命令介绍——echo

    echo是一个非常简单 直接的linux命令 将argument送出至标准输出 STDOUT 通常就是在显示器 monitor 上输出 为了更好的理解 不如先让我们跑一下 echo 命令好了 echo 你会发现只有一个空白行 然后又回到 s
  • k8s--基础--6.1--环境搭建--多master高可用集群

    k8s 基础 6 1 环境搭建 多master高可用集群 前提 使用root用户 1 机器 主机名 IP 说明 master1 192 168 187 154 2核4G 硬盘20G 核数最小要求是2 master2 192 168 187
  • SQLite向arm板子的移植

    SQLite向arm linux的移植 SQLite是一个开源的嵌入式关系数据库 我们用它来管理从M0端接收的数据 将检测到的仓库信息存储起来 SQLite环境的建立 首先从下载最新版本的sqlite源码包 我下载的是sqlite amal
  • mac idea 使用技巧-长期更新

    公司配发了新款Mac book pro M1 以前都是使用window 版本 切换成了mac 操作idea 很多技巧需要重新掌握 现在总结文档 idea 版本 试用版 建议大家自行购买账户 idea 在Mac 环境下游多中快捷键组合 注意事
  • 最通俗易懂的nginx

    nginx 文章目录 nginx 什么是nginx nginx配置文件 正向代理 反向代理 负载均衡 动静分离 高可用 什么是nginx Nginx是一款自由的 开源的 高性能的HTTP服务器和反向代理服务器 同时也是一个IMAP POP3
  • 【STM32】单片机启动文件分析

    启动文件 启动文件由汇编语言写成 时单片机上电之后执行的第一个文件 也就是从上电到mian函数中间的一段过程 bootloader bootloader也可以叫启动文件 每种MCU都有对应的启动文件 但开发环境往往自动完整地提供了这个启动文
  • 虚拟机nat模式网卡配置

    我们的目的是 虚拟机和主机能互ping 虚拟机可以ping外网 1 设置win10防火墙 添加入站规则 2 共享无线网卡或者有线网卡给虚拟机网卡 VMnet8 3 虚拟机虚拟网络编辑 4 修改虚拟网卡vmnet8配置 5 关闭centos防
  • 史上最全树莓派安装方法

    众所粥汁 树莓派是一个只有银行卡大小的 电脑 但很多人在安装树莓派时会有疑问 我安装的对不对 系统是正版吗 怎么会出错 等等等等问题 所以今天我就带来一个树莓派使用指南 材料有 1 树莓派3b 3b 4b 2 外壳 3 网线 可选 4 显示
  • 怎么能学会做买卖步骤是什么(想做买卖赚钱应该先从什么做起)

    如何能学会做交易 办法是什么 胜利者 有本人的战略 遵照本人的战略 比方价格入股 趋向盯梢入股 套利 缠论买卖体例之类 波折者 自我买卖 情结买卖 动静炒买炒卖股票 贪嗔痴慢疑主宰你的操纵 你必需输得起 没有人 会在看了一本简略五官科手术的
  • JetBrains IDEA 系列产品通用xx方法(license server)

    若资金允许 请点击https www jetbrains com idea buy 购买正版 谢谢合作 学生凭学生证可免费申请正版授权 创业公司可5折购买正版授权 本文适用于所有 JetBrains 系列产品 方法一 最新方法 Jet Br
  • springboot+cache缓存上

    cache内容 缓存的意义 将方法的运行结果进行缓存 以后再要相同的数据 直接从缓存中获取 不用调用方法 cacheManager管理多个Cache组件 对缓存的真正操作CRUD操作在Cache组件中 每一个缓存组件有自己唯一一个名字 几个
  • FreeRTOS入门(07):流缓冲区 & 消息缓冲区

    文章目录 目的 基础说明 流缓冲区 相关函数 使用演示 消息缓冲区 相关函数 使用演示 总结 目的 缓冲区是操作系统中常见的一种用于任务间数据传递的机制 这篇文章将对FreeRTOS中相关内容做个介绍 本文代码测试环境见前面的文章 Free