题
我需要两个设备(PC 和微控制器)之间的简单通信协议。PC必须向微处理器发送一些命令和参数。微控制器必须传输字节数组(来自传感器的数据)。
数据必须是 噪音保护 (除了奇偶校验之外,我想我还需要一些其他的数据校正方法)。
有没有标准的解决方案可以做到这一点?(我只需要一个想法,而不是完整的解决方案)。
附:任何建议表示赞赏。 P.P.S 抱歉有语法错误,希望你能理解。
编辑1. 我还没有决定是否会 主从 协议或双方都可以发起通信。PC 必须知道微控制器何时完成工作并可以发送数据。如果数据准备好,它可以连续轮询微控制器,或者当作业完成时微控制器可以发送数据。我不知道哪个更好更简单。
编辑2. 硬件和 物理层 协议。 自从 RS-232在PC上使用的C串口标准,我会使用 异步通信. 。我将仅使用 RxD、TxD 和 GND 信号。我不能使用额外的电线,因为微控制器据我所知不支持它们。顺便说一句,我正在使用 调压器 ATmega128芯片。
所以我将使用固定波特率、8 位数据、2 个停止位,没有奇偶校验(或有?)。
数据链路协议. 。这就是我的问题主要关心的问题。感谢您的建议 高密度脂蛋白层, 购买力平价 和 MODBUS 协议。我会研究一下。
解决方案
我会使用 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和命令处理是应用程序层。
其他提示
RS232 协议很棘手。使用 HDLC 的建议是一个很好的建议,但它不是完整的解决方案。您还需要决定其他事项:
- 两个设备之间的波特率如何确定?汽车布德?预定义,还是设置明确?
- 您会在软件或硬件或两者中进行流量控制吗?请注意,如果您使用硬件流控制,那么您 必须 确保电缆安装正确。
- 说到电缆,这对于 RS233 来说是一个巨大的痛苦。根据设备的不同,您可能需要使用直通电缆、交叉电缆或变体。
- 使用基于软件的流量控制机制非常有效,因为它允许使用最简单的电缆 - 只需三根线(TX、RX 和公共线)。
- 您选择 7 位字还是 8 位字?
- 硬件奇偶校验或软件错误检查。
我建议您使用 8 个数据位、无硬件奇偶校验、1 个停止位,并使用基于软件的流量控制。如果您的硬件支持,您应该使用自动波特率。如果不是,那么自动波特率在软件中就很难实现。
这里有一些很好的答案,这里有一些有用的指示:
即使您的数据包没有时间分隔,同步字节也是减少尝试构建数据包所需位置数量的重要方法。您的设备通常必须处理一堆垃圾数据(即打开时飞行中数据包的末尾,或硬件冲突的结果)。如果没有同步字节,您将不得不尝试从接收到的每个字节中生成数据包。同步字节意味着只有1/255字节的随机噪声可能是数据包的第一个字节。当你想要窥探你的协议时也很神奇。
当您通过 snoop工具。您可以通过为PC提供与DEVICE不同的同步字节来实现此目的。此外,这意味着设备不会响应自己的回声。
您可能需要查看错误更正(例如汉明)。将8位数据打包成12位受保护字节。这12位中的任何一位都可以在途中翻转并检索原始的8位。用于数据存储(在CD上使用)或设备无法轻松重新发送(卫星链接,单向射频)。
数据包编号让生活更轻松。发送的分组携带一个号码,响应携带相同的号码和一个标记为“响应”的标志。这意味着发送方很容易检测到从未到达的数据包(同步已损坏的数据),并且在具有慢速链接的全双工模式下,可以在收到第一个响应之前发送两个命令。这也使协议分析更容易(第三方可以理解在不知道底层协议的情况下接收了哪些数据包)
拥有一个主人是一个很棒的简化。也就是说,在全双工环境中,它根本不重要。我只想说你应该总是这样做,除非你试图节省电力,或者你正在设备端进行事件驱动(输入状态改变,样品就绪)。
我的建议是modbus。 它是一种高效且简单的标准协议,用于与具有传感器和参数的设备(例如PLC)进行通信。 您可以在 http://www.modbus.org 上获取规格。它自1979年以来一直存在并且越来越受欢迎,您可以毫无困难地找到示例和库。
几个月前我读过这个问题,问题完全相同,并且没有真正找到任何有效的东西,只需要一个微小的8位微内存。因此受到CAN和LIN的启发,我建立了一些工作。我把它叫做MIN(微控制器互连网络),我把它上传到GitHub:
https://github.com/min-protocol/min
有两个实现:一个在嵌入式C中,一个在Python中用于PC。还有一点“你好世界”测试程序,PC发送命令,固件点亮LED。我在博客上写了关于在Arduino板上运行并运行的信息:
https:// kentindell .wordpress.com / 2015/02/18 / micrcontroller互连网络分钟版本-1-0 /
MIN非常简单。我修复了第0层表示(8个数据位,1个停止位,无奇偶校验),但保持波特率打开。每帧以三个0xAA字节开始,二进制为1010101010,如果一端想要动态适应另一端,则可以进行自动波特率检测。帧是0-15字节的有效载荷,具有16位Fletcher的校验和以及控制字节和8位标识符(告诉应用程序有效载荷数据包含的内容)。
该协议使用字符填充,以便0xAA 0xAA 0xAA始终指示帧起始。这意味着如果设备退出复位,它总是与下一帧的开始同步(MIN的设计目标永远不会传递不完整或不正确的帧)。这也意味着不需要具有特定的字节间和帧间时序约束。该协议的完整细节在GitHub repo wiki中。
MIN的未来改进空间。我已经留下了一些钩子用于阻止消息传递(保留4位控制字节)和更高级别的功能协商(标识符0xFF保留),因此有足够的空间来增加对常用功能的支持。 / p>
这是另一种协议:
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信号,可以直接连接到处理器,无需电平转换。
我们使用了 TTL-232R-3V3 来自FDTI Chip,它非常适合这种应用。
我唯一的建议是,如果您需要抗噪音,您可能需要使用全双工RS-422/485。你可以使用类似于这个的IC AVR侧,然后是PC端的RS-232-> RS-422转换器,如这里的485PTBR 。如果您可以找到或制作屏蔽电缆(两对双绞屏蔽),那么您将获得更多保护。所有这一切对微型和PC都是不可见的 - 没有软件改变。
无论您做什么,都要确保使用全双工系统,并确保在IC上声明读/写使能线。
您可以查看 Telemetry
及其相关的桌面实施在python Pytelemetry
主要功能
这是一个基于PubSub的协议,但与MQTT不同,它是点对点协议,无经纪人。
与任何pubsub协议一样,您可以从主题
的一端发布,并在该主题的另一端收到通知。
在嵌入式方面,发布到主题非常简单:
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库
只要你有一个像样的UART库,C库就可以很容易地添加到任何新设备上。
您只需实例化一个名为 TM_transport
的数据结构(由 Telemetry
定义),并分配4个函数指针 read
可读
写
可写
。
// 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库
在桌面端,有 pytelemetry
模块实现协议。
如果你知道python,下面的代码连接到一个串口,在主题 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,可以使用命令行界面
Pytelemetry CLI
可以使用
启动命令行pytlm
然后你可以 connect
, ls
(list)收到的主题, print
收到的主题数据, pub
(发布)主题,或在主题上打开 plot
以实时显示接收的数据
关于奇偶校验(因为它在这里出现了几次):
他们大多没用。如果您担心单个位可能会出错更改,则很可能第二位也可能会发生变化,您将从奇偶校验中获得误报。
使用像CRC16这样的轻量级内容和查找表 - 它可以在收到每个字节时计算出来,基本上只是一个异或。 Steve Melnikoff的建议非常适合小型微观。
我还建议传输人类可读数据,而不是原始二进制文件(如果性能不是您的首要任务)。它将使调试和日志文件更加愉快。
也许这个问题可能完全是愚蠢的,但有人考虑过使用 X / Y / Z MODEM 协议?
使用上述协议之一的主要好处是可以在各种编程环境中实现即用型实现。
SLIP和UDP。认真。
所有PC和类似设备都会说出来。
TCP Lean 有一本好书和例子
Jeremy Bentham偷偷摸摸地让PIC工作TCP / IP。 AVR和PIC一样好吗?
我建议使用UDP,这很简单。