【第26期】环形缓冲区 (Ring Buffer):数据流大动脉

环形缓冲区优点及实现 使用环形缓冲区时存放sensor的x和y位置时,读与写互不干扰:读数据根据读指针读取,只有TaskReadPosition任务能够修改读指针位置;写数据使用写指针写数据,只有TaskWritePosition任务能够修改写指针的位置。环形缓冲区所有的push和pop操作都是在一个固定的存储空间内进行,相比队列方式,少掉了对于缓冲区元素所用存储空间的分配、释放。这是环形缓冲区的一个主要优势。环形缓冲区是一种特殊的缓冲区,其读指针和写指针都指向同一个缓冲区,通过移动指针来实现数据的读取和写入。 阅读详情

核心痛点:串口(或网络)数据来得太快、太乱,或者不定长。

  • 用普通数组 Buffer[100]?写满了怎么办?要把数据整体搬回开头吗?那 CPU 就累死了。

  • 用链表?malloc 太多会碎片化,且速度慢。

解决方案:把数组的首尾连起来,做成一个环。

1. 物理模型:衔尾蛇

想象一条蛇咬住了自己的尾巴。 我们只需要两个指针(索引):

  • Head (头/写指针):猛兽的嘴。数据来了就往这里塞,塞完头往前伸。

  • Tail (尾/读指针):猛兽的排泄口(或者叫处理端)。业务逻辑从这里把数据取走,取完尾巴也往前挪。

核心规则:

  • Head 追 Tail:说明数据太快,缓冲区要满了(Overflow)。

  • Tail 追 Head:说明处理得很快,缓冲区空了。

2. C 语言实现:结构体定义

一个标准的环形缓冲区对象通常包含以下成员:

typedef struct {
    uint8_t *buffer;    // 实际的内存块
    uint32_t size;      // 缓冲区总大小 (最好是 2 的幂次)
    volatile uint32_t head; // 写索引 (ISR 会改它,必须 volatile)
    volatile uint32_t tail; // 读索引 (Task 会改它,必须 volatile)
} RingBuffer_t;

3. 写入逻辑 (Push) —— 中断里跑的代码

这是 ISR 里最常用的代码。要求极快。

// 返回 1 表示成功,0 表示满了
int RingBuffer_Push(RingBuffer_t *rb, uint8_t data) {
    uint32_t next_head = rb->head + 1;
    
    // 1. 处理回绕 (Wrap Around)
    if (next_head >= rb->size) {
        next_head = 0;
    }

    // 2. 判断满 (Full)
    // 经典策略:保留一个字节不存,用于区分“满”和“空”
    // 如果 Head 的下一步撞上了 Tail,就是满了
    if (next_head == rb->tail) {
        return 0; // 满了,丢弃数据 (或者覆盖旧数据,看策略)
    }

    // 3. 存入数据
    rb->buffer[rb->head] = data;
    
    // 4. 更新指针
    rb->head = next_head;
    return 1;
}

4. 读取逻辑 (Pop) —— 任务里跑的代码

这是 Task 里的代码。

// 返回 1 表示读到了,0 表示空了
int RingBuffer_Pop(RingBuffer_t *rb, uint8_t *data) {
    // 1. 判断空 (Empty)
    // 如果头尾重合,就是空的
    if (rb->head == rb->tail) {
        return 0; 
    }

    // 2. 取数据
    *data = rb->buffer[rb->tail];

    // 3. 更新指针 & 处理回绕
    uint32_t next_tail = rb->tail + 1;
    if (next_tail >= rb->size) {
        next_tail = 0;
    }
    rb->tail = next_tail;
    
    return 1;
}

5. 进阶技巧:取模运算的优化

在上面的代码中,我们用了 if (next >= size) next = 0; 来处理回绕。这涉及到了分支判断。 如果你对速度有极致追求(比如音频处理),或者你不想用 if,有一个位运算的黑魔法。

前提:缓冲区大小 size 必须是 2 的幂次方 (16, 32, 64, 128, 256...)。

优化写法:

