什么时候应该从ASCII切换到高级串行协议?


28

我所有通过UART与PC通信的微控制器设备都使用ASCII字符串发送命令和接收数据(在Arduino中实现)。这是我开始研究电子产品时学到的,我总是发现发送裸线就足够了。但是我注意到,我遇到的大多数设备都使用复杂的二进制协议,其中包括功能代码,地址和CRC错误检查。

什么时候可以接受基本的ASCII通讯?何时应该考虑使用更高级的功能,例如Modbus?商用设备是否使用这种ASCII?产业?


3
简短的答案:当您的应用程序需要它时。是的,商用设备使用ASCII。以GPS NMEA为例。(再次,我将在这里引用我自己的问题
Eugene Sh。

1
Modbus具有ASCII模式。请参见Modicon Modbus协议参考指南
Tut 2015年

@EugeneSh .:值得注意的是NMEA有一个校验和字段,并且由于校验和失败(比您想象的要多发生)而丢弃单个样本脉冲串通常不是严重的失败。对于其他协议,情况可能并非如此…… 并且有很多二进制GPS协议(例如Garmin)用于那些确实很关键的应用(或其中采样率高于1Hz的应用) NMEA过于冗长)。虽然这确实只会巩固您的观点。
与Monica进行的Lightness竞赛

Answers:


28
  1. ASCII和CRC不互斥。ASCII是一种编码,而CRC是用于错误检查。

  2. 任何东西都可以ASCII形式发送。我们的老人们肯定记得UUEncoding,它将任何东西转换为ASCII字符串。

  3. 答:对我来说,通常是速度和效率的问题。通过ASCII发送大的32位数字可能会花费很长时间,但是通过串行协议以二进制形式发送它只需要4个字节。

    B)通过ASCII发送数字意味着您必须将数字转换为ASCII,这是一个明显的额外步骤(这是“ printf”功能的一部分)。

  4. 如果您以某种方式迷失了自己的位置,搞砸了,丢失了格式,获取了错误的字节序等,那么二进制通信协议肯定会搞砸了。如果要发送ASCII,则只需进入并查找数据流,就可以更轻松地从乱码中恢复。


12
+1为“ ASCII是一种编码”。这不是协议;协议可以建立在ASCII之上。
Pete Becker 2015年

8
对于基于文本的协议,从二进制文件中自动恢复并不是一件容易的事,但是对它进行检查和调试无疑是一件容易的事。
尼克·约翰逊

1
@NickJohnson-绝对。一旦您要在十六进制编辑器中打开文件以查看可以恢复的内容,就SOP而言,您已经在FUBAR上了
Scott Seidman

1
@nickjohnson并非如此。ASCII为您提供了许多带外成帧/定界符选项,以帮助进行同步和恢复,如果该通道用于全宽二进制数据,则将需要额外的转义,位填充,时间间隔或其他技巧。
克里斯·斯特拉顿

2
在编写协议时,我总是偏爱ASCII,以获得所有明显的好处(可读性,可记录性等)。在两种情况下,使用二进制更有意义:首先,如果速度是一个问题,并且您需要二进制以将尽可能多的数据塞入流中;其次,如果您有意试图混淆或什至加密数据,则需要进行少量的处理。阻碍或阻止逆向工程。那时,我已经对二进制协议进行了逆向工程,它在很大程度上使我不仅仅真正阻止了这种行为。
J ...

10

这里有一些想法:

  • ASCII很好,因为您可以使用串行监视器来手动查看发送的内容。
  • 如果连接不可靠,则必须预见到传输错误,并应使用CRC来检查每个接收到的消息的完整性。这也可以在ASCII消息上完成。
  • 如果连接速度太慢,可以通过切换为二进制格式来减小消息的大小
  • 专用二进制格式在接收方可能比ASCII更容易解码

7

在最简单的级别上,您可以说一个简单的通信协议具有三层:物理层,传输层和应用程序。(有些模型具有更多功能,例如OSI带有7或TCP / IP带有4。在此问题中,层数并不是很重要。)

应用程序层是您直接在代码中处理的层,也是问题的焦点。就传输层而言,您在send_data中传递给它的字节只是一个二进制模式,但是您可以在应用程序代码中将其解释为字母“ A”。无论您认为字节是'A',0x41还是0b01000001,CRC或校验和的计算都是相同的。

传输层是数据包级别,在其中具有消息头和错误检查(无论是CRC还是基本校验和)。在固件环境中,您可能具有诸如send_data之类的功能,在其中向其传递了一个字节以进行发送。在该函数内部,它放入一个数据包,其中说:“嘿,这是一条正常消息,需要确认,校验和为0x47,当前时间为X。” 该数据包通过物理层发送到接收节点。

