我所有通过UART与PC通信的微控制器设备都使用ASCII字符串发送命令和接收数据(在Arduino中实现)。这是我开始研究电子产品时学到的,我总是发现发送裸线就足够了。但是我注意到,我遇到的大多数设备都使用复杂的二进制协议,其中包括功能代码,地址和CRC错误检查。
什么时候可以接受基本的ASCII通讯?何时应该考虑使用更高级的功能,例如Modbus?商用设备是否使用这种ASCII?产业?
我所有通过UART与PC通信的微控制器设备都使用ASCII字符串发送命令和接收数据(在Arduino中实现)。这是我开始研究电子产品时学到的,我总是发现发送裸线就足够了。但是我注意到,我遇到的大多数设备都使用复杂的二进制协议,其中包括功能代码,地址和CRC错误检查。
什么时候可以接受基本的ASCII通讯?何时应该考虑使用更高级的功能,例如Modbus?商用设备是否使用这种ASCII?产业?
Answers:
ASCII和CRC不互斥。ASCII是一种编码,而CRC是用于错误检查。
任何东西都可以ASCII形式发送。我们的老人们肯定记得UUEncoding,它将任何东西转换为ASCII字符串。
答:对我来说,通常是速度和效率的问题。通过ASCII发送大的32位数字可能会花费很长时间,但是通过串行协议以二进制形式发送它只需要4个字节。
B)通过ASCII发送数字意味着您必须将数字转换为ASCII,这是一个明显的额外步骤(这是“ printf”功能的一部分)。
如果您以某种方式迷失了自己的位置,搞砸了,丢失了格式,获取了错误的字节序等,那么二进制通信协议肯定会搞砸了。如果要发送ASCII,则只需进入并查找数据流,就可以更轻松地从乱码中恢复。
在最简单的级别上,您可以说一个简单的通信协议具有三层:物理层,传输层和应用程序。(有些模型具有更多功能,例如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还是二进制协议,在每个数据包之前发送擦除字符都将确保即使在数据包开始之前出现了线路噪声或成帧错误,所有字符都将在擦除后在没有其他噪音的情况下,将正确构图。否则,如果一个人连续发送数据包并且不包含保证实现重新同步的任何字符,则一个小故障可能会破坏随后的所有内容,直到下一次传输暂停为止。0xFF字符很不错,因为它可以确保任何收件人都可以在以下字符上重新同步。
(*)0xFF-之所以称为“擦除”,是因为在纸带上键入数据时键入错误字符的人可以按下“向后步进磁带”按钮,然后按“擦除”以将错误打孔的字符替换为0xFF,这将被大多数收件人忽略)。
发送ASCII字符串的优点之一是控制代码可用于发信号通知消息的开始/结束。例如,STX(字符2)和ETX(字符3)可以发出开始传输和结束传输的信号。或者,您可以添加简单的换行符以标记传输结束。
当发送二进制数据时,这变得更加复杂,因为不能为控制代码保留特定的位模式(没有一些额外的开销或复杂性),因为有效数据字节可能具有相同的模式。
代替Modbus,请考虑使用HDLC。您将获得错误检测(这对于嘈杂的串行线路很重要)。同步功能强大,转义功能强大。
我已经在RS-485网络中使用HDLC了,而PPP也使用了它。
UART上的ASCII是最受欢迎的部分原因是:
在调试时,它是人类可读的(我还没有看到不解码ASCII的逻辑分析仪)。
这很容易实现,您已经通过快速google标准化了ASCII表。
它具有与开始/停止位同步的功能。
整个嗜好者世界几乎都已通过ASCII设置了自己,因此任何新方法都必须处理该问题,这绝非易事。
然后,当您开始发送特定的编码时会遇到这种情况,例如,与将浮点数转换为ASCII相比,发送浮点数在内存中的表示形式,通过串行方式发送的浮点数可能超过4个字节,然后再将其转换回到主机上的内存中表示形式。相反,您每次都只发送4字节表示形式。当然,您可以自己开始处理编码,但随后需要设置开始/结束标签,顺序等。
相反,可以使用Protobuf之类的东西。这实际上是在我正在从事的项目中使用的,它非常有益,它可以处理可变长度的消息,为您处理字节序,以及其他一些很酷的功能。它的代码大小也不是很大,您可以指定在启动时静态分配的所有内容。如果需要的话,您将不得不自己添加校验和。