如何为嵌入式系统设计串行命令协议?

时间:2009-09-18 15:46:17

标签: embedded serial-port

我有一个嵌入式系统,我正在通过串口进行通信。现在,命令结构旨在以交互方式操作:它显示提示,接受一些命令,并以人类可读的形式显示结果。

我正在考虑将其更改为更加机器可用的格式,因此我可以通过MATLAB GUI与它进行对话而不会有太多麻烦(现在它在交互式提示和不同的消息长度等方面打嗝)。

那么是否有某个文档或标准描述了如何为嵌入式系统设计良好的串行命令协议?

9 个答案:

答案 0 :(得分:47)

我有一些偏好(和烦恼)从编写软件到使用RS232控制媒体和显示设备。根据您的硬件,其中一些可能不适用:

  • 我认为让协议对自动化更友好是一个好主意。如果需要交互式界面(命令行或其他),请单独构建它并使其使用自动化协议。我不会太担心让人类可读,但这取决于你。

  • 如果收到无效命令,则始终(特别是)返回响应。简单的东西就像是06美元的ACK和15美元的NAK。如果你想让它更具人性化,请拼写出来。

  • 如果您可以设置任何值,请确保有某种方法可以查询相同的值。如果您有很多值,可能需要一段时间才能查询所有值。考虑让一个或几个元查询一次返回多个值。

  • 如果您的信息无法设置,但很重要(型号,序列号,版本,版权等),请确保可以查询这些信息,而不是仅在启动或重置时显示一次

  • 永远不要回复有效命令的错误。你认为这个很明显......

  • 说到明显,请记录硬件支持的串行设置。特别是如果它将被除你以外的任何人使用,并且你不希望他们花费前30分钟试图弄清楚他们是否因为串口,连接,电缆或者无法与设备通话他们的软件。不是说我很苦......

  • 使用绝对命令而不是切换值。例如,为开机和关机提供单独的命令,而不是发送相同的命令并打开和关闭电源切换。

  • 响应应包含有关他们响应的命令的信息。这样,任何程序都不需要记住它为处理响应而要求的最后一件事(请参阅下面的额外信用选项)。

  • 如果您的设备支持待机模式(关闭但未关闭),请确保在您处于此状态时查询仍然有效。

取决于您对数据完整性的偏执程度:

  • 将信息包裹在信封中。标题可以包括起始字符,消息的lengeth和结束字符。以防您收到部分或格式错误的邮件。也许开头是02美元,最后是03美元。

  • 如果您对邮件完整性非常偏执,请包含校验和。不过,他们可能会有点痛苦。

额外信用:

  • 如果您的硬件设置可以手动更改,可以将此更改发送出串口,就像用户查询过一样。例如,您可能不希望用户能够更改公共显示器的输入源。

我希望这会有所帮助。

<强>更新

我忘记了重要的事情。在你严肃地使用它之前,特别是在你把它交给别人之前,试试一些微不足道的东西,以确保它按照你期望的方式工作,并且(更重要的是)确保你没有留下任何东西。如果您在更大的项目中发现问题,则需要花费更多的时间和精力来解决问题。

无论您是设计命令协议,Web服务,数据库架构还是类等,这都是一个很好的经验法则。

答案 1 :(得分:13)

Here是Eli Benderski关于串行协议框架的精彩文章。无论您选择哪种数据包格式,请务必使用转义字符。它允许您在实际数据中包含此类字符,并使数据包损坏时重新同步非常容易。

答案 2 :(得分:7)

除非带宽或延迟是一个大问题,否则请尽可能使用ASCII - 它使调试变得更加容易。

我喜欢发送消息的协议,然后是明确的“消息结束”字符(例如“回车”)。我通常不会发现数据包信号的开始是有用的(该线路上还有什么?)使用CR进行消息结束也使得通过终端程序进行测试变得更容易。

更新:Bruce指出(在评论中)数据包字符的开头可以让您在发生损坏时更快地找到数据包。如果没有数据包字符的开头,那么在您知道自己的位置之前,它将一直持续到下一个数据包的末尾,此时您将丢弃2个数据包而不是一个数据包。

答案 3 :(得分:6)