// 假设 size = 256 (0x100), mask = 255 (0xFF)
// 任何数 & 0xFF,结果一定在 0~255 之间,自动回绕!

rb->head = (rb->head + 1) & (rb->size - 1);

这条指令通常比 if 跳转要快,且流水线更顺畅。

6. 线程安全问题 (Lock-Free?)

这是一个经典的面试题:Ring Buffer 需要加锁吗?

答案是:如果是“单生产者 - 单消费者”模型,通常不需要加锁。

  • ISR (生产者) 只修改 head,只读取 tail。

  • Task (消费者) 只修改 tail,只读取 head。

只要 head 和 tail 的读写是原子的(32位 CPU 读写 32位变量通常是原子的),就不会出大乱子。

但是:如果你的 head 和 tail 是 16 位的,而在 8 位单片机上跑,读写就需要两步指令,这时候必须关中断保护,否则会读到“半个指针”。 建议:在 ARM Cortex-M 上,使用 uint32_t 类型的索引是安全的。

7. 常见的大坑

  1. 分不清空和满: 如果 Head == Tail 表示空,那什么时候表示满?

    • 如果存满了也是 Head == Tail,程序就傻了。

    • 解决:牺牲一个字节的空间。当 (Head + 1) % Size == Tail 时,就认为满了。虽然浪费了 1 字节,但逻辑最简单。

  2. DMA 配合的 Cache 一致性: 如果你用 DMA 往 RingBuffer 里搬数据(自动循环模式),而你的 CPU 开启了 D-Cache(如 STM32F7/H7)。

    • 现象:DMA 改了内存,但 CPU 读到的还是 Cache 里的旧数据。

    • 解决:读取前必须做 Cache Invalidate 操作,或者把这块内存配置为 MPU 无缓存区 (Non-cacheable)。


关键点

  1. Ring Buffer 是解决“生产快、消费慢”或“不定长数据”的神器。

  2. 单产单消模型下,在 32 位机上可以实现无锁(Lock-Free)操作。

  3. 大小设为 2 的幂次,可以用位与运算 & 代替取模 + if,效率起飞。

/***************************************************
 * 本文为作者《嵌入式开发基础与工程实践》系列文章之一。
 * 关注即可订阅后续内容更新,翻阅往期信息,采用异步推送机制,无需主动轮询。
 * 转发本文可视为一次网络广播,有助于更多节点接收该信息。
 ***************************************************/

 

ESP32 Modbus TCP分片缓存与环形缓冲区实战 Modbus TCP是一种基于TCP字节流的应用层工业协议,其可靠性高度依赖底层数据帧的完整接收与精准解析。在资源受限的嵌入式设备如ESP32上,TCP分片、Wi-Fi丢包、内存紧张和FreeRTOS多核调度共同导致‘recv一次收不全帧’这一典型问题。解决关键在于摒弃简单Socket模型,采用环形缓冲区实现零拷贝字节流暂存,并结合有限状态机完成MBAP头识别、长度校验与CRC验证,从而保障Modbus ADU的可靠重组。该方案广泛适用于工业物联网网关、PLC代理及智能电表通信等对稳定性要求严苛的场景。 阅读详情

相关推荐

iOS 26 Foundation Models:本地生成式AI开发实战指南

Foundation Models是苹果在iOS 26中推出的设备端生成式AI运行时环境,不同于传统Core ML模型或云端LLM调用,它融合模型、Metal优化运行时与安全沙箱于一体。其核心原理基于预编译`.fmmodel`格式、Metal Graph Compiler硬件协同编译、Token Ring上下文管理及neurald守护进程隔离机制,带来毫秒级延迟、零网络依赖与GDPR/HIPAA就绪的隐私保障。技术价值体现在亚秒级响应、全链路加密、跨App内存自适应降级等工程优势,广泛适用于离线笔记、医疗问

weixin_34130389的博客 2099

嵌入式开发常用的Ring Buffer,今天一篇文章讲透它

