news 2026/9/4 6:44:58

STM32 串口发送接收与数据包学习笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32 串口发送接收与数据包学习笔记

数据包理论

一、为什么需要数据包

一帧只能传 8 位

串口物理层一帧 = 起始位 + 8 数据位 + 停止位,一次只能传 1 个字节。可实际通信往往要传一组有含义的信息

打包

给数据加上固定的边界标记,让接收方"一看就知道这包从哪开始、到哪结束":

┌────┬─────────────┬────┐ │包头 │ 数据区 │包尾 │ └────┴─────────────┴────┘ 固定值 内容 固定值

二、数据包的基本格式

一个完整的数据包通常包含:

部分

作用

说明

包头(Head)

标记"一包从这里开始"

1~2 个固定字节,如0xFF@

数据区(Data)

真正要传的内容

长度固定或可变

包尾(Tail)

标记"这包到此结束"

固定字节,如0xFC\r\n

校验(Check,可选)

检测传输是否出错

和校验/CRC 等

发送与接收两端必须约定同一套格式(通信协议),否则无法互相理解。

三、两种数据包类型

1. HEX 数据包(十六进制/原始数据包)

包头 数据区 包尾 0xFF 0xFE │ 0x01 0x02 0x03 │ 0xFC

特点

说明

边界

不可见控制字节(0xFF 等)当包头包尾

数据

直接传二进制数值(原始数据)

优点

传输高效、紧凑

缺点

不可读、需程序解析、数据区不能出现和包头相同的值(要转义)

适用

程序间通信、传感器数据、指令下发

2. 文本数据包(ASCII/字符数据包)

包头 数据区 包尾 @ │ "123 456" │ \r\n

特点

说明

边界

可见字符@\r\n回车换行)当包头包尾

数据

以 ASCII 文本传输(如 “123” 是 3 个 ASCII 字符)

优点

人眼可读、上位机解析简单、调试方便

缺点

效率低(数字要转字符串)、传输量大

适用

调试输出、人机交互、简单上位机协议

3. 对比表

对比项

HEX 数据包

文本数据包

包头示例

0xFF 0xFE

@

包尾示例

0xFC

\r\n

数据形态

二进制原始值

ASCII 字符

人眼可读性

✗ 不可读

✓ 可读

传输效率

解析难度

需处理转义

简单直观

常见场景

指令/传感器

调试/上位机

四、固定长度可变长度

数据区的长度有两种设计方式:

1. 固定长度数据包

数据个数固定,接收方数够指定个数即为一包,甚至不需要包尾。

包头(0xFF) 数据1 数据2 数据3(固定3个) ← 数到3个即收完

2. 可变长度数据包

数据个数不定,必须靠包尾来判定一包结束。

包头(0xFF) 数据...(数量不定)... 包尾(0xFC) ← 看到包尾才收完

长度固定与否决定了拆包逻辑——固定数个数,可变看包尾。

五、打包与拆包思想

1. 发送端:打包

按协议格式把数据"组装"再逐个发送:

填包头 → 填数据 → 填包尾 → 依次 Serial_SendByte 发出

2. 接收端:拆包

接收是边收边判断的,用"状态机"描述:

┌─────────────────────────────────────────┐ ▼ │ 状态0:等包头 ──收到包头──► 状态1:收数据 ──收到包尾──► 状态2:处理数据 ▲ │ └────────────── 处理完回到状态0,等下一包 ◄──────────────┘

状态

干什么

状态0(等包头)

收到包头 → 转状态1;否则继续等

状态1(收数据)

数据存入缓冲区;收到包尾 → 转状态2

状态2(处理)

校验/解析缓冲区内容 → 回状态0

状态机的好处:不阻塞。每来一个字节喂给它,它自动流转,主程序不用死等整包。

3. 数据区出现包头值

HEX 包用0xFF当包头,若数据里恰好也有0xFF,接收方会误判为新包头:

转义:数据中的包头值改成两个字节的转义序列(如0xFF0xFD 0x01)或用连续两个字节做包头0xFF 0xFE)降低误判概率。

六、数据包可能遇到的问题

问题

现象

应对

错位

一包被拦腰截断

包头定位,重新同步

粘包

多包连成一片

包头+包尾界定边界

丢帧