我喜欢Bruce McGee的答案。使用类似的接口后,我可以提供其他几个指针:

  • 在数据包中返回数字类型时,请尝试将所有内容设置为相同的格式。某些数字没有而其他数字 double 。并且不要随意!

  • 提供ICD中数据包的示例。必须猜测字节顺序甚至是位顺序是非常令人沮丧的(首先是MSByte,还是最后一个?什么是第一个和最后一个?)。提供一个显示数据包与时间的关系图(即最早发送0x02,然后是地址字节,然后是消息ID等)。

  • 如果可能,请勿在数据格式之间切换。我曾在一些系统中使用'ASCII编码数字'来处理某些消息,你必须从字节中删除前导'3',然后将它们拉到一起以形成实数。 (通常使用ASCII编码,当你有一个必须避免的字节序列,如0x02,0x04等。编码的数字将是0x30,0x32,0x30,0x34。如果可能的话,使用长度字段来避免这种情况,或者至少一直这样做!)

  • 绝对肯定会记录波特率,奇偶校验等。如果您使用的是RS-485文件总线模式(2线?4线?)或任何设置将出现在您的机器上打算将其用于。如果必须,请提供屏幕截图。

此接口可能对调试非常有用。我使用过一些具有调试功能的系统,例如:

  • 程序员列出“已记录参数”(内部变量)的系统。您可以告诉系统您想要报告哪些(最多8个),然后当您向系统查询已记录的参数时,它会将它们返回到一个数据包中。我喜欢这个,但是根据系统的复杂性,你可能会或者可能无法在运行时指定它们(或者你可以做一些简单的事情并向系统发送一个掩码,选择你想要返回的掩​​码)。 / p>

  • “破坏”行为的数据包 并允许系统的部分 独立测试(即,在D / A上输出此电压,在DIO端口上激励此字节等)

祝你好运!

答案 4 :(得分:5)

如果您必须拥有自己的协议,

请请使用数据包框架。

SLIP仅构建几行代码。在(RFC 1055)中指定

所以现在所有数据包总是看起来像这样

 <slip packet start>
 message
 message crc
 <slip packet start>

不要发送消息长度。它可能会被破坏,然后接收者消息解析器会混淆。

如果您的接收器有一个小的接收器缓冲区并且它溢出,您只需继续读取直到数据包边界。没有伤害。

大量简单的2字节CRC; Xmodem很容易。您只需要清除数据包中的所有字节即可。

如果你想成为一个非常好的人,请使用PPP,DDNS和HTTP-REST作为实际命令。 关于在16位系列PIC处理器上做这件事的可爱的书,由杰里米·本特姆,TCP / IP精益。

然后你可以使用网络浏览器与它交谈,或者像C代码中的libcurl。 由于几乎每种编程语言都有可以执行http的库,因此每个人都可以与您的设备通信。

答案 5 :(得分:4)

这里有很多好的建议和想法,并注意到有不同的方法来解决它的不同目的。使用了许多串行协议,无论好坏,以及我自己的几个(好的和坏的......)都是我的一些建议和评论。

  • 保持简单。我找到了 简单的标题最大的成功 基于命令响应“数据包”。

  • 不要担心人类可读的ASCII。它只对您实际调试协议的几个小时有用。之后,总是将数据编码为ASCII并且如果您传输大量数据效率非常低,则限制性。

  • 使用错误检查。我更喜欢16位CRC,因为它在校验和上提供了数量级的保护,并且比MD5或SHA1等更重的算法更简单有效。

  • 对命令使用与响应相同的数据包格式。

  • 使用没有奇偶校验的8位数据。如果您已经使用CRC或其他数据完整性检查并且最好是错误检查,则串行奇偶校验位不会添加任何保护。

  • 因此,在最简单的形式中,包头是命令或响应,包的大小,零个或多个数据以及错误检查码(CRC)。

答案 6 :(得分:2)

FTP是协议的一个示例,它在交互式和自动化方面都能很好地工作。一个关键是响应以一个代码开始,该代码指示自动客户端是否应该支付费用。同样适用于POP3。

关于这些协议的一个好处是,当您进行开发/调试时,您可以合理地从常规终端驱动通信,或使用常规shell脚本/批处理文件/任何内容编写通信脚本。

然而,他们不做的一件事是提供可靠性 - 这是由comm栈的较低层提供的。这在大多数嵌入式通信中都应该被考虑。

答案 7 :(得分:2)

你看过Modbus(http://www.modbus.org/)了吗?这是一个相当简单的协议,包括每条消息的校验和。它还会向每个命令发送响应,甚至是那些不需要“返回值”的命令,因此您可以知道您的命令是否已正确接收。选择Modbus后唯一的选择是存储数据的寄存器地址,以及任何用户定义函数的格式(MODBUS协议允许的格式)。

答案 8 :(得分:1)

请查看Firmata作为示例协议。