当前位置: 首页 > news >正文

串口通信中,实现串口接收函数时,避免数据丢失或被覆盖的方法

一. 简介

本文来学习一下,串口通信中,在实现串口接收函数时,如何避免数据丢失或被覆盖。可以解决的几种方法。

二. 串口通信中,实现串口接收函数时,避免数据覆盖或丢失的方法

在编写串口接收函数时,避免数据丢失或被覆盖的核心在于 合理设计缓冲区、优化接收逻辑和处理异常情况。

在串口通信中,数据覆盖或丢失通常源于接收速度与处理速度不匹配、缓冲区管理不当或中断处理不及时。以下是避免这些问题的核心策略和实现方法:

1. 使用环形缓冲区(Ring Buffer)

环形缓冲区(Ring Buffer)类似如下:

原理
  • 环形缓冲区通过头尾指针循环写入/读取数据,避免线性缓冲区的溢出问题。

  • 写入指针(head)由中断服务程序(ISR)更新,读取指针(tail)由主程序控制。

优点
  • 无数据覆盖:缓冲区满时丢弃新数据或报错。

  • 高效解耦:中断仅负责写入,主程序异步读取。

2. 流控(Flow Control)

硬件流控(RTS/CTS)
  • 通过RTS(Request to Send)和CTS(Clear to Send)引脚控制数据流。

软件流控(XON/XOFF)
  • 发送特殊字符(XOFF=0x13暂停,XON=0x11继续)。

  • 适用场景:无硬件流控引脚时。

3. 进行超时和错误处理

关键措施

        (1)数据包超时检测:

// 检查自上次接收到串口数据以来的时间是否超过了预设的超时阈值(单位:毫秒)
// HAL_GetTick() 返回系统启动后的总毫秒数(由 SysTick 定时器每 1ms 更新一次)
// last_rx_time 记录了最后一次成功接收到数据的时刻(也是用 HAL_GetTick() 获取的)
// TIMEOUT_MS 是一个宏或常量,定义了等待一帧数据完成的最大空闲时间(如 5、10 或 20ms)
if (HAL_GetTick() - last_rx_time > TIMEOUT_MS) {// 如果超时,说明很可能一包完整的数据已经接收完毕(即使没有收到结束符)// 此时调用处理函数,提交当前缓冲区中已接收到的部分或完整数据进行解析// 即使数据不完整,也尝试处理,避免数据长期滞留导致系统无响应process_incomplete_packet();// 清空接收缓冲区,重置接收状态// 防止旧数据残留影响下一包数据的接收和解析// 通常会将缓冲区索引(如 head/tail)重置为初始状态reset_buffer();
}

        (2)溢出检测:

if (USART1->ISR & USART_ISR_ORE) { // 检查溢出标志USART1->ICR |= USART_ICR_ORECF; // 清除标志handle_overflow_error(); // 错误处理
}

4. 启用硬件FIFO(如果支持)

原理
  • 许多MCU的UART模块内置硬件FIFO(如STM32的16级FIFO),可缓存多个字节再触发中断,减少中断频率。

  • 配置FIFO阈值(如半满触发中断)。

优点
  • 降低CPU负载:减少中断次数,适合高波特率场景。

5. DMA传输(大数据量场景)

原理
  • 使用DMA自动将串口数据搬运到内存,无需CPU干预。

  • 循环模式(Circular Mode):DMA持续接收数据,覆盖旧数据(需及时处理)。

优点
  • 零CPU占用:适合高速通信(如1Mbps)。

  • 抗突发数据:DMA自动处理连续数据流。

6. 双缓冲区策略(Ping-Pong Buffer)

原理
  • 使用两个缓冲区交替工作:DMA写入缓冲区A时,主程序处理缓冲区B,反之亦然。

  • 避免处理延迟导致的数据覆盖。

三. 总结

方案选型建议

下一篇文章举例来说明这几种方法的使用(可能使用单片机STM32进行举例)。

http://www.dtcms.com/a/331387.html

相关文章:

  • 20250814在荣品RD-RK3588开发板的Android13下解决卡迪的LCD屏在开机的时候brightness最暗【背光的pwm信号的极性反了】
  • 机器学习核心概念与实践笔记
  • 安卓设备通过USB,连接继电器,再通过继电器开关闸机
  • 前端包管理工具
  • 【FreeRTOS】任务管理:创建与删除任务,任务优先级与阻塞
  • 计算机网络---传输控制协议Transmission Control Protocol(TCP)
  • Redis的 ​​散列(Hash)​​ 和 ​​列表(List)​​ 数据结构操作详解
  • 力扣-64.最小路径和
  • 【AI推理部署教程】使用 vLLM 运行智谱 GLM-4.5V 视觉语言模型推理服务
  • 电商双 11 美妆数据分析总结(补充)
  • 入门概述(面试常问)
  • 中久数创——笔试题
  • Android构建工具版本兼容性对照表
  • Git 中切换到指定 tag
  • 会议系统核心流程详解:创建、加入与消息交互
  • 卫星通信链路预算之七:上行载噪比计算
  • MySQL-dble分库分表方案
  • 【最新版】怎么下载mysqlclient并成功安装?
  • 物化视图优先迁移大表,缩短逻辑迁移时间
  • MySql——binlog和redolog的区别
  • uniapp开发动态添加密码验证
  • Go语言全面解析:从入门到精通
  • C/C++ 指针与内存操作详解——从一级指针到字符串转换函数的完整解析
  • 拒绝“孤岛式”作战,全方位构筑隧道应急通信解决方案
  • Java 学习笔记(基础篇2)
  • 13、C 语言结构体尺寸知识点总结
  • LeetCode 刷题【41. 缺失的第一个正数】
  • 【力扣322】零钱兑换
  • 非容器方式安装Prometheus和Grafana,以及nginx配置访问Grafana
  • GraphRAG查询(Query)流程实现原理分析