简单的串行点对点通信协议
我需要两个设备(PC 和微控制器)之间的简单通信协议。 PC必须向微处理器发送一些命令和参数。 微控制器必须传输字节数组(来自传感器的数据)。
数据必须噪声保护(除了奇偶校验之外,我想我还需要一些其他数据校正方法) 。
有没有标准的解决方案可以做到这一点? (我只需要一个想法,而不是完整的解决方案)。
PS 如有任何建议,我们将不胜感激。 PPS 抱歉有语法错误,希望你能理解。
编辑 1. 我还没有决定是否主/从 协议或者双方都可以发起通信。 PC 必须知道微控制器何时完成工作并可以发送数据。 如果数据准备好,它可以连续轮询微控制器,或者当作业完成时微控制器可以发送数据。 我不知道哪个更好、更简单。
编辑 2. 硬件和物理层协议.自从 RS-232C 串行标准用于PC,我将使用异步通信。 我将仅使用 RxD、TxD 和 GND 信号。 我不能使用额外的电线,因为微控制器据我所知不支持它们。 顺便说一句,我正在使用 AVR ATmega128 芯片。
所以我将使用固定波特率、8 位数据、2 个停止位,没有奇偶校验(或有?)。
数据链路协议。 这就是我的问题主要关心的问题。 感谢您建议HDLC,PPP 和 Modbus > 协议。 我会研究一下。
I need a simple communication protocol between two devices (a PC and a microcontroller). The PC must send some commands and parameters to the micro. The micro must transmit an array of bytes (data from sensor).
The data must be noise protected (besides parity checking, I think I need some other data correction method).
Is there any standard solution to do this? (I need only an idea, not the complete solution).
P.S. Any advice is appreciated. P.P.S Sorry for any grammar mistakes, I hope you understand.
Edit 1. I have not decided whether it will be master/slave protocol or both sides can initiate communication. The PC must know when micro have done a job and can send data. It can continuously poll the micro if data is ready, or the micro can send data, when a job is done. I don't know which is better and simpler.
Edit 2. Hardware and physical layer protocol. Since RS-232C serial standard used in the PC, I will use asynchronous communication. I will use only RxD, TxD and GND signals. I can't use additional wires because the microcontroller AFAIK doesn't support them. BTW I'm using the AVR ATmega128 chip.
So I will use fixed baud rate, 8 bits of data, 2 stop bits without parity checking (or with?).
Data link protocol. That's what my question primarily concerned about. Thanks for suggesting HDLC, PPP and Modbus protocols. I will research on it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
我会使用HDLC。 我过去在这方面运气很好。 对于点对点串行,只需使用 异步帧 并忘记所有其他控制的东西,因为它可能是矫枉过正的。
此外还使用 HDLC 来对数据包进行成帧。 我将数据包格式化如下。 这就是使用 802.11 传递选项的方式
每个命令数据包的总大小为 len +2
然后定义命令,如
另一个优点是您可以添加新命令,如果您正确设计解析器以忽略未定义的命令,那么您将有一些向后兼容性。
因此,将所有内容放在一起,数据包将如下所示。
然后,系统将监视串行流中的标志 0x7e,当它出现时,您检查长度以查看它是否 pklen >= 4 且 pklen=len+4 以及 crc 是否有效。 请注意,不要仅依赖 crc 来处理小数据包,在检查长度时您也会得到很多误报。 如果长度或 crc 不匹配,只需重置长度和 crc 并开始解码新帧。 如果匹配,则将数据包复制到新缓冲区并将其传递给命令处理函数。 当收到标志时,总是重置长度和 crc。
对于命令处理函数,获取 cmd 和 len,然后使用开关来处理每种类型的命令。 我还要求某些事件发送响应,以便系统的行为类似于事件驱动的远程过程调用。
例如,传感器设备可以具有计时器或响应命令来读取读数。 然后它会格式化一个数据包并将其发送到 PC,PC 会响应它收到了该数据包。 如果不是,则传感器设备可能会在超时时重新发送。
此外,当您进行网络传输时,您应该将其设计为网络堆栈,例如 OSI 模型 Foredecker 要点不要忘记物理层内容。 我的 HDLC 帖子是数据链路层和RPC 和命令处理是应用层。
I would use HDLC. I have had good luck with it in the past. I would for a point to point serial just use the Asynchronous framing and forget about all of the other control stuff as it would probably be overkill.
In addition to using HDLC for the framing of the packet. I format my packet like the following. This is how options are passed using 802.11
The total size of each command packet is len +2
You then define commands like
The other advantage is that you can add new commands and if you design your parser correctly to ignore undefined commands then you will have some backwards compatibility.
So putting it all together the packet would look like the following.
The system will then monitor the serial stream for the flag 0x7e and when it is there you check the length to see if it is pklen >= 4 and pklen=len+4 and that the crc is valid. Note do not rely on just crc for small packets you will get a lot of false positives also check length. If the length or crc does not match just reset the length and crc and start with decoding the new frame. If it is a match then copy the packet to a new buffer and pass it to your command processing function. Always reset length and crc when a flag is received.
For your command processing function grab the cmd and len and then use a switch to handle each type of command. I also require that a certain events send a response so the system behaves like a remote procedure call that is event driven.
So for example the sensor device can have a timer or respond to a command to take a reading. It then would format a packet and send it to the PC and the PC would respond that it received the packet. If not then the sensor device could resend on a timeout.
Also when you are doing a network transfer you should design it as a network stack like the OSI modle as Foredecker points don't forget about the physical layer stuff. My post with the HDLC is the data link layer and the RPC and command handling is the Application Layer.
几个月前我读到了这个问题,遇到了完全相同的问题,并且没有真正找到任何对于具有少量 RAM 的微型 8 位微处理器来说足够高效的东西。 受到 CAN 和 LIN 的启发,我构建了一些东西来完成这项工作。 我将其称为 MIN(微控制器互连网络),并将其上传到 GitHub:
https://github。 com/min-protocol/min
那里有两种实现:一种是嵌入式 C 语言,一种是 PC 上的 Python 语言。 再加上一个小“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 存储库 wiki 中。
MIN 未来还有改进的空间。 我在那里留下了一些钩子,用于块消息传递(保留 4 位控制字节)和更高级别的功能协商(保留标识符 0xFF),因此有足够的空间来添加对常用功能的支持。
I read this question a few months back, having exactly the same issue, and didn't really find anything efficient enough for a tiny 8-bit micro with tiny amounts of RAM. So inspired by CAN and LIN I built something to do the job. I called it MIN (Microcontroller Interconnect Network) and I've uploaded it to GitHub here:
https://github.com/min-protocol/min
There are two implementations there: one in embedded C, one in Python for a PC. Plus a little "hello world" test program where the PC sends commands and the firmware lights an LED. I blogged about getting this up and running on an Arduino board here:
https://kentindell.wordpress.com/2015/02/18/micrcontroller-interconnect-network-min-version-1-0/
MIN is pretty simple. I fixed the layer 0 representation (8 data bits, 1 stop bit, no parity) but left the baud rate open. Each frame starts with three 0xAA bytes which in binary is 1010101010, a nice pulsetrain to do autobaud rate detection if one end wants to dynamically adapt to the other. Frames are 0-15 bytes of payload, with a 16-bit Fletcher's checksum as well as a control byte and an 8-bit identifier (to tell the application what the payload data contains).
The protocol uses character stuffing so that 0xAA 0xAA 0xAA always indicates start-of-frame. This means that if a device comes out of reset it always syncs with the start of the next frame (a design goal for MIN was never to pass up an incomplete or incorrect frame). This also means there's no need to have specific inter-byte and inter-frame timing constraints. Full details of the protocol are in the GitHub repo wiki.
There's room for future improvements with MIN. I've left some hooks in there for block message passing (4 bits of the control byte are reserved) and for higher-level negotiation of capabilities (identifier 0xFF is reserved) so there's plenty of scope for adding support for commonly required functionality.
RS232 协议很棘手。 使用 HDLC 的建议是一个很好的建议,但它不是完整的解决方案。 您还需要决定其他事项:
我建议您使用 8 个数据位、无硬件奇偶校验、1 个停止位,并使用基于软件的流量控制。 如果您的硬件支持,您应该使用自动波特率。 如果不是,那么自动波特率在软件中就很难实现。
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:
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.
这里有一些很好的答案,这里有一些有用的提示:
即使您的数据包没有时间分隔,同步字节也是减少您需要尝试构建数据包的位置数量的基本方法。 您的设备通常必须处理一堆垃圾数据(即打开时传输中的数据包的结尾,或硬件冲突的结果)。 如果没有同步字节,您将不得不尝试从收到的每个字节中创建一个数据包。 同步字节意味着只有 1/255 字节的随机噪声可能是数据包的第一个字节。 当你想窥探你的协议时也很棒。
当您通过 某种类型的监听工具。 您可以通过为 PC 设置与设备不同的同步字节来实现此目的。 此外,这意味着设备不会响应其自身的回声。
您可能需要研究纠错(例如 Hamming)。 将 8 位数据打包到 12 位受保护字节中。 这 12 位中的任何一位都可以在途中翻转并恢复原始 8 位。 对于数据存储(在 CD 上使用)或设备无法轻松重新发送的情况(卫星链路、单向射频)很有用。
数据包号码让生活更轻松。 发送的数据包携带一个数字,响应携带相同的数字和一个表示“响应”的标志。 这意味着发送方很容易检测到从未到达的数据包(例如同步损坏),并且在具有慢速链路的全双工模式下,可以在收到第一个响应之前发送两个命令。 这也使得协议分析变得更加容易(第三方可以在不了解底层协议的情况下了解收到了哪些数据包)
拥有一个主机是一个很棒的简化。 也就是说,在全双工环境中,这根本不重要。 可以说,您应该始终这样做,除非您试图节省电量,或者您正在设备端执行一些事件驱动的操作(输入状态已更改,样本已准备好)。
There are some good answers in here, here are some useful pointers:
Even if your packets are not time-separated, the sync byte is an essential way of reducing the number of places you need to attempt to construct a packet from. Your devices will often have to deal with a bunch of junk data (i.e the end of a packet in flight when they turned on, or result of a hardware collision). Without a sync byte you will have to try to make a packet out of every byte you receive. The sync byte means that only 1/255 bytes of random noise could be the first byte of your packet. Also FANTASTIC when you want to snoop on your protocol.
Having an address on your packets or even just a bit saying master / slave or pc / device is useful when you look at the packets via a snoop tool of some type or another. You might do this by having a different sync byte for the PC than the DEVICE. Also, this will mean a device will not respond to its own echo.
You might want to look into error correction (such as Hamming). You package 8 bit of data into a 12 bit protected byte. Any one of those 12 bits can be flipped en-route and the original 8 bits retrieved. Useful for data storage (used on CDs) or where the device can't re-send easily (satellite links, one-way rf).
Packet numbers make life easier. A packet sent carries a number, responses carry the same number an a flag saying "response". This means that packets that never arrived (sync corrupted say) are easily detected by the sender and in full-duplex mode with a slow link, two commands can be sent before the first response is received. This also makes protocol analysis easier (A third party can understand which packets were received with no knowledge of the underlying protocol)
Having a single master is an awesome simplification. That said, in a full-duplex environment it does not matter much at all. Suffice to say you should always do it unless you are trying to save power or you are doing something event driven at the device end (input state changed, sample ready).
我的建议是modbus。
它是一种高效且简单的标准协议,用于与具有传感器和参数的设备(例如 PLC)进行通信。
您可以在 http://www.modbus.org 获取规范。 它自 1979 年以来一直存在,并且越来越受欢迎,您可以毫无问题地找到示例和库。
My suggestion is modbus.
It's an efficient and easy standard protocol for communication with devices that has sensors and parameters (for example a PLC).
You can get the specifications at http://www.modbus.org. It’s been around since 1979 and is gaining in popularity, you will have no problem finding examples and libraries.
关于奇偶校验(因为它在这里出现了几次):
它们几乎没有用。 如果您担心单个位可能会被错误更改,那么第二个位很可能也会更改,并且您会从奇偶校验中得到误报。
使用诸如 CRC16 之类的轻量级内容和查找表 - 它可以在接收到每个字节时进行计算,并且基本上只是一个 XOR。 史蒂夫·梅尔尼科夫的建议对于小型微型企业来说非常有用。
我还建议传输人类可读的数据,而不是原始二进制数据(如果性能不是您的首要任务)。 它将使调试和日志文件变得更加愉快。
Regarding parity checks (as it's come up a few times here):
They're mostly useless. If you're concerned that a single bit may be changed in error, then it's highly likely that a second bit may also change and you'll get a false positive from the parity check.
Use something lightweight like CRC16 with a lookup table - it can be calculated as each byte is received and is basically just an XOR. Steve Melnikoff's suggestion is great for small micros.
I would also suggest transmitting human readable data, rather than raw binary (if performance is not your first priority). It will make debugging and log files much more pleasant.
这里有一个替代协议:
使用 RS232/UART,因为 PC(串行端口)和处理器(UART)已经可以轻松处理该问题(只需要一个 MAX232 芯片或类似芯片进行电平转换)。
并且使用RS232/UART,如果不相关,您不必担心主/从。 如有必要,可以进行流量控制。
建议的PC软件:要么自己编写,要么使用Docklight进行简单的监视和控制(评估版)免费)。
为了进行更好的错误检查,最简单的是奇偶校验,或者如果您需要更强大的东西,也许卷积编码。
无论如何,无论您做什么:保持简单!
编辑:在 PC 上使用 RS232 比以前更容易,因为您现在可以通过 USB 转 RS232 /TTL 转换器。 一端插入 PC 的 USB 插座,并显示为普通串行端口; 另一个输出 5 V 或 3.3 V 信号,可以直接连接到您的处理器,无需电平转换。
我们使用了 FDTI 芯片的 TTL-232R-3V3 ,非常适合此类应用程序。
Here's an alternative protocol:
Use RS232/UART, as the PC (serial port) and the processor (UART) can already handle that with minimum fuss (just need a MAX232 chip or similar to do the level shifting).
And using RS232/UART, you don't have to worry about master/slave if it's not relevant. Flow control is available if necessary.
Suggested PC software: either write your own, or Docklight for simple monitoring and control (evaluation version is free).
For greater error checking, simplest is parity checking, or if you need something more powerful, maybe convolutional coding.
In any case, whatever you do: keep it simple!
EDIT: Using RS232 with a PC is even easier than it used to be, as you can now get USB to RS232/TTL converters. One end goes into your PC's USB socket, and appears as a normal serial port; the other comes out to 5 V or 3.3 V signals that can be connected directly to your processor, with no level-shifting required.
We've used TTL-232R-3V3 from FDTI Chip, which works perfectly for this kind of application.
您可以查看
Telemetry
及其相关的 python 桌面实现< a href="https://github.com/Overdrivr/pytelemetry" rel="nofollow noreferrer">Pytelemetry
主要特点
它是一个基于 PubSub 的协议,但与 MQTT 不同的是,它是一种点对点协议,无代理。
与任何 pubsub 协议一样,您可以从一端
主题
发布,并在另一端收到该主题的通知。在嵌入式方面,发布到主题就像:
对于数字:
这种发送变量的方式可能看起来有限,但下一个里程碑打算通过执行以下操作为主题的解析添加额外的含义:
如果您这样做,这很好需要发送数组、复杂的数据结构等。
此外,PubSub 模式因其灵活性而非常出色。 您可以构建主/从应用程序、设备到设备等。
C 库
只要您有一个不错的 UART 库,C 库就可以非常简单地添加到任何新设备上它。
您只需实例化一个名为
TM_transport
的数据结构(由Telemetry
定义),并分配 4 个函数指针read
可读
可写
可写
。要使用 Telemetry,您只需添加以下代码
Python 库
在桌面端,有实现该协议的
pytelemetry
模块。如果您了解 python,以下代码将连接到串行端口,在主题
foo
上发布一次,在 3 秒内打印所有收到的主题,然后终止。如果您不懂 python,可以使用命令行界面
Pytelemetry CLI
可以使用命令行启动
然后就可以
connect
,ls(list) 接收到的主题、
print
接收到的主题数据、pub
(发布)某个主题,或者在某个主题上打开一个plot
实时显示接收到的数据的主题You can have a look at
Telemetry
and its associated desktop implementation in pythonPytelemetry
Main features
It is a PubSub-based protocol, but unlike MQTT it is a point-to-point protocol, no broker.
As any pubsub protocol, you can publish from one end on a
topic
and be notified on the other end on that topic.On the embedded side, publishing to a topic is as simple as :
For numbers:
This way of sending variables may seem limited, but the next milestone intends to add extra meaning to the topic's parsing by doing things like this :
This is good if you need to send arrays, complex data structures, etc.
Also, the PubSub pattern is great because of its flexibility. You can build master/slave applications, device to device, etc.
C library
The C library is very simple to add on any new device as long as you have a decent UART library on it.
You just have to instanciate a data structure called
TM_transport
(defined byTelemetry
), and assign the 4 function pointersread
readable
write
writeable
.To use Telemetry, you just have to add the following code
Python library
On the desktop side, there is the
pytelemetry
module that implements the protocol.If you know python, the following code connects to a serial port, publishes once on topic
foo
, prints all received topics during 3 seconds then terminates.If you don't know python, you can use the command line interface
Pytelemetry CLI
The command line can be started with
Then you can
connect
,ls
(list) received topics,print
data received on a topic,pub
(publish) on a topic, or open aplot
on a topic to display received data in real-time我唯一的建议是,如果您需要抗噪声,您可能需要使用全双工 RS-422/485。 您可以使用类似于此的IC在 AVR 端,然后在 PC 端使用 RS-232->RS-422 转换器,例如 此处为 485PTBR。 如果您可以找到或制作屏蔽电缆(两根屏蔽双绞线),那么您将获得更多保护。 所有这一切对于微型计算机和 PC 来说都是不可见的——无需软件更改。
无论您做什么,请确保您使用的是全双工系统,并确保 IC 上的读/写使能线有效。
My only suggestion is if you need noise-resistant you might want to use full-duplex RS-422/485. You can use an IC similar to this on the AVR side, then an RS-232->RS-422 converter on the PC side like the 485PTBR here. If you can find or make a shielded cable (two twisted shielded pairs) then you'll have even more protection. And all of this is invisible to the micro and PC - no software changes.
Whatever you do make sure that you are using a full-duplex system and make sure the read/write enable lines are asserted on the IC.
您没有具体指定微控制器的行为方式,但从微控制器传输的所有内容是否都是对 PC 命令的直接响应? 如果这样做,那么您似乎可以使用某种主/从协议(这通常是最简单的解决方案)。 如果双方都能发起通信,就需要更通用的数据链路层协议。 HDLC 是一个经典协议。 尽管完整的协议可能无法满足您的需求,但您至少可以使用相同的帧格式。 您还可以查看 PPP 看看是否有一些有用的部分。
You do not specify exactly how the microcontroller behaves, but will everything transmitted from the micro be a direct response to a command from the PC? If do then it seems like you can use a master/slave protocol of some kind (this will typically be the simplest solution). If both sides can initiate communication, you need a more general data link layer protocol. HDLC is a classic protocol for this. Although the full protocol probably is a overkill for your needs, you could for instance at least use the same frame format. You might also have a look at PPP to see if there are something useful parts.
也许这个问题可能完全愚蠢,但有人考虑过使用 X/Y/Z MODEM 协议?
使用上述协议之一的主要好处是在各种编程环境中随时可用的实现具有很高的可用性。
maybe this question can be completely stupid but has anyone considered use of one of X/Y/Z MODEM protocols?
The main benefit of using one of above protocols is great availability of ready-to-use implementations in various programming environments.
SLIP 和 UDP。 严重地。
所有 PC 和类似设备都可以使用该语言。
TCP Lean 有一本好书和示例
Jeremy Bentham 偷偷地做了一个 PIC工作 TCP/IP。 AVR 和 PIC 一样好,对吗?
我建议使用 UDP,这非常简单。
SLIP and UDP. Seriously.
All PC's and similar devices speak it.
There is a good book and examples from TCP Lean
Jeremy Bentham has sneakily got a PIC doing working TCP/IP. An AVR is as good as a PIC right ?
I'd recommend UDP instead, it's pretty darn easy.