因为缓冲区成头尾相连的环形,写操作可能会覆盖未及时读取的数据,有的场景允许这种情况发生,有的场景又严格限制这种情况发生。因为缓冲区成头尾相连的环形,写操作可能会覆盖未及时读取的数据,有的场景允许这种情况发生,有的场景又严格限制这种情况发生。来看策略一,例如,这时。如果缓冲区的大小需要经常调整,就不适合用环形缓冲区,因为在扩展缓冲区大小时,需要搬移其中的数据,这种场合使用链表更加合适;如果缓冲区的大小需要经常调整,就不适合用环形缓存区,因为在扩展缓冲区大小时,需要搬移其中的数据,这种场合使用链表更加合适;

一名热爱技术的工程师的博客。分享技术干货,记录美好生活。永远相信美好的事情即将发生。 1286

DeepSeek V4百万上下文技术解析:Ring Attention与FlashMLA实战指南

长上下文大模型是当前AI工程落地的核心瓶颈之一,其本质涉及注意力机制的计算复杂度、显存占用与分布式通信效率三大挑战。传统Transformer的O(N²)复杂度在百万级序列下遭遇严重内存墙,催生了Ring Attention等环形分布式注意力架构,通过降低通信量至O(N×d)实现可扩展推理。配合深度优化的FlashMLA CUDA内核,支持动态分块、零拷贝KV复用与混合精度训练,在单卡A100上稳定运行1M tokens上下文。该技术显著提升文档理解、合同审查、工业日志分析等长文本场景的语义连贯性与跨段推理

weixin_30252709的博客 389

【RingBuffer】环形缓冲区C语言——两种实现方式

【RingBuffer】环形缓冲区C语言——两种实现方式

Telly_的博客 1024

AT指令状态机设计与实现:解决NB-IoT串口通信难题

在嵌入式开发中,串口通信的异步性常常导致数据分包、乱序等问题,状态机作为一种结构化的事件驱动模型,能有效管理复杂的字符流解析流程。通过将接收、解析与业务处理分层,状态机可大幅提升系统的健壮性与可维护性。在NB-IoT设备中,AT指令交互频繁且伴随URC主动上报,合理设计状态机能够解决命令响应错乱、半包粘包、低功耗唤醒后通信失败等工程痛点。本文结合STM32平台,详细介绍AT指令状态机的设计思路、环形缓冲区实现、性能优化与实战排错经验,并给出针对BC26等模组的调试要点,帮助开发者构建稳定可靠的物联网通信方案

weixin_34242509的博客 412

ICM-42688-P与PIC18F26K22在运动控制与振动监测中的应用

MEMS惯性测量单元(IMU)与微控制器(MCU)的组合是嵌入式运动感知系统的核心技术。IMU通过加速度计和陀螺仪实现运动状态检测,而MCU负责数据处理和系统控制。这种技术组合在机器人导航、工业自动化等领域具有重要价值,能够实现高精度运动控制和实时振动监测。ICM-42688-P作为工业级六轴IMU,具备超低功耗和内置FIFO缓冲区特性,与PIC18F26K22微控制器的硬件接口完美匹配。在机器人技术中,该方案可用于地形识别和机械臂控制;在工业自动化中,则适用于输送带异物检测和电机健康预测。通过边缘计算和智

weixin_30385925的博客 409

环形缓冲区(ring buffer),环形队列(ring queue) 原理

1. 序言 环形缓冲区(ring buffer),环形队列(ring queue) 多用于2个线程之间传递数据,是标准的先入先出(FIFO)模型。一般来说,对于多线程共享数据,需要使用mutex来同步,这样共享数据才不至于发生不可预测的修改/读取,然而,mutex的使用也带来了额外的系统开销,ring buffer/queue 的引入,就是为了有效地解决这个问题,因其特殊的结构及算法,可以用

wabil的专栏 1万+

自回归分布滞后模型 (ARDL)及 Stata 具体操作步骤

