跳转到内容

串口编程/数据包的形成

来自 Wikibooks,开放的世界,开放的书籍

几乎所有关于计算机之间通信的想法都涉及“数据包”,尤其是在涉及到超过两台计算机的情况下。

这个想法非常类似于将支票放入信封中寄给电力公司。我们把要发送给特定计算机的数据(“支票”)放在一个“信封”里,这个信封包含特定计算机的地址。

数据包从一个前导码开始,接着是头信息,然后是原始数据,最后用一些额外的字节用于传输相关的错误检测信息——通常是一个 Fletcher-32 校验和。我们将在下一章 串口编程/错误校正方法 中详细讨论如何处理这些错误检测信息。

电力公司的会计在收到支票后会扔掉信封。她已经知道她自己公司的地址了。但这是否意味着信封的“开销”毫无用处?不。

同样地,一旦一台计算机收到数据包,它会立即扔掉前导码。如果计算机看到数据包的地址是它自己,并且没有错误,那么它会丢弃包装并保留数据。

头信息包含所有路由器和交换机用来将完整的数据包发送到正确目标地址的目标地址信息,就像纸质信封上写着邮递员用来将邮件发送到正确目标地址的目标地址一样。大多数协议使用一个头信息,像大多数纸质邮件信封一样,还包括源地址和一些其他传输相关信息。

不幸的是,数据包有几十种略微不同、不兼容的协议,因为人们选择略微不同的方式来表示地址信息和错误检测信息。

…… 不兼容协议之间的网关 ……

数据包大小的权衡

[编辑 | 编辑源代码]

协议设计人员根据许多权衡选择最大和最小数据包大小。

  • 数据包应该“小”以防止一个发射机发送一个长数据包来占用网络。
  • 数据包应该“小”以便单个错误可以通过重新传输一个小数据包而不是一个大数据包来纠正。
  • 数据包应该“大”以便更多时间用于传输好数据,更少时间用于开销(前导码、头信息、尾信息、后导码和数据包间隙)。
  • 数据包头信息和尾部信息应该很短,以减少开销。
  • 尾部信息应该包含一个大的错误检测码字字段,因为一个较短的码字更容易错误地接受一个错误严重的数据包(我们将在下一章 ../错误校正方法/ 中更详细地讨论错误检测)。
  • 使数据包头信息稍微长一些,以便有意义的字段落在字节或字边界上,而不是高度编码的位字段,使 CPU 更容易解释它们,从而允许更低成本的网络硬件。
  • 使数据包头信息稍微长一些——而不是一个涵盖整个数据包的单个错误检测字段,我们有一个用于头信息的错误检测字段,另一个用于数据的错误检测字段——允许一个节点立即拒绝一个在目标地址或长度字段中出现位错误的数据包,避免不必要的处理。相同的 CRC 多项式用于两者。这种只涵盖头信息的“额外”CRC 在几种文件格式中使用[1]——它是 MPEG 音频文件格式的可选功能[2][3][4],gzip 格式的可选功能等等。
  • 固定大小的数据包——所有数据包都属于几个长度类别——不需要“长度”字段,简化缓冲区分配,但在您想发送不是固定数据大小的精确倍数的数据时,会浪费“内部”数据空间来填充最后一个数据包。

数据包起始和透明度的权衡

[编辑 | 编辑源代码]

不幸的是,任何通信协议都无法拥有所有这些理想的功能

  • 透明度:数据通信是透明的,并且是“8 位干净”的——(a) 任何可能的数据文件都可以传输,(b) 文件中的字节序列始终被视为数据,而绝不会被误解为其他东西,(c) 目标接收整个数据文件,没有错误,没有添加或删除任何内容。
  • 简单复制:如果我们只是简单地将数据从源盲目地复制到数据包的数据字段中而不进行任何更改,那么形成数据包最容易。
  • 唯一起始:数据包起始符号很容易识别,因为它是一个已知的常数字节,在头信息、头信息 CRC、数据有效负载或数据 CRC 中任何地方都不会出现。
  • 8 位:只使用 8 位字节。

一些通信协议会破坏透明度,需要在其他地方增加复杂性——需要更高的网络层来实现变通方法,例如 w:二进制到文本编码,否则会遇到神秘的错误,就像 w:时间无关转义序列 那样。

一些通信协议会打破“8 位”——也就是说,除了 256 个可能的字节之外,它们还有“额外的符号”。一些通信协议只有少数几个额外的非数据符号——例如用作 Hayes 转义序列一部分的“长暂停”;用作 SDI-12 协议一部分的“长断开”;4B5B 编码、8b/10b 编码中的“命令字符”或“控制符号”等。其他系统,例如 9 位协议,[5][6][7][8][9][10][11] 传输 9 位符号。通常数据包的第一个 9 位符号的高位设置为 1,唤醒所有节点;然后每个节点检查数据包的目标地址,所有非目标节点都进入休眠状态。数据包中的其余数据(和 ACK 响应)以 9 位符号传输,高位清零到 0,有效地为 8 位值,休眠节点会忽略这些值。(这类似于 MIDI 消息中所有数据字节实际上都是 7 位值的方式;仅在 MIDI 消息的第一个字节中设置高位)。唉,一些 UART 使得发送和接收这种 9 位字符变得很尴尬,[12][13] 困难或不可能。

一些通信协议会打破“唯一开始”——也就是说,它们允许非唯一的开始数据包符号出现在其他地方——最常见的原因是我们正在发送包含该字节的文件,而“简单复制”会将该字节放入数据有效负载中。当接收器第一次打开,或当电缆拔掉后重新连接,或当噪声破坏了原本应该作为真实开始数据包符号的内容时,接收器会错误地将该数据解释为开始数据包。即使接收器通常会识别出出现问题(校验和失败),一次这样的噪声故障也可能导致许多数据包丢失,因为接收器在(错误地)将有效负载中的该数据字节解释为开始数据包,以及(错误地)将真实的开始数据包符号解释为有效负载数据之间来回切换。更糟糕的是,这些常见问题可能会导致接收器丢失对字符开始和结束位置的跟踪。早期的协议设计者认为,一旦同步丢失,就必须有一个唯一的开始数据包字符序列来重新获得同步。[14] 之后的协议设计者设计了一些协议,例如基于 CRC 的帧,[15] 不仅打破了“唯一开始”——允许数据有效负载包含与开始数据包相同的字节序列,支持简单复制透明性——它们甚至不需要固定的不变的开始数据包字符序列。

为了保留“唯一开始”功能,许多通信协议会打破“简单复制”。这需要一些额外的软件,并且每个数据包需要比简单复制数据更多的时间——这在现代处理器中通常可以忽略不计。这种笨拙之处在于(a)确保整个过程——发射机将原始数据的块编码/转义为数据包有效负载,该有效负载必须不包含开始数据包字节,以及接收器将数据包有效负载解码/解转义为原始数据的块——对所有可能的原始数据字节序列都是完全透明的,即使这些字节包含一个或多个开始数据包字节,并且(b)由于编码/转义的有效负载数据不可避免地比原始数据需要更多字节,我们必须确保我们即使在最坏的情况下也不溢出任何缓冲区,并且(c)与“简单复制”不同,在“简单复制”中,有效负载数据位的恒定比特率会导致原始数据位的相同恒定吞吐量,我们必须确保系统被设计为处理有效负载数据比特率或原始数据比特吞吐量或两者的变化。通过使用一致开销字节填充(COBS),[16] 可以减少一些这种笨拙之处,而不是可变开销字节填充技术,例如 SLIP 使用的技术。

计算 CRC 并将其附加到数据包,*在*用 COBS 对原始数据和 CRC 进行编码之前。 [17]

前导码

[edit | edit source]

前导码的两种流行方法是

  • 第一个发射机发送足够的前导码位,以便此跳跃的接收器锁定。然后它发送数据包。该接收器一旦知道它需要转发数据包到另一个跳跃,就会在下一个跳跃上发送一个新的完整大小的前导码,后面跟着数据包。好处是,无论数据包跳跃多少次,相对较短的固定长度前导码就足够了。
  • 第一个发射机发送一个长得多的前导码,远远超出此跳跃的接收器锁定所需的长度。然后它发送数据包。该接收器,一旦检测到前导码,就会立即将每个传入的位从另一个端口发送出去,直到到达数据包的末尾。好处是中继节点可以非常简单,因为它们不需要存储任何数据。前导码消耗 (w:5-4-3 规则#前导码消耗) 会使前导码在每个跳跃后越来越短——丢失太多位,最终没有足够的前导码位来锁定,整个数据包都会丢失。

自动波特率检测

[edit | edit source]


Clipboard

待办事项
简单介绍一下自动波特率检测 (autobaud)。(串行编程书籍的哪个部分更适合讨论 autobaud 实现?)




进一步阅读

[edit | edit source]
  1. Andy McFadden。 "文件格式设计"
  2. 维基百科:基本流
  3. Gabriel Bouvigne。 "MPEG 音频层 I/II/III 帧头"
  4. Predrag Supurovic。 "MPEG 音频帧头"
  5. uLan:9 位面向消息的通信协议,通过 RS-485 链接传输。
  6. Pavel Pisa。 "uLan RS-485 通信驱动程序" "9 位面向消息的通信协议,通过 RS-485 链接传输。"
  7. Peter Gasparik。 "9 位数据传输格式"
  8. Stephen Byron Cooper。 "9 位串行协议".
  9. "使用 PC 的 UART 与 9 位协议"。1998 年。
  10. 维基百科:多点总线 (MDB) 是一种在许多自动售货机中使用的 9 位协议。
  11. ParitySwitch_9BitProtocols:操纵奇偶校验以模拟 9 位协议
  12. "使用 PC 的 UART 与 9 位协议"。电子设计。1998 年 12 月。
  13. Thomas Lochmatter。 "Linux 和 MARK/SPACE 奇偶校验"。2010 年。
  14. J. Robinson。 RFC 935。 "可靠的链路层协议"。1985 年。引用:"一旦检测到报头错误,计数字段必须假定为无效,因此必须有一个唯一的字符序列来引入下一个报头,以便接收器可以重新与发送器同步。"
  15. 维基百科:基于 CRC 的帧
  16. "一致开销字节填充" 作者 Stuart Cheshire 和 Mary Baker,1999 年。
  17. Jason Sachs。 "救命,我的串行数据被帧化了:如何在只有流的情况下处理数据包"。2011 年。
“CMX-MicroNet 是第一个允许 TCP/IP
以及其他协议在小型处理器上原生运行的系统
... [包括] AVR、PIC 18、M16C。”
华夏公益教科书