news 2026/6/18 22:21:25

UART串口不定长数据接收方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UART串口不定长数据接收方法

一、基本概念与问题

在嵌入式系统中,串口(UART)通信时,数据通常以不定长的“帧”为单位发送。串口硬件本身只能识别单个字节的接收完成,无法自动判断一帧数据何时开始和结束。因此,需要通过软件方法来解决帧边界识别问题。

所有方法都基于一个基本的数据管理结构:

#define MAX_BUF_SIZE 200 typedef struct { uint8_t buffer[MAX_BUF_SIZE]; // 数据存储区 uint16_t count; // 已接收字节数 uint16_t length; // 帧长度 uint8_t complete_flag; // 帧完成标志 } UartRxManager; UartRxManager uart1_rx;

二、四种基础实现方法

1. 空闲中断检测法

原理

利用串口硬件的空闲检测功能:当RX引脚在一个字节传输时间后保持高电平,硬件会触发空闲中断,标志着一帧数据传输结束。

实现要点

初始化配置

// 开启空闲中断 __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); // 启动DMA接收 HAL_UART_Receive_DMA(&huart1, uart1_rx.buffer, MAX_BUF_SIZE);

中断处理

void handle_idle_interrupt(UART_HandleTypeDef *huart) { if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE)) { __HAL_UART_CLEAR_IDLEFLAG(huart); // 停止DMA并计算接收长度 HAL_UART_DMAStop(huart); uart1_rx.length = MAX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx); uart1_rx.complete_flag = 1; // 重新启动接收 HAL_UART_Receive_DMA(huart, uart1_rx.buffer, MAX_BUF_SIZE); } }

2. 协议解析法

原理

在通信协议中定义固定的帧结构,通过识别帧头、帧长等信息来确定帧边界。

协议示例
字节位置内容说明
00x5A帧头1
10xA5帧头2
2N数据长度
3~N+2数据有效载荷
实现代码
typedef enum { WAIT_HEADER1, WAIT_HEADER2, WAIT_LENGTH, RECEIVING_DATA } RxState; void process_received_byte(uint8_t byte) { static RxState state = WAIT_HEADER1; static uint8_t expected_len = 0; switch(state) { case WAIT_HEADER1: if(byte == 0x5A) { uart1_rx.count = 0; uart1_rx.buffer[uart1_rx.count++] = byte; state = WAIT_HEADER2; } break; case WAIT_HEADER2: if(byte == 0xA5) { uart1_rx.buffer[uart1_rx.count++] = byte; state = WAIT_LENGTH; } else { state = WAIT_HEADER1; // 重新同步 } break; case WAIT_LENGTH: expected_len = byte; uart1_rx.buffer[uart1_rx.count++] = byte; state = RECEIVING_DATA; break; case RECEIVING_DATA: uart1_rx.buffer[uart1_rx.count++] = byte; if(uart1_rx.count >= (expected_len + 3)) { uart1_rx.complete_flag = 1; uart1_rx.length = uart1_rx.count; state = WAIT_HEADER1; } break; } }

3. 超时判断法

原理

基于数据连续性假设:如果在一定时间内没有收到新数据,则认为当前帧已结束。

时间计算

以9600波特率为例:

  • 1个字节传输时间 ≈ 1.04ms (10位/字节 ÷ 9600位/秒)

  • 超时时间建议:1.5-2倍字节时间 ≈ 2ms

实现代码
volatile uint32_t last_receive_time = 0; #define TIMEOUT_MS 2 // 接收中断中调用 void on_byte_received(uint8_t byte) { uart1_rx.buffer[uart1_rx.count++] = byte; last_receive_time = get_current_time(); // 更新时间戳 } // 主循环中检查 void check_timeout(void) { uint32_t current_time = get_current_time(); if(uart1_rx.count > 0 && (current_time - last_receive_time > TIMEOUT_MS)) { uart1_rx.complete_flag = 1; uart1_rx.length = uart1_rx.count; uart1_rx.count = 0; // 准备接收下一帧 } }

4. 环形缓冲区法

原理

中断只负责将数据存入缓冲区,主程序从缓冲区读取并解析数据,实现接收与处理的解耦。

数据结构
typedef struct { uint8_t *data; uint16_t size; uint16_t head; // 写入位置 uint16_t tail; // 读取位置 uint16_t count; // 数据数量 } RingBuffer; void rb_init(RingBuffer *rb, uint8_t *buf, uint16_t size) { rb->data = buf; rb->size = size; rb->head = rb->tail = rb->count = 0; } uint8_t rb_write(RingBuffer *rb, uint8_t byte) { if(rb->count >= rb->size) return 0; rb->data[rb->head] = byte; rb->head = (rb->head + 1) % rb->size; rb->count++; return 1; } uint8_t rb_read(RingBuffer *rb, uint8_t *byte) { if(rb->count == 0) return 0; *byte = rb->data[rb->tail]; rb->tail = (rb->tail + 1) % rb->size; rb->count--; return 1; }
使用方式
// 中断服务程序(极简) void USART1_IRQHandler(void) { uint8_t byte = USART1->DR; rb_write(&rx_buffer, byte); } // 主程序处理 int main(void) { uint8_t byte; while(1) { if(rb_read(&rx_buffer, &byte)) { // 解析协议或处理数据 process_received_byte(byte); } } }

三、方法对比与选择

方法优点缺点适用场景
空闲中断硬件支持、效率高需要硬件支持高速连续数据
协议解析可靠性高、有校验实现较复杂有固定协议
超时判断实现简单精度依赖定时低速应用
环形缓冲区解耦接收与处理内存占用较大多任务系统

四、选择建议

  1. 简单应用:从超时判断法开始,最容易理解和实现

  2. 可靠通信:选择协议解析法,具备错误检测能力

  3. 高效接收:使用空闲中断+DMA,减少CPU干预

  4. 复杂系统:采用环形缓冲区,便于扩展和维护

实际应用中常组合使用,如:空闲中断+协议解析,或环形缓冲区+超时判断。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/18 17:55:43

COMSOL案例解析:水平井应力场耦合机制与模拟研究

comsol案例水平井应力场耦合在青海某页岩气田的钻探现场,老张盯着实时监测屏幕上突然飙升的井口压力直挠头。这种地层应力突变导致套管变形的糟心事,搞石油工程的同行们应该都不陌生。今天咱们就扒一扒COMSOL里怎么玩转水平井应力场耦合,保准…

作者头像 李华
网站建设 2026/6/13 3:44:10

职场复盘不会说?这3句话,瞬间让你在领导面前闪闪发光

每次复盘会都像公开处刑?明明做了很多事,却讲得支离破碎?看着同事侃侃而谈,自己却紧张到语无伦次?别怕,问题不在你做了多少,而在于你怎么说。今天,就教你三句“万能公式”&#xff0…

作者头像 李华
网站建设 2026/6/5 23:11:46

2026年AI情感交互测试指南:软件测试从业者的专业框架

在AI技术快速迭代的2026年,情感交互测试已成为软件测试的关键领域。本文从测试从业者视角出发,系统阐述测试策略、工具应用及挑战应对,帮助团队确保AI系统在情感识别、响应和生成上的准确性与可靠性。 一、情感交互测试的核心维度与层级 AI…

作者头像 李华
网站建设 2026/6/15 21:26:04

谷歌新操作系统 Aluminium OS 细节曝光

自 2024 年起,业内便不断有传闻称谷歌正计划打造一款全新的 PC 操作系统。去年底,谷歌正式确认了这一战略方向。然而,具体细节一直鲜有披露——直到本周,谷歌的问题追踪系统意外泄露了一段代号为 “Aluminium”的操作系统的简短视…

作者头像 李华
网站建设 2026/6/15 19:55:47

网络安全学习路线(超全攻略):从入门到精通,一篇搞定所有

在众多高大上的学习路线指导中,尝试做一股清流,把要讲清楚的都讲清楚,该学些什么,学到哪个程度进入到下一阶段的学习这些才是最重要的。 在学习之前首先要做好学习的系统规划: 1.目前市场需求主流的岗位里&#xff0…

作者头像 李华
网站建设 2026/5/29 21:32:19

丢掉向量数据库!推理型 RAG 正在重新定义长文档问答的准确边界

前言 在大模型应用落地的浪潮中,RAG(检索增强生成)一度被视为解决知识幻觉、提升事实准确性的“银弹”。然而,当开发者真正将 RAG 投入企业级场景——比如解析一份 300 页的 SEC 财报、一份技术标准文档或一本法律汇编时&#xf…

作者头像 李华