中间丢字节

靠包头重新同步(状态机回到等包头)

数据区含包头

误判为新包

双字节包头 / 转义

只要状态机设计得当,上述问题都能在"等包头"环节自动恢复同步。

七、接收方案总体设计

串口中断只负责"收字节存起来",拆包在专门函数里做(状态机):

串口中断:收到字节 → Serial_RxData → 置标志 主循环:把 Serial_RxData 喂给 Packet_Receive() 状态机拆包 收完一包 → PacketFlag 置位 → 主循环解析 RxPacket[]

状态机三大要素:

要素

代码体现

当前状态

uint8_t RxState(0=等包头,1=收数据,2=处理)

数据缓冲

RxPacket[PACKET_LEN](存这一包的数据)

完成标志

RxPacketFlag(收完一包置 1,主循环处理)

八、方案①:HEX 数据包收发

协议约定:包头1(0xFF) 包头2(0xFE) 数据1~3 包尾(0xFC)

/* ================= HEXPacket.c ================= */ #include "stm32f10x.h" // 包含 STM32 标准库头文件 #include "Serial.h" // 串口模块(见 9-3 笔记) /* ===== 协议定义 ===== */ #define HEAD1 0xFF // 包头1 #define HEAD2 0xFE // 包头2 #define TAIL 0xFC // 包尾 #define PACKET_LEN 3 // 固定数据个数(示例) uint8_t RxPacket[PACKET_LEN]; // 接收缓冲(本包数据) uint8_t RxPacketFlag = 0; // 收包完成标志 uint8_t RxState = 0; // 状态机当前状态 /** * @brief 发送 HEX 数据包 * @param Data 数据指针;Length 数据个数 */ void HEXPacket_Send(uint8_t *Data, uint8_t Length) { uint8_t i; Serial_SendByte(HEAD1); // 包头1 Serial_SendByte(HEAD2); // 包头2 for (i = 0; i < Length; i++) { Serial_SendByte(Data[i]); // 数据 } Serial_SendByte(TAIL); // 包尾 } /** * @brief 接收状态机,每收到一字节调用一次 * @param Byte 收到的字节 */ void HEXPacket_Receive(uint8_t Byte) { static uint8_t DataIndex = 0; switch (RxState) { case 0: // 等包头1 if (Byte == HEAD1) { RxState = 1; } break; case 1: // 等包头2 if (Byte == HEAD2) { RxState = 2; // 包头完整,开收数据 DataIndex = 0; } else if (Byte != HEAD1) { RxState = 0; } // 非包头,重新等 break; case 2: // 收数据 if (Byte == TAIL) // 包尾到了 { RxState = 3; } else if (DataIndex < PACKET_LEN) { RxPacket[DataIndex] = Byte; // 存入缓冲 DataIndex++; } break; case 3: // 收包完成,转主循环处理 RxPacketFlag = 1; RxState = 0; break; } } /** * @brief 查询收包标志 * @retval 1=收到完整一包 */ uint8_t HEXPacket_GetFlag(void) { if (RxPacketFlag == 1) { RxPacketFlag = 0; return 1; } return 0; }
/* ================= HEXPacket.h ================= */ #ifndef __HEXPACKET_H // 防止头文件重复包含 #define __HEXPACKET_H #include "stm32f10x.h" extern uint8_t RxPacket[]; // 接收到的数据 extern uint8_t RxPacketFlag; // 收包标志 void HEXPacket_Send(uint8_t *Data, uint8_t Length); // 打包发送 void HEXPacket_Receive(uint8_t Byte); // 状态机收包 uint8_t HEXPacket_GetFlag(void); // 查收包标志 #endif

九、方案②:文本数据包收发

协议约定:@ "数据(ASCII文本,不定长)" \r \n

与 HEX 包区别:

HEX 包

文本包

包头

0xFF 0xFE

@

包尾

0xFC

\r\n(两个字节)

数据

二进制

ASCII,收完要加'\0'变字符串

可读性

不可读

可直接 printf / 显示

/* ================= TextPacket.h ================= */ #ifndef __TEXTPACKET_H // 防止头文件重复包含 #define __TEXTPACKET_H #include "stm32f10x.h" extern uint8_t RxPacket[]; // 接收到的文本(含 '\0') extern uint8_t RxPacketFlag; // 收包标志 void TextPacket_Send(char *Data); // 打包发送 void TextPacket_Receive(uint8_t Byte); // 状态机收包 uint8_t TextPacket_GetFlag(void); // 查收包标志 #endif

十、主函数:中断收字节 → 喂状态机

/* ================= main.c ================= */ #include "stm32f10x.h" // 包含 STM32 标准库头文件 #include "Delay.h" // 延时模块 #include "OLED.h" // OLED 模块 #include "Serial.h" // 串口模块(9-3,含中断接收) #include "HEXPacket.h" // HEX 包 #include "TextPacket.h" // 文本包 uint8_t TestData[] = {0x01, 0x02, 0x03}; // 测试数据 /** * @brief 主函数:串口中断收字节 → 主循环喂状态机拆包 */ int main(void) { OLED_Init(); Serial_Init(); // 串口 + 中断接收 while (1) { // 每 1 秒发一个 HEX 包 HEXPacket_Send(TestData, 3); Delay(1000000); // 中断收到字节 → 喂给两个状态机(分别拆 HEX/文本包) if (Serial_GetRxFlag() == 1) { HEXPacket_Receive(Serial_RxData); // HEX 包状态机 TextPacket_Receive(Serial_RxData); // 文本包状态机 } // 收到完整 HEX 包:显示内容 if (HEXPacket_GetFlag() == 1) { OLED_ShowHexNum(1, 1, RxPacket[0], 2); OLED_ShowHexNum(1, 5, RxPacket[1], 2); OLED_ShowHexNum(1, 9, RxPacket[2], 2); } // 收到完整文本包:当字符串显示 if (TextPacket_GetFlag() == 1) { OLED_ShowString(3, 1, (char *)RxPacket); } } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 6:44:54

EHR数据补全实战:从缺失值处理到混合模型构建

简介&#xff1a;本资源面向备战2026年江西省研究生数学建模竞赛的参赛团队&#xff0c;聚焦赛题2——电子健康记录&#xff08;EHR&#xff09;数据补全这一典型高维稀疏数据建模问题&#xff0c;提供从解题思路、算法实现到论文撰写的全栈式解决方案。压缩包共117个文件&…

作者头像 李华
网站建设 2026/9/4 6:44:40

改完UA改Cookie还是被封?拆解TLS指纹与HTTP/2协议级反爬的底层逻辑

做工业数据采集的工程师近两年应该都有明显体感&#xff1a;访问控制的战场已经从应用层下沉到了协议层。 以前封IP、校验UA、验证Cookie、过滑块验证码&#xff0c;一套组合拳下来总能找到绕行方案&#xff1b;现在很多站点&#xff0c;你把请求头改得和浏览器一模一样&#x…

作者头像 李华
网站建设 2026/9/4 6:42:40

MATLAB实现实时人体异常行为检测系统:从算法到GUI应用开发

简介&#xff1a;本资源是一个面向计算机视觉初学者与MATLAB进阶用户的实战型项目&#xff0c;聚焦视频监控场景下的实时人体异常行为检测与识别问题&#xff0c;适用于安防系统开发、智能视频分析课程设计及毕业设计参考。压缩包共769个文件&#xff0c;含755张标注样本图像&a…

作者头像 李华
网站建设 2026/9/4 6:42:35

头歌实践教学平台:大数据存储2023(二十一下)

二十一、MongoDB 实验——java 和 MongoDB第2关&#xff1a;Java 操作 MongoDB 数据库&#xff08;二&#xff09;任务描述 本关任务&#xff1a;根据编程要求&#xff0c;使用 Java 代码完成文档的检索&#xff08;查询&#xff09;、更新与删除。相关知识 为了完成本关任务&a…

作者头像 李华
网站建设 2026/9/4 6:41:33

API技术驱动GEO内容生态:新闻发稿平台的底层价值重构

AI搜索时代&#xff0c;内容"被看见"的规则已经改变2025年以来&#xff0c;以ChatGPT、DeepSeek、文心一言、Kimi等为代表的生成式AI搜索引擎&#xff0c;正在重塑互联网信息的分发格局。用户获取信息的方式&#xff0c;从传统的"搜关键词-翻列表-点链接"三…

作者头像 李华