例如,Bahmani-Oskooee 和 Brooks(1999)研究了汇率波动与贸易收支之间的关系,发现汇率的变动在长期和短期内对贸易收支的影响存在差异,ARDL 模型能够有效地捕捉这种复杂的关系。它结合了自回归(Autoregressive,AR)模型和分布滞后(Distributed Lag,DL)模型的特点,能够同时考察变量之间的短期和长期关系。假设我们收集了一段时间内的居民消费和可支配收入数据,通过对这些数据进行分析和估计,可以得到模型的参数估计值,从而揭示消费与收入之间的短期和长期关系。

a519573917的博客 6093

浅谈环形缓冲区RingBuffer的原理与实现

环形缓冲区(Ring Buffer)是一种固定大小的循环数据结构,通过首尾相接的逻辑结构实现数据的高效读写。首尾相连:当尾指针(Tail)到达缓冲区末尾时(尚未追上头指针Head),自动绕回起始位置继续读出,形成逻辑闭环。先进先出(FIFO):数据按写入顺序依次被读取,适用于生产者-消费者模型。免锁设计:单生产者-单消费者场景下,通过隔离读写指针可实现无锁并发访问。上图中就能够看到环形缓冲区的关键元素:存储数组:固定长度的连续内存区域,用于存储数据。

yaojiachang__的博客 721

Linux内核支持串口屏,linux串口触摸屏设计总结

Linux serial touch 设计总结概述:最近在做嵌入式linux下串口触摸屏设计,遇到一些问题,经过查找资料和请教同事,总算把问题解决了,事后有把linux相关的内核代码仔细看了一遍,为了有点成果,特别写了个总结。如有任何问题请联系yxj_5421@http://www.doczj.com/doc/87b94b1e227916888486d76d.html,转载请标明出处。系统资源:L...

weixin_39935903的博客 1296

【可不卸载重装】VS2019新建项目里没有CUDA选项

问题:VS2019 新建项目里没有CUDA选项,vs也属性没有cuda。这是因为你在Visual Studio 2019安装之前,先安装了CUDA Toolkit。

qq_62844901的博客 1318

LabVIEW环形缓冲区工业级温度采集

摘要:本方案基于NI Variant环形缓冲区实现工业温度监测系统,针对1秒周期可变的26路温度采集场景。采用固定180-200容量的环形缓冲区自动管理3分钟数据,通过时间戳精准查找1/2分钟前数据计算温度变化量。方案特点包括:1)工业级稳定性,兼容LabVIEW 2014+;2)高性能低损耗,Variant数据类型简化开发;3)灵活适配周期可变场景;4)模块化设计易于扩展。实际应用表明,该方案在1秒高频采集下实现零数据丢失、界面无卡顿,温度变化量计算误差小于0.1秒,满足智能制造装备的严苛监测需求。(14

bjcyck的博客 652

Matlab Arduino 硬件支持包安装 MATLAB_Support_Package_for_Arduino_Hardware

Matlab Arduino硬件支持包离线安装

weixin_43283734的博客 2840

嵌入式UART串口驱动开发:中断、环形缓冲区与协议解析实战

在嵌入式系统开发中,串口通信是最基础也最关键的环节之一。UART作为通用异步收发器,其底层原理涉及波特率计算、寄存器配置和中断处理等核心知识。从单片机裸机驱动到RTOS集成,串口收发路径的设计直接影响数据完整性和系统实时性。本文从中断模式与环形缓冲区的配合原理切入,解析如何解决数据丢帧、溢出和读写竞争问题,并结合协议状态机实现高效的数据帧解析。这些技术在物联网模组、工业控制和调试工具等场景中广泛应用,掌握串口驱动的完整实现路径,是提升嵌入式开发能力的重要一步。文章基于实际项目经验,分享了从硬件波形验证到驱动

weixin_34216196的博客 227

用Multisim仿真AD630锁定放大器:从2012年电赛A题实战到避坑指南

本文详细介绍了如何使用Multisim仿真AD630锁定放大器,从2012年电赛A题实战出发,提供完整的电路搭建、参数优化及避坑指南。重点解析AD630的开关调制架构和双相位检测的工程实现,帮助读者在强噪声背景下有效提取微弱信号,提升电子设计竞赛和工程实践中的信号处理能力。

weixin_42549451的博客 202

重回童年的经典系列☀️|【炸弹人小游戏】制作过程+解析 | 收藏起来跟曾经的小伙伴一起梦回童年!

Unity,小游戏开发。 本篇文章对童年经典小游戏——炸弹超人进行制作和解析。不知道有没有勾起你童年的回忆呢!快来和我一起制作这个童年经典的小游戏吧! 敬请品尝!

努力前行,总会成为自己心中的那道光 13万+

【Go 1.26.4】Golang Channel 深度解析

Golang Channel 深度解析

zhonglinzhang 906

YOLO11实战优化:长尾分布解决 | 引入Seesaw Loss配合YOLO11分类头,完美应对类别极其不平衡的现实业务场景

摘要: YOLO11在工业缺陷检测等长尾分布场景中面临尾部类别检测失效的问题,根源在于头部类别样本的负样本梯度压制了尾部类别的学习。传统方法如重采样、Focal Loss等效果有限。Seesaw Loss通过动态调整缓解因子和补偿因子,平衡类别间的梯度分布,结合YOLO11的解耦分类头、Anchor-Free设计和C2PSA/C3K2模块,显著提升尾部类别识别能力。文章详细解析了Seesaw Loss的数学原理,并提供了可直接集成到YOLO11的PyTorch实现代码,为长尾分布下的目标检测提供了实用解决方

2601_95807009的博客 251

深入解析RP2040 DMA:从寄存器到链式传输的完整指南

DMA(直接存储器访问)是嵌入式系统中将CPU从繁重数据搬运中解放的关键机制,其核心价值在于让CPU专注于计算与控制,同时通过硬件自动完成外设与内存间的数据传输。理解DMA的触发源(如DREQ信号)和寄存器配置,是掌握高效数据传输的基础。在树莓派Pico(RP2040)平台上,DMA与PIO、ADC、SPI等外设的深度协作,能够显著提升系统吞吐量,典型应用包括高速连续采样、双缓冲舵机控制以及Scatter-Gather链式传输。本文从寄存器底层行为出发,结合工程实践,系统梳理了通道配置、链式传输陷阱、缓冲区

weixin_33850890的博客 370

使用mindie:2.0.RC2-800I-A2-py311-openeuler24.03-lts制作一个通用的模型推理性能测试的镜像

本文详细介绍了在NPU环境下进行模型推理性能测试的完整流程。首先配置了测试所需的环境和设备信息,包括Python 3.10.9和3.11.6版本、测试脚本和镜像文件。然后分步骤说明了镜像制作过程:创建特权容器、安装Python 3.10.9、配置VLLM环境,并详细描述了测试容器的启动方法。最后提供了镜像打包和使用指南,包括如何加载镜像、启动容器、运行测试脚本(以DeepSeek-32B模型为例)以及更换测试模型的步骤。整个过程涉及环境变量配置、权限设置和服务启动等关键操作。

m0_50105717的博客 1015

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

嵌入式UART串口处理函数设计:从原理到实战的帧解析与缓冲区管理

串口通信是嵌入式系统中最基础且广泛使用的异步通信接口,其核心在于将字节流数据可靠地解析为有意义的帧。理解其工作原理,关键在于掌握数据帧的界定方法,如定界符、超时和长度字段等策略,这直接决定了通信的可靠性。在工程实践中,高效的数据缓冲管理技术,如环形缓冲区,能有效解决数据收发速度不匹配的问题,防止数据丢失或覆盖。结合中断与轮询的架构设计,既能保证实时性,又能避免复杂逻辑阻塞系统。这些技术共同构成了稳定串口驱动的基石,广泛应用于传感器数据采集、设备调试、模块间通信等场景,而一个健壮的Uart_Proc函数正是实

weixin_34411563的博客 485

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

深入解析UART FIFO与中断/DMA机制:从字节搬运到智能数据流管理

在嵌入式系统与外设通信中,串行通信是基础且关键的技术。其核心原理在于通过异步串行协议,在单根数据线上实现设备间的数据交换。为了提升CPU效率与系统性能,现代微控制器普遍引入了FIFO(先进先出缓冲区)与中断/DMA(直接内存访问)协同工作的机制。这项技术的核心价值在于将CPU从繁琐的字节级轮询操作中解放出来,实现数据的批量、自动搬运,从而显著降低CPU负载,提升系统实时响应能力与整体吞吐量。其典型应用场景包括高速串口日志传输、传感器数据采集、以及IrDA红外通信等对时序和效率有要求的领域。本文以TI UAR

weixin_30410119的博客 432

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Android声卡播放PCM实战:AI辅助开发中的低延迟优化方案

基于火山引擎豆包大模型,从零搭建一个实时语音通话应用。它不是简单的问答,而是需要你亲手打通 ASR(语音识别)→ LLM(大脑思考)→ TTS(语音合成)的完整 WebSocket 链路。对于想要掌握 AI 原生应用架构的同学来说,这是个绝佳的练手项目。架构理解:掌握实时语音应用的完整技术链路(ASR→LLM→TTS)技能提升:学会申请、配置与调用火山引擎AI服务定制能力:通过代码修改自定义角色性格与音色,实现“从使用到创造”从0到1构建生产级别应用,脱离Demo,点击打开。

2600_94960057的博客 420

STM32+NB-IoT模组AT指令状态机设计:从阻塞到事件驱动

嵌入式开发中,串口通信是MCU与无线模组交互的基础,尤其NB-IoT模组依赖AT指令完成网络附着、数据收发等操作。然而,实际项目里AT指令并非简单的“一问一答”,模组可能延迟响应、乱序返回,甚至主动上报URC事件,导致阻塞式处理极易丢数据、卡死或误判超时。状态机模型将不可预测的异步串口事件流转化为有限状态迁移,配合环形缓冲区、超时重试和事件驱动架构,可显著提升系统的稳定性与实时性。在STM32等资源受限平台上,通过双状态机分离字节解析与指令流程,并针对URC做好隔离处理,能有效解决NB-IoT调试中的顽固问

weixin_34318326的博客 290

ESP32 Modbus TCP分片缓存设计:解决粘包、阻塞与数据一致性

Modbus TCP是工业物联网中最常用的协议之一,但其基于字节流的TCP传输特性与MCU资源受限现实存在根本矛盾。当在ESP32等轻量级平台部署Modbus主站或从站时,常面临TCP粘包导致帧解析失败、同步阻塞式IO引发CPU过载、多寄存器读取缺乏原子性保障等典型问题。‘分片’机制通过MBAP头动态截取实现精准帧重组,‘缓存’则依托带版本号的寄存器映射表确保跨请求数据一致性。该方案不依赖Linux环境,在FreeRTOS下即可落地,适用于PLC、电表、温控器等主流工业设备对接,显著提升边缘节点的稳定性、实

weixin_33827590的博客 442

深入解析CC13x2/CC26x2射频核心:中断、队列与CSMA-CA硬件加速机制

在嵌入式无线通信领域,中断机制是MCU响应异步事件的核心,尤其在IEEE 802.15.4等低功耗无线网络中,实时处理射频事件对系统性能至关重要。其原理在于通过硬件中断信号快速响应数据收发、信道状态变化等事件,从而减少CPU轮询开销,提升响应效率。这项技术的价值在于能够显著降低通信延迟、提高系统实时性,并优化功耗管理。在实际应用中,它广泛用于智能家居传感器、工业物联网监测节点等对可靠性和实时性要求高的场景。本文聚焦TI CC13x2/CC26x2系列无线MCU,深入探讨其中断体系、数据队列管理以及CSMA-

weixin_30629653的博客 362
上一篇: 【第25期】中断处理策略:即时处理 vs 推迟处理 (Deferred)
下一篇: 【第27期】有限状态机 (FSM):逻辑控制的灵魂
一路往蓝-Anbo
博客等级 码龄8年 792粉丝 183原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一路往蓝-Anbo

转发是最高褒奖,硬核打赏随心!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值