在我的 UART 通信中,我需要知道所发送消息的起始字节和停止字节。开始字节很容易,但停止字节就不那么容易了。我在消息末尾实现了两个停止字节,即 \n 和 \r(十进制的 10 和 13)。UART 仅适用于字节 0-255 的值,那么它的故障安全性如何?我可以想象,虽然概率很低,但当它们不是停止字节时,我的消息可能会包含一个接一个的值“10 和 13”。
有没有更好的方法来实现这一点?
在我的 UART 通信中,我需要知道所发送消息的起始字节和停止字节。开始字节很容易,但停止字节就不那么容易了。我在消息末尾实现了两个停止字节,即 \n 和 \r(十进制的 10 和 13)。UART 仅适用于字节 0-255 的值,那么它的故障安全性如何?我可以想象,虽然概率很低,但当它们不是停止字节时,我的消息可能会包含一个接一个的值“10 和 13”。
有没有更好的方法来实现这一点?
有不同的方法可以防止这种情况:
20 21 22 23 24 25 10 13
20 21 1b 10 1b 13 25 26
<nr_of_data_bytes > <数据>
如果您的消息最大为 256 字节,请发送:
06 20 21 22 23 24 25
所以你知道在收到 6 个数据字节后就结束了;之后您不必发送 10 13 。您可以在消息中发送 10 13 。如果您的消息可以更长,您可以使用 2 个字节作为数据大小。
更新 1:另一种定义数据包的方法
另一种选择是发送具有特定长度并且可以有很多变化的命令,例如
10 20 30(命令 10 总是有 2 个数据字节)
11 30 40 50(命令 11 始终具有 3 个数据字节)
12 06 10 11 12 13 14 15(命令 12 + 1 字节用于后面的数据字节数)
13 01 02 01 02 03 ...(命令 13 + 2 个字节(01 02 表示 256 + 2 = 258 个数据字节)
14 80 90 10 13(命令 14 后跟以 10 13 结尾的 ASCII 字符串)
更新 2:连接错误/字节丢失
以上所有方法仅在 UART 线路正确发送字节时有效。如果您想使用更可靠的发送方式,也有很多可能性。以下是一些:
请注意,上述所有机制可以简单,也可以根据您的需要(或需要)复杂。在重新发送消息的情况下,还需要一种识别消息的机制(例如,将序列号添加到包中)。
\n\r 作为停止字节的故障安全性如何?
如果您发送任意数据 -> 可能不够安全。
一个常见的解决方案是使用转义:
让我们定义字符 0x02(STX - 帧开始)和 0x03(ETX - 帧结束)在传输的数据流中必须是唯一的。这样可以安全地检测消息的开始和结束。
如果应在消息帧中发送这些字符之一,则将其替换为前缀转义字符 (ESC = 0x1b) 并将 0x20 添加到原始字符。
原始字符替换为
0x02 -> 0x1b 0x22
0x03 -> 0x1b 0x23
0x1b -> 0x1b 0x3b
接收者反转这个过程:任何时候他收到一个转义字符,这个字符被丢弃,下一个字符被减去 0x20。
这只会增加一些处理开销,但 100% 可靠(假设没有发生传输错误,您可以/应该通过额外实施校验和机制来验证)。
你知道,ASCII 已经有这些函数的字节。
它还在有效载荷内具有各种用途的代码。
您的协议应指定 ACK (0x06) 和 NAK (0x15) 的最细粒度,以便可以重新传输否定的确认数据。在最精细的粒度下,明智的做法是在任何(未转义的)开始指示符之后立即有一个长度字段,并且(如其他答案中所述)在任何(未转义的)停止指示符之后使用 CRC 是明智的。
UART 本质上并不是故障安全的——我们在这里谈论的是 1960 年代的技术。
问题的根源在于 UART 每 10 位仅同步一次,从而允许在这些同步周期之间传递大量乱码。与例如 CAN 不同,它对每个单独的位进行多次采样。
数据内部发生的任何双位错误都会破坏 UART 帧,并且不会被检测到。开始/停止位中的位错误可能会或可能不会以溢出错误的形式被检测到。
因此,无论使用原始数据还是数据包,EMI 引起的位翻转总是有可能导致意外数据。
有许多“传统的 UART 骗子”方法可以稍微改善这种情况。您可以添加同步字节、同步位、奇偶校验、双停止位。您可以添加校验和来计算所有字节的总和(然后将其反转 - 因为为什么不),或者您可以将二进制数作为校验和来计算。所有这些都被广泛使用,非常不科学,并且很可能会丢失错误。但这就是人们从 1960 年代到 1990 年代所做的事情,以及许多像今天这样的奇怪事情。
处理 UART 安全传输的最专业方法是在数据包末尾添加 16 位 CRC 校验和。其他一切都不是很安全,并且很可能会丢失错误。
然后在硬件层面,您可以使用差分 RS-422/RS-485 来大幅提高传输的耐用性。这是长距离安全传输的必要条件。TTL 电平 UART 只能用于板载通信。RS-232 不应用于任何其他目的,但应与旧东西向后兼容。
总的来说,你的错误检测机制越接近硬件,它就越有效。在有效性方面,差分信号增加最多,其次是检查帧/溢出等错误。CRC16 增加了一些,然后“传统的 UART quackery”增加了一点。