简单的串行点对点通信协议

时间:2009-05-02 22:20:39

标签: embedded serial-port protocols

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

数据必须是noise protected(除了奇偶校验,我认为我还需要一些其他的数据校正方法)。

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

P.S。任何建议表示赞赏。 P.P.S很抱歉任何语法错误,我希望你理解。

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

编辑2。 硬件和physical layer协议。 由于PC中使用了RS-232 C系列标准,我将使用asynchronous communication。我将只使用RxD,TxD和GND信号。我无法使用额外的电线,因为微控制器AFAIK不支持它们。顺便说一下,我正在使用AVR ATmega128芯片。

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

Data link protocol 即可。这就是我的问题主要关注的问题。感谢您提出HDLCPPPModbus协议。我会研究它。

12 个答案:

答案 0 :(得分:36)

我会使用HDLC。我过去好运。我想要点串口只使用Asynchronous framing并忘记所有其他控件的东西,因为它可能会有点过分。

除了使用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 modle之类的网络堆栈,因为Foredecker点不会忘记physical layer stuff。我在HDLC上的帖子是data link layerRPC and command handling is the Application Layer

答案 1 :(得分:10)

RS232协议很棘手。使用HDLC的建议是一个很好的建议,但它不是整个解决方案。您还需要决定其他事项:

  • 如何确定两台设备之间的波特率? Autobuad?预定义,还是设置explicate?
  • 你会用软件或硬件或两者进行流量控制吗?请注意,如果您使用硬件流控制,则必须确保电缆构建正确。
  • 说到电缆,这对RS233来说是一个巨大的痛苦。根据设备的不同,您可能需要使用直通电缆,交叉电缆或变体。
  • 使用基于软件的流量控制机制可能是有效的,因为它允许使用最简单的电缆 - 只有三个有线(TX,RX和公共)。
  • 你选择7位或8位字吗?
  • 硬件奇偶校验或软件错误检查。

我建议你使用8个数据位,没有硬件奇偶校验,1个停止位,并使用基于软件的流量控制。如果您的硬件支持,您应该使用自动波特率。如果没有,那么autobaud在软件中是非常困难的。

答案 2 :(得分:8)

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

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

当您通过某种类型的snoop tool查看数据包时,在您的数据包上有一个地址,甚至只是说主/从或PC /设备有用。您可以通过为PC提供与DEVICE不同的同步字节来实现此目的。此外,这意味着设备不会响应自己的回声。

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

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

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

答案 3 :(得分:5)

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

答案 4 :(得分:5)

几个月前我读过这个问题,问题完全相同,并没有真正找到任何有效的东西,只需要一个微小的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保留),因此有足够的空间来增加支持通常需要的功能。

答案 5 :(得分:3)

这是另一种协议:

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进行简单的监控和控制(评估版是免费的)。

对于更大的错误检查,最简单的是奇偶校验,或者如果您需要更强大的功能,可能是convolutional coding

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

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

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

答案 6 :(得分:2)

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

无论您做什么,都要确保使用全双工系统,并确保在IC上声明读/写使能线。

答案 7 :(得分: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 version

只要你有一个像样的UART库,C库就可以很容易地添加到任何新设备上。

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

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();

Python库PyPI version

在桌面端,有// 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,则以下代码连接到串行端口,在主题pytelemetry上发布一次,在3秒内打印所有收到的主题,然后终止。

foo

如果您不了解python,可以使用命令行界面

Pytelemetry CLI PyPI version

可以使用

启动命令行
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()

然后,您可以pytlm connect(列表)收到主题,收到关于主题的ls数据,print(发布)主题,或打开{ {1}}关于实时显示接收数据的主题

enter image description here

enter image description here

答案 8 :(得分:1)

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

他们大多没用。如果您担心单个位可能会发生错误更改,那么第二位很可能也会发生变化,您将从奇偶校验中获得误报。

使用像CRC16这样的轻量级内容和查找表 - 它可以在收到每个字节时计算出来,基本上只是一个异或。 Steve Melnikoff的建议非常适合小型微观。

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

也许这个问题可能完全是愚蠢的,但有人考虑使用X/Y/Z MODEM协议之一吗?

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

答案 11 :(得分:-2)

SLIP和UDP。认真。

所有PC和类似设备都会说出来。

TCP Lean

有一本好书和例子

Jeremy Bentham偷偷摸摸地让PIC工作TCP / IP。 AVR和PIC一样好吗?

我建议使用UDP,这很简单。