利用ESP32开发一种更智能的UART字节传输方式
我为何开发它(问题所在)
如果你曾经连接过两个微控制器——比如ESP32和STM32——你很可能使用过UART。通常,最简单的数据传输方式是通过来回发送纯文本字符串。
这种方法虽然可行,但容易出问题。当我编写裸机轮询循环(不使用中断或DMA)时,发现了一个严重的问题:如果接收端的微控制器正在执行其他任务而错过单个字节——即典型的缓冲区溢出错误——整个文本流就会发生偏移。
想象一下这样的场景:你的ESP32在发送温度和湿度数据。如果丢失了一个字节,接收端的字符串解析器就会混乱。它可能将一半的温度值和一半的湿度值读取为一个整数,从而将完全损坏的数据保存到变量中。
BAVA是什么(解决方案)
我希望有一种更安全的方式,在不依赖复杂库的情况下实现线路上的数据传输。于是,我开发了BAVA。它是一个轻量级的C语言库,直接位于标准UART之上,为通信添加结构化和安全性。
BAVA 不会发送文本,而是将你的变量打包成整洁的二进制帧。
[起始标记] -> [命令] -> [ID] -> [长度] -> [有效载荷] -> [CRC-16]
•起始标记(0xAA):告诉接收方有新数据包到达。
•命令:告知接收方这是“写入”(保存这些数据)还是“读取”请求。
•ID:你特定变量的唯一十六进制标签。
•长度:有效载荷中确切包含的字节数。
•有效载荷:实际的原始二进制数据(你的结构体或变量)。
•CRC-16:一种数学校验和,用于验证是否有字节损坏或丢失。‘
1:定义数据与硬件设置
首先,ESP32 和 STM32 需要就数据格式达成一致。我们为遥测数据定义一个标准的 C 结构体。
接着,我们告诉 BAVA 如何与特定硬件通信。我们编写一个简单的发送回调函数,并将其传递给初始化函数。
2:注册变量(对象字典)
在此处,BAVA 取代了字符串解析。我们不再发送如“TEMP”这样的名称,而是将传感器结构体的内存地址映射到特定 ID(例如 0x01)。这一操作在两个微控制器上都执行。
3:数据传输(ESP32)
当ESP32想要发送新的传感器数据时,无需使用snprintf格式化字符串,只需更新本地的结构体,并告诉BAVA发送该特定ID即可。
BAVA会自动将结构体封装成[Start][Cmd][ID][Len][Data][CRC]帧,并通过UART线传输。为防止实际的传感器数据意外与起始标记匹配导致错误,BAVA会自动使用转义字节(0x07)安全地编码有效载荷。
4:无解析接收(STM32)
在STM32端,主轮询循环监控UART硬件。每当接收到一个字节,就会直接传入BAVA的非阻塞状态机中。
随着字节不断流入,状态机检查长度并计算CRC-16。如果硬件丢失了某个字节,CRC将失败,此时数据包会被安全忽略。
但如果数据包有效,BAVA会查找ID(0x01),并将有效载荷直接写入STM32传感器结构体的指针位置。
整个过程无需字符串解析,我们只需检查变量是否已更新,若已更新,则可立即向ESP32发送确认(ACK)数据包。
通过将十六进制ID直接映射到内存指针,BAVA能够即时更新变量。它完全不使用动态内存(无malloc调用),因此在裸机系统上具有高度的确定性。
本文编译自hackster.io





