64

我需要两个设备(PC 和微控制器)之间的简单通信协议。PC 必须向 micro 发送一些命令和参数。微型必须传输一个字节数组(来自传感器的数据)。

数据必须有噪声保护(除了奇偶校验,我想我需要一些其他的数据校正方法)。

有没有标准的解决方案来做到这一点?(我只需要一个想法,而不是完整的解决方案)。

PS任何建议表示赞赏。PPS 很抱歉有任何语法错误,希望你能理解。

编辑1.我还没有决定是主/从协议还是双方都可以发起通信。PC 必须知道 micro 何时完成工作并可以发送数据。如果数据准备好,它可以连续轮询微,或者微可以在工作完成时发送数据。我不知道哪个更好更简单。

编辑 2. 硬件和物理层协议。由于PC 使用RS-232 C 串行标准,我将使用异步通信。我将只使用 RxD、TxD 和 GND 信号。我不能使用额外的电线,因为微控制器 AFAIK 不支持它们。顺便说一句,我使用的是AVR ATmega128 芯片。

所以我将使用固定波特率、8 位数据、2 个停止位而不进行奇偶校验(或使用?)。

数据链路协议。这就是我的问题主要关心的问题。感谢您推荐HDLCPPPModbus协议。我会研究它。

4

12 回答 12

41

我会使用HDLC。过去我很幸运。我希望点对点串行只使用异步框架并忘记所有其他控制内容,因为它可能会过度杀伤。

除了使用 HDLC 来构建数据包。我像下面这样格式化我的数据包。这是使用 802.11 传递选项的方式

U8 cmd;
U8 len;
u8 payload[len];

每个命令包的总大小为 len +2

然后,您定义命令,例如

#define TRIGGER_SENSOR 0x01
#define SENSOR_RESPONSE 0x02

另一个优点是您可以添加新命令,并且如果您正确设计解析器以忽略未定义的命令,那么您将具有一些向后兼容性。

因此,将它们放在一起,数据包将如下所示。

 // total packet length minus flags len+4
 U8 sflag;   //0x7e start of packet end of packet flag from HDLC
 U8 cmd;     //tells the other side what to do.
 U8 len;     // payload length
 U8 payload[len];  // could be zero len
 U16 crc;
 U8 eflag;   //end of frame flag

然后系统将监视串行流的标志 0x7e,当它在那里时,您检查长度以查看它是否 pklen >= 4 和 pklen=len+4 以及 crc 是否有效。注意不要仅仅依赖于小数据包的 crc,你会得到很多误报,还会检查长度。如果长度或 crc 不匹配,只需重置长度和 crc 并开始解码新帧。如果匹配,则将数据包复制到新缓冲区并将其传递给您的命令处理函数。收到标志时始终重置长度和CRC。

对于您的命令处理功能,请获取 cmd 和 len,然后使用开关来处理每种类型的命令。我还要求某些事件发送响应,以便系统的行为类似于事件驱动的远程过程调用。

因此,例如,传感器设备可以具有计时器或响应命令以读取读数。然后它将格式化一个数据包并将其发送到 PC,PC 将响应它收到数据包。如果不是,则传感器设备可以在超时时重新发送。

此外,当您进行网络传输时,您应该将其设计为像OSI 模型一样的网络堆栈,因为Foredecker指出不要忘记物理层的东西。我在 HDLC 上的帖子是数据链路层,而RPC 和命令处理是应用层

于 2009-05-02T22:45:56.887 回答
11

RS232 protocols are tricky. The suggestion to use HDLC, is a good one, but its not the entire solution. There are other things you need to decide:

  • How will the baud rate between the two devices be determined? Autobuad? Predefined, or set explicate?
  • Will you do flow control in software or hardware or both? Note, if you use hardware flow control then you must make sure, that the cables are built correctly.
  • Speaking of cables, this is a huge pain with RS233. Depending on the device, you may need to use a straight through cable, or a cross over cable, or a variant.
  • Using a software based flow control mechanism can be effective as it allows the most simple cable to be used - just three wired (TX, RX, and common).
  • Do you pick a 7 or 8 bit word?
  • HW parity or software error checking.

I suggest you go with 8 data bits, no hardware parity, 1 stop bit, and use software based flow control. You should use autobaud if your hardware supports it. If not, then autobaud is devilishly difficult to do in software.

于 2009-05-03T19:08:46.917 回答
9

几个月前我读了这个问题,遇到了完全相同的问题,并没有真正找到任何足够有效的东西来处理一个只有少量 RAM 的 8 位微型计算机。因此,受 CAN 和 LIN 的启发,我构建了一些东西来完成这项工作。我将其称为 MIN(微控制器互连网络),并已将其上传到 GitHub:

https://github.com/min-protocol/min

那里有两种实现:一种在嵌入式 C 中,另一种在 Python 中用于 PC。加上一个小小的“hello world”测试程序,PC 发送命令,固件点亮 LED。我在这里写了一篇关于如何在 Arduino 板上启动和运行的博客:

https://kentindell.wordpress.com/2015/02/18/micrcontroller-interconnect-network-min-version-1-0/

MIN 很简单。我修复了第 0 层表示(8 个数据位,1 个停止位,无奇偶校验),但波特率保持打开状态。每帧以三个 0xAA 字节开始,二进制为 1010101010,如果一端想要动态适应另一端,则可以很好地进行自动波特率检测。帧是 0-15 字节的有效载荷,带有 16 位 Fletcher 校验和以及一个控制字节和一个 8 位标识符(用于告诉应用程序有效载荷数据包含什么)。

该协议使用字符填充,因此 0xAA 0xAA 0xAA 始终表示帧开始。这意味着如果设备退出复位,它总是与下一帧的开始同步(MIN 的设计目标是永远不要传递不完整或不正确的帧)。这也意味着不需要有特定的字节间和帧间时序约束。该协议的完整细节在 GitHub repo wiki 中。

MIN 有未来改进的空间。我在其中留下了一些用于块消息传递(保留控制字节的 4 位)和更高级别的功能协商(保留标识符 0xFF)的钩子,因此有足够的空间来添加对常用功能的支持。

于 2015-02-18T16:51:00.517 回答
8

这里有一些很好的答案,这里有一些有用的指针:

即使您的数据包不是时间分离的,同步字节也是减少您需要尝试构建数据包的位置数量的重要方法。您的设备通常必须处理一堆垃圾数据(即当它们打开时传输中的数据包结束,或硬件冲突的结果)。如果没有同步字节,您将不得不尝试从收到的每个字节中制作一个数据包。同步字节意味着只有 1/255 字节的随机噪声可能是数据包的第一个字节。当你想窥探你的协议时也很棒。

当您通过某种类型的窥探工具查看数据包时,在您的数据包上拥有一个地址,甚至只是说主/从或 pc / 设备非常有用。您可以通过为 PC 设置与 DEVICE 不同的同步字节来做到这一点。此外,这意味着设备不会响应自己的回声。

您可能想研究纠错(例如Hamming)。您将 8 位数据打包成 12 位受保护字节。这 12 位中的任何一位都可以在途中翻转并检索原始的 8 位。适用于数据存储(用于 CD)或设备无法轻松重新发送的情况(卫星链接、单向射频)。

数据包编号使生活更轻松。发送的数据包带有一个数字,响应带有相同的数字和一个表示“响应”的标志。这意味着发送方很容易检测到从未到达的数据包(例如同步损坏),并且在具有慢速链路的全双工模式下,可以在收到第一个响应之前发送两个命令。这也使协议分析更容易(第三方可以在不了解底层协议的情况下了解接收到的数据包)

拥有一个主人是一个很棒的简化。也就是说,在全双工环境中,这并不重要。可以说你应该总是这样做,除非你试图节省电力或者你正在做一些在设备端驱动的事件(输入状态改变,样本准备好)。

于 2009-06-21T04:29:49.467 回答
5

我的建议是modbus。它是一种高效且简单的标准协议,用于与具有传感器和参数的设备(例如 PLC)进行通信。您可以在http://www.modbus.org获得规格。它自 1979 年以来一直存在并且越来越受欢迎,您可以毫无问题地找到示例和库。

于 2009-05-04T21:51:06.160 回答
4

这是一个替代协议:

u8  Sync          // A constant value which always marks the start of a packet
u16 Length        // Number of bytes in payload
u8  Data[Length]  // The payload
u16 Crc           // CRC

使用 RS232/UART,因为 PC(串行端口)和处理器(UART)已经可以轻松处理(只需要MAX232芯片或类似芯片来进行电平转换)。

并且使用 RS232/UART,如果它不相关,您不必担心主/从。如有必要,可以使用流量控制。

建议的 PC 软件:可以自己编写,也可以使用Docklight进行简单的监控(评估版免费)。

对于更大的错误检查,最简单的是奇偶校验,或者如果你需要更强大的东西,也许是卷积编码

无论如何,无论你做什么:保持简单!

编辑:在 PC 上使用 RS232 比以前更容易,因为您现在可以获得 USB 到 RS232/TTL 转换器。一端插入 PC 的 USB 插座,显示为普通串口;另一个输出 5 V 或 3.3 V 信号,可直接连接到您的处理器,无需电平转换。

我们使用了 FDTI Chip的 TTL-232R-3V3,它非常适合这种应用。

于 2009-05-03T14:02:34.220 回答
3

关于奇偶校验(因为它在这里出现了几次):

他们大多没用。如果您担心单个位可能会错误地更改,那么很有可能第二个位也可能会更改,并且您会从奇偶校验中得到误报。

使用带有查找表的 CRC16 等轻量级的东西 - 它可以在接收到每个字节时计算出来,基本上只是一个 XOR。Steve Melnikoff 的建议非常适合小型微型企业。

我还建议传输人类可读的数据,而不是原始二进制文件(如果性能不是您的首要任务)。它将使调试和日志文件更加愉快。

于 2009-05-14T12:23:50.470 回答
2

我唯一的建议是,如果您需要抗噪,您可能需要使用全双工 RS-422/485。您可以在 AVR 端使用与此类似的 IC ,然后在 PC 端使用 RS-232->RS-422 转换器,如此处的 485PTBR。如果您能找到或制作屏蔽电缆(两对屏蔽双绞线),那么您将获得更多保护。所有这些对于微型计算机和 PC 来说都是不可见的——无需更改软件。

无论您做什么,请确保您使用的是全双工系统,并确保 IC 上的读/写使能线已置位。

于 2009-05-06T02:35:12.647 回答
2

您可以在 python 中查看Telemetry及其相关的桌面实现Pytelemetry

主要特点

它是基于PubSub 的协议,但与 MQTT 不同的是,它是点对点协议,没有代理

与任何 pubsub 协议一样,您可以从一端发布topic并在另一端收到有关该主题的通知。

在嵌入式方面,发布到主题非常简单:

publish("someTopic","someMessage")

对于数字:

publish_f32("foo",1.23e-4)
publish_u32("bar",56789)

这种发送变量的方式可能看起来有限,但下一个里程碑旨在通过执行以下操作为主题的解析增加额外的意义:

// Add an indexing meaning to the topic
publish("foo:1",45) // foo with index = 1
publish("foo:2",56) // foo with index = 2

// Add a grouping meaning to the topic
publish("bar/foo",67) // foo is under group 'bar'

// Combine
publish("bar/foo:45",54)

如果您需要发送数组、复杂的数据结构等,这很好。

此外,PubSub 模式因其灵活性而非常出色。您可以构建主/从应用程序、设备到设备等。

C 库GitHub版本

只要您有一个像样的 UART 库,C 库就可以非常简单地添加到任何新设备上。

您只需实例化一个名为TM_transport(由 定义Telemetry)的数据结构,并分配 4 个函数指针read readable write writeable

// your device's uart library function signatures (usually you already have them)
int32_t read(void * buf, uint32_t sizeToRead);
int32_t readable();
int32_t write(void * buf, uint32_t sizeToWrite);
int32_t writeable();

要使用遥测,您只需添加以下代码

// At the beginning of main function, this is the ONLY code you have to add to support a new device with telemetry
TM_transport transport;
transport.read = read;
transport.write = write;
transport.readable = readable;
transport.writeable = writeable;

// Init telemetry with the transport structure
init_telemetry(&transport);  

// and you're good to start publishing
publish_i32("foobar",...

Python 库PyPI 版本

在桌面端,有pytelemetry实现协议的模块。

如果您知道 python,以下代码连接到串行端口,在 topic 上发布一次foo,在 3 秒内打印所有接收到的主题然后终止。

import runner
import pytelemetry.pytelemetry as tm
import pytelemetry.transports.serialtransport as transports
import time

transport = transports.SerialTransport()
telemetry = tm.pytelemetry(transport)
app = runner.Runner(transport,telemetry)

def printer(topic, data):
    print(topic," : ", data)

options = dict()
options['port'] = "COM20"
options['baudrate'] = 9600

app.connect(options)

telemetry.subscribe(None, printer)
telemetry.publish('bar',1354,'int32')
time.sleep(3)

app.terminate()

如果你不懂python,可以使用命令行界面

遥测 CLIPyPI 版本

命令行可以启动

pytlm

然后你可以connectls(列出)接收到的主题,print在一个主题上接收到的数据,pub(发布)在一个主题上,或者plot在一个主题上打开一个来实时显示接收到的数据

在此处输入图像描述

在此处输入图像描述

于 2016-02-10T08:07:26.693 回答
1

也许这个问题可能完全是愚蠢的,但有没有人考虑过使用X/Y/Z 调制解调器协议之一?

使用上述协议之一的主要好处是在各种编程环境中都可以使用现成的实现。

于 2009-05-07T13:25:48.143 回答
0

您没有具体说明微控制器的行为方式,但从微控制器传输的所有内容都会直接响应来自 PC 的命令吗?如果这样做,那么您似乎可以使用某种主/从协议(这通常是最简单的解决方案)。如果双方都能发起通信,则需要更通用的数据链路层协议。HDLC是一个经典的协议。尽管完整的协议可能对您的需求来说是多余的,但您至少可以使用相同的帧格式。你也可以看看PPP看看是否有一些有用的部分。

于 2009-05-02T22:59:40.240 回答
-1

SLIP 和 UDP。严重地。

所有 PC 和类似设备都使用它。

TCP Lean有一本好书和例子

Jeremy Bentham 偷偷地得到了一个 PIC 正在工作的 TCP/IP。AVR 和 PIC 一样好,对吗?

我会推荐 UDP,它非常简单。

于 2009-12-01T03:46:52.763 回答