物理层是定义电子设备和接口的地方:连接器,电压电平,时序等。该层的范围可以从运行PCB上基本UART的TTL信号的几条迹线到某些电路中的完全隔离的差分对。CAN实施。

在接收节点,数据包进入物理层,在传输层解包,然后您的二进制模式可用于应用程序层。由接收节点应用程序层知道该模式应解释为“ A”,0x41还是0b01000001,以及如何处理。

总之,如果这是应用程序所需要的,发送ASCII字符几乎总是可以接受的。重要的是要了解您的通信方案,并包括一个错误检查机制。


Ascii协议也可以合并校验和。我已经使用数字的ascii表示遇到了十六进制的ascii变体。
尤金(Eugene Sh)。

@EugeneSh。澄清了这一点
马特·杨

不用说挑剔,但是TCP并不是四层。它被视为适合OSI模型的第四层。串行通信并不十分适合OSI模型。
batsplatsterson,2015年

@batsplatsterson这很挑剔,与我要说的很不相关。
马特·杨

5

还没有提到的一点是,无论是使用ASCII还是二进制协议,在每个数据包之前发送擦除字符都将确保即使在数据包开始之前出现了线路噪声或成帧错误,所有字符都将在擦除后在没有其他噪音的情况下,将正确构图。否则,如果一个人连续发送数据包并且不包含保证实现重新同步的任何字符,则一个小故障可能会破坏随后的所有内容,直到下一次传输暂停为止。0xFF字符很不错,因为它可以确保任何收件人都可以在以下字符上重新同步。

(*)0xFF-之所以称为“擦除”,是因为在纸带上键入数据时键入错误字符的人可以按下“向后步进磁带”按钮,然后按“擦除”以将错误打孔的字符替换为0xFF,这将被大多数收件人忽略)。


2

发送ASCII字符串的优点之一是控制代码可用于发信号通知消息的开始/结束。例如,STX(字符2)和ETX(字符3)可以发出开始传输和结束传输的信号。或者,您可以添加简单的换行符以标记传输结束。

当发送二进制数据时,这变得更加复杂,因为不能为控制代码保留特定的位模式(没有一些额外的开销或复杂性),因为有效数据字节可能具有相同的模式。


3
许多二进制协议确实保留一个或多个位模式作为控制代码,但是它们还包括转义机制,用于在数据中出现这些代码时对其进行处理。
戴夫·特威德

您可以保留任何模式来标记您想要的二进制文件。例如,我在一个项目中,快速数据流和慢速数据流都出自同一项目。我保留了最大的负INT32作为我慢数据的标记,而只是在最大负+ 1浸透我的负面数据
斯科特塞德曼

同意 我希望在编辑后的答案中对此进行了澄清。
晶体管

2

ASCII很好,我几乎在所有项目中都使用它。它使调试端口的调试变得更加容易,并且只有在要发送大量数据的情况下,这才成为问题。

另一个好处是,我使用串行无线电设备在arduinos之间获取消息,并且可以使用连接到笔记本电脑的串行监视器并注入消息以使某些事情发生。非常适合测试。

同样,以二进制形式发送内容并非不可能进行调试,并且取决于您的工具,您可以提取二进制并将其转换为人类可读的内容。或者,如果您知道要查找的内容,则可以直观地检查数据流并识别它们应在的值,并以这种方式进行故障查找,尽管不那么容易。即,您将识别字节模式并识别期望值


2

代替Modbus,请考虑使用HDLC。您将获得错误检测(这对于嘈杂的串行线路很重要)。同步功能强大,转义功能强大。

我已经在RS-485网络中使用HDLC了,而PPP也使用了它。


2
如果您指出了为什么要通过Modbus提出建议,那就更好了。
我不知道自己在做什么

1

UART上的ASCII是最受欢迎的部分原因是:

  • 在调试时,它是人类可读的(我还没有看到不解码ASCII的逻辑分析仪)。

  • 这很容易实现,您已经通过快速google标准化了ASCII表。

  • 它具有与开始/停止位同步的功能。

  • 整个嗜好者世界几乎都已通过ASCII设置了自己,因此任何新方法都必须处理该问题,这绝非易事。

然后,当您开始发送特定的编码时会遇到这种情况,例如,与将浮点数转换为ASCII相比,发送浮点数在内存中的表示形式,通过串行方式发送的浮点数可能超过4个字节,然后再将其转换回到主机上的内存中表示形式。相反,您每次都只发送4字节表示形式。当然,您可以自己开始处理编码,但随后需要设置开始/结束标签,顺序等。

相反,可以使用Protobuf之类的东西。这实际上是在我正在从事的项目中使用的,它非常有益,它可以处理可变长度的消息,为您处理字节序,以及其他一些很酷的功能。它的代码大小也不是很大,您可以指定在启动时静态分配的所有内容。如果需要的话,您将不得不自己添加校验和。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.