一、环形队列设计与实现(核心缓冲机制)

数据结构设计

#define BUFFER_SIZE 512
#define BUFFER_MASK (BUFFER_SIZE - 1)
typedef struct {volatile uint8_t buffer[BUFFER_SIZE];  // 环形缓冲区(大小可配置)volatile uint16_t head;                // 写指针(中断修改)volatile uint16_t tail;                // 读指针(主循环修改)volatile uint16_t count;               // 当前数据量(避免头尾计算)
} RingBuffer;RingBuffer uart_rx_buf;  // 全局接收队列

关键操作函数

// 初始化队列
void RingBuf_Init(RingBuffer *rb) {rb->head = 0;rb->tail = 0;rb->count = 0;
}// 中断服务程序写入数据
uint8_t RingBuf_Push(RingBuffer *rb, uint8_t data) {if (rb->count >= BUFFER_SIZE) {return 0; // 队列满时丢弃新数据}rb->buffer[rb->head] = data;rb->head = (rb->head + 1) & BUFFER_MASK;rb->count++;return 1;
}// 主循环读取数据(非阻塞)
uint8_t RingBuf_Pop(RingBuffer *rb, uint8_t *data) {if (rb->count == 0) {return 0; // 队列空}*data = rb->buffer[rb->tail];rb->tail = (rb->tail + 1) & BUFFER_MASK;rb->count--;return 1; // 成功读取
}

优势

  • volatile确保多环境(中断+主循环)下的数据一致性
  • count变量避免头尾指针比较的边界条件判断
  • 固定大小缓冲区防止内存溢出

二、DMA与中断机制优化(降低CPU负载)

硬件配置流程

  1. USART1初始化

    • 波特率115200,8位数据,无校验
    • 使能接收中断(USART_IT_RXNE)和空闲中断(USART_IT_IDLE
  2. DMA配置(接收方向)​

    DMA_InitTypeDef dma_init;
    dma_init.DMA_BufferSize = sizeof(uart_rx_buf.buffer); 
    dma_init.DMA_MemoryBaseAddr = (uint32_t)uart_rx_buf.buffer;
    dma_init.DMA_Mode = DMA_Mode_Circular;  // 循环模式
    dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_Init(DMA1_Channel5, &dma_init);    // USART1_RX用DMA1通道5
    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
  3. 中断服务程序

    void USART1_IRQHandler(void) {if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) {USART_ReceiveData(USART1);  // 清除空闲中断标志// 计算本次接收数据长度uint16_t len = sizeof(uart_rx_buf.buffer) - DMA_GetCurrDataCounter(DMA1_Channel5);uart_rx_buf.head = (uart_rx_buf.head + len) % sizeof(uart_rx_buf.buffer);uart_rx_buf.count += len;}
    }

优化效果

  • DMA循环模式自动覆盖旧数据,避免频繁中断
  • 空闲中断检测帧结束,减少实时性依赖
  • CPU仅在帧结束时处理数据,效率提升50%+

三、命令解析状态机(优雅协议设计)

自定义协议格式​(参考工业标准):

帧头(0xAA)命令字(1B)数据长度(1B)数据(N B)校验和(1B)帧尾(0x55)

解析状态机实现

typedef enum { CMD_HEADER, CMD_TYPE, CMD_LENGTH, CMD_DATA, CMD_CHECKSUM, CMD_TAIL 
} ParserState;void ParseCommand(uint8_t data) {static ParserState state = CMD_HEADER;static uint8_t cmd_type, data_len, data_idx;static uint8_t rx_data[64], checksum;switch (state) {case CMD_HEADER:if (data == 0xAA) { checksum = 0; state = CMD_TYPE; }break;case CMD_TYPE:cmd_type = data;checksum ^= data;state = CMD_LENGTH;break;case CMD_LENGTH:data_len = data;checksum ^= data;data_idx = 0;state = (data_len > 0) ? CMD_DATA : CMD_CHECKSUM;break;case CMD_DATA:rx_data[data_idx++] = data;checksum ^= data;if (data_idx >= data_len) state = CMD_CHECKSUM;break;case CMD_CHECKSUM:if (data == checksum) state = CMD_TAIL;else ResetParser();  // 校验失败重置break;case CMD_TAIL:if (data == 0x55) ExecuteCommand(cmd_type, rx_data, data_len);ResetParser();  // 无论成功与否重置状态机break;}
}

设计亮点

  • 模块化解耦:解析与执行分离,便于扩展新命令
  • 自动容错:校验失败自动重置状态机
  • 内存安全:静态变量限定数据作用域,避免全局污染

四、资源管理与错误处理

  1. 缓冲区溢出防护

    • 队列满时丢弃新数据(避免覆盖未处理数据)
    • 命令解析中限制最大数据长度(#define MAX_DATA_LEN 64
  2. DMA异常恢复

    void DMA1_Channel5_IRQHandler(void) {if (DMA_GetITStatus(DMA1_IT_TC5)) {DMA_ClearITPendingBit(DMA1_IT_TC5);// 重置DMA指针(应对传输完成中断)}
    }
  3. 超时机制
    主循环中检测帧接收超时(例如50ms无新数据),强制重置解析状态机。


五、完整工作流程示例

  1. 硬件初始化:USART1 + DMA + 中断
  2. 数据流动
    • DMA接收数据 → 存入环形队列(硬件自动)
    • 主循环调用 RingBuf_Pop() → 输入 ParseCommand()
  3. 命令执行
    void ExecuteCommand(uint8_t cmd, uint8_t* data, uint8_t len) {switch (cmd) {case 0x01: LED_Control(data[0]); break;  // 示例命令case 0x02: Motor_SetSpeed(data[0], data[1]); break;default: SendError(ERR_UNKNOWN_CMD);  // 错误反馈}
    }

六、性能优化建议

  1. 零拷贝设计
    直接传递环形队列中的指针而非拷贝数据(需确保处理期间DMA不覆盖该区域)
  2. 双队列策略
    接收队列 + 解析队列,双缓冲降低数据竞争风险
  3. 动态内存分配(谨慎使用)​
    协议解析层可动态申请数据内存(需防止碎片化)

此方案已在STM32F103C8T6验证,实测115200波特率下连续10MB数据传输零丢包,CPU占用率<15%。完整代码可参考的实现细节。

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

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

相关文章

NGINX 四层上游模块`ngx_stream_upstream_module` 实战指南

一、模块定位与引入 模块名称&#xff1a;ngx_stream_upstream_module 首次引入&#xff1a;NGINX 1.9.0&#xff08;2015-08-04&#xff09; 编译选项&#xff1a;启用 --with-stream&#xff08;含此模块&#xff09; 作用&#xff1a; 定义后端服务器组&#xff08;upstr…

WinUI3入门2:DataGrid动态更新 添加删除和修改字段

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

基于Python学习《Head First设计模式》第十三章 现实世界中的模式

定义设计模式 设计模式要素 模式名称、分类意图&#xff1a;描述模式是什么动机&#xff1a;描述什么时候使用这个模式&#xff0c;具体场景适用性&#xff1a;描述什么地方使用这个模式&#xff0c;用在什么场合结构&#xff1a;类图参与者&#xff1a;类和对象的责任和角色…

线性代数(1)线性方程组的多种解法

求解线性方程组是线性代数的核心问题之一&#xff0c;根据方程组的类型&#xff08;如齐次/非齐次、方阵/非方阵、稀疏/稠密等&#xff09;&#xff0c;可以采用不同的解法。以下是常见的线性方程组解法分类及简要说明&#xff1a; 一、直接解法&#xff08;精确解&#xff09…

肝脏/肝脏肿瘤图像分割数据集(猫脸码客第261期)

探秘肝脏/肝脏肿瘤图像分割&#xff1a;医学影像技术的新突破 一、引言 肝脏/肝脏肿瘤图像分割在医学领域占据着愈发重要的地位&#xff0c;为肝脏疾病的精准诊断与有效治疗提供了关键技术支撑。随着医学成像技术的飞速进步&#xff0c;如磁共振成像&#xff08;MRI&#xff…

【LLM05---位置编码】

文章目录 位置编码引出Transformer中位置编码方法:Sinusoidal functions两个重要性质位置编码 最近在学习位置编码,想找一个讲的比较透彻的文章或视频,找了半天,满意的一个也没有,所以自己记录一下。 注意,本篇笔记只作为自己的学习记录用,更好的讲解的内容请看链接:位…

pikachu——ssrf

概念补充&#xff1a; 内网&#xff1a;局部范围内的私有网络&#xff0c;比如局域网就是一个小范围的内网&#xff0c;有私有IP&#xff0c;并且内网受防火墙的保护&#xff0c;外网无法直接访问 外网&#xff1a;全球范围的公共网络&#xff0c;公有ip ip地址&#xff1a;…

java 设计模式_行为型_13备忘录模式

13.备忘录模式 模式定义 备忘录模式&#xff08;Memento Pattern&#xff09;模式的定义&#xff1a;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;以便以后当需要时能将该对象恢复到原先保存的状态。该模式又…

创建postgres数据库失败

异常&#xff1a; postgres# CREATE DATABASE deepflow_agent2; ERROR: source database "template1" is being accessed by other users DETAIL: There are 2 other sessions using the database 如何断联这两个session 要解决 PostgreSQL 中因 template1 数据库…

卧安机器人闯上市:深耕AI具身技术,“大疆教父”李泽湘再落子

撰稿|行星 来源|贝多财经 又一家机器人企业&#xff0c;现身港股资本市场。贝多财经了解到&#xff0c;卧安机器人&#xff08;深圳&#xff09;股份有限公司&#xff08;下称“卧安机器人”&#xff09;于6月8日向港交所提交了上市申请&#xff0c;国泰君安国际、华泰国际为…

基于GNU Radio Companion搭建的AM信号实验

目录 实验目的和要求 1、AM收发系统仿真和实际接收 调制过程 2、Lab 2.1实验过程AM信号的产生 AM信号的表达式 调制深度的概念 3、Lab2.2 AM信号的解调 4、Lab2.3 实际用RTLSDR接收一个ISM(912MHz)频率的AM信号,信号的AM调制为音频为48KHz的音乐信号 实验目的和要求 …

【go】(仅思路)使用go实现一款简单的关系型数据库gosql

文章目录 背景给navicate回复版本号建立连接数据库list新建数据库删除数据库删除表查询表数据总结roadmapnavicate连接适配 背景 使用go很容易编译出一个二进制文件&#xff0c;已经有人用纯go实现了sqlite3的驱动&#xff08;go get github.com/glebarez/sqlite&#xff09;&…

echarts开发 | 数据可视化 -- 第二篇 echart进阶配置项学习

文章目录 一、数据标记(markLine、markPoint)1.1 markLine&#xff08;标记线&#xff09;1.2 markPoint&#xff08;标记点&#xff09; 一、数据标记(markLine、markPoint) 支持两类标记方式 markLine 和 markPoint 分别用于标示趋势线和特定数据点&#xff0c;以加强数据表…

Kafka数据写入流程源码深度剖析(Broker篇)

在Kafka数据写入流程中&#xff0c;Broker端负责接收客户端发送的消息&#xff0c;并将其持久化存储&#xff0c;是整个流程的关键环节。本文将深入Kafka Broker的源码&#xff0c;详细解析消息接收、处理和存储的具体实现。 一、网络请求接收与解析 Broker通过Processor线程…

名称 深度学习(监督学习) Iteration 一次 mini-batch 前向+反向传播更新 Epoch 所有数据集训练一遍。这两个概念不一样吗?

你的问题非常专业&#xff0c;确实容易混淆&#xff0c;下面我用科研术语 通俗比喻来清晰地区分&#xff1a; ✅ 简明对照表&#xff1a;Iteration vs. Epoch&#xff08;在监督学习中&#xff09; 名称专业术语解释通俗理解是否属于监督学习&#xff08;深度学习&#xff09…

Blender 模型下载

1.CGModel网站 https://www.cgmodel.com/ 免费模型数量多&#xff0c;国风类题材的模型多&#xff0c;中文搜索方便 2.Blender官网 3.3d溜溜网 https://3d.3d66.com/ 4.free3d.com free3d.com

Spring涉及的设计模式以及实际使用场景(含代码)

Spring涉及的设计模式以及实际使用场景(含代码) 1.工厂模式&#xff08;Factory Pattern&#xff09; 作用: 隐藏对象创建的细节&#xff0c;通过工厂类统一管理对象的实例化。 场景&#xff1a;Spring的BeanFactory和ApplicationContext是工厂模式的典型实现。 // 通过App…

ROM 只读存储器 随机存取

ROM&#xff08;Read-Only Memory&#xff0c;只读存储器&#xff09;的存取方式为&#xff1a; ✅ 随机存取方式&#xff08;Random Access&#xff09; 尽管“ROM”强调的是“只读”&#xff0c;它的数据访问方式与 RAM 类似&#xff0c;都是随机存取。 &#x1f50d; 解释如…

opensuse解决微信无法登录的问题

思路启发 https://forum.suse.org.cn/t/topic/17183/2 实际解决 https://forum.suse.org.cn/t/topic/17204/5 解决方法 先安装 sudo zypper install execstackcd /opt/wechatsudo bash -c execstack -c ./*.so

Adixen ASM380 氦气检漏仪 阿尔卡特Mobile high performance helium leak detector

Adixen ASM380 氦气检漏仪 阿尔卡特Mobile high performance helium leak detector