Embedded 用于在嵌入式CPU和PC之间进行通信的协议

Embedded 用于在嵌入式CPU和PC之间进行通信的协议,embedded,avr,communication-protocol,Embedded,Avr,Communication Protocol,我正在构建一个带有自己CPU(AVR Mega8)的小型设备,该设备应该连接到PC。假设物理连接和字节传递已经完成,那么在这些字节之上使用的最佳协议是什么?计算机需要能够在设备上设置某些电压,并读回某些其他电压 目前,我正在考虑一个完全由主机驱动的同步协议:计算机发送请求,嵌入式CPU应答。还有其他想法吗?关于客户机-服务器体系结构和同步协议还有很多要说的。简单性和健壮性。如果速度不是问题,你可以考虑一个紧凑的、人类可读的协议来帮助调试。我在考虑调制解调器AT命令:一个“唤醒”序列,后跟一个se

我正在构建一个带有自己CPU(AVR Mega8)的小型设备,该设备应该连接到PC。假设物理连接和字节传递已经完成,那么在这些字节之上使用的最佳协议是什么?计算机需要能够在设备上设置某些电压,并读回某些其他电压


目前,我正在考虑一个完全由主机驱动的同步协议:计算机发送请求,嵌入式CPU应答。还有其他想法吗?

关于客户机-服务器体系结构和同步协议还有很多要说的。简单性和健壮性。如果速度不是问题,你可以考虑一个紧凑的、人类可读的协议来帮助调试。我在考虑调制解调器AT命令:一个“唤醒”序列,后跟一个set/get命令,后跟一个终止符

Host -->  [V02?]      // Request voltage #2
AVR  -->  [V02=2.34]  // Reply with voltage #2
Host -->  [V06=3.12]  // Set voltage #6
AVR  -->  [V06=3.15]  // Reply with voltage #6
如果看不到结束括号,则每一方都可能超时,并且它们将在下一个打开的括号上重新同步,而下一个打开的括号不能出现在消息本身中

根据速度和可靠性要求,您可以将命令编码为一个或两个字节,并添加校验和

最好用实际电压回复,而不是简单地回显命令,因为这样可以节省后续的读取操作

定义错误消息也很有帮助,以防您需要调试。

将满足您的所有要求。它可能是一个非常简单的usb设备,只有控制管道可以向您的设备发送请求,或者您可以添加一个中断管道,允许您将设备中的更改通知主机。 有许多简单的usb控制器可以使用,例如或


传输之上的协议实际上是关于您的需求的。从您的描述看来,简单的同步协议就足够了。是什么让你四处游荡并寻找其他方法?分享您的疑问,我们将尽力帮助:)

亚当·利斯提出了很多很好的观点。简单性和健壮性应该是重点。人类可读的ASCII传输在调试时帮助很大。很好的建议


对于您的需求来说,它们可能有些过分,但HDLC和/或PPP增加了数据链路层的概念,以及数据链路层带来的所有好处(和成本)。链路管理、帧、校验和、序列号、重传等。。。所有这些都有助于确保可靠的通信,但会增加复杂性、处理和代码大小,对于您的特定应用程序来说可能不是必需的。

如果我不希望需要进行高效的二进制传输,我会选择已经建议的终端样式接口

如果我确实想使用二进制数据包格式,我倾向于使用基于PPP字节asnc HDLC格式的松散格式,该格式非常简单且易于发送和接收,基本上:

数据包以0x7e开始和结束 通过在字符前面加上0x7d并切换位5(即,用0x20进行异或)来转义字符 所以0x7e变成了0x7d 0x5e 并且0x7d变为0x7d 0x5d

每次看到0x7e时,如果存储了任何数据,则可以对其进行处理


我通常做主机驱动的同步工作,除非我有很好的理由去做。这是一种从简单的点RS232扩展到多点RS422/485的技术,不费吹灰之力——通常是一种额外的优势。

我的投票是支持人类可读的


但是如果您使用二进制,请尝试在数据包的开头添加一个头字节来标记数据包的开头。我总是运气不好,串行协议不同步。头字节允许嵌入式系统与PC重新同步。另外,在末尾添加一个校验和。

我用简单的二进制格式做过类似的事情

struct PacketHdr
{
  char syncByte1;
  char syncByte2;
  char packetType;
  char bytesToFollow;  //-or- totalPacketSize
};

struct VoltageSet
{ 
   struct PacketHdr;
   int16 channelId;
   int16 voltageLevel; 
   uint16 crc;
};

struct VoltageResponse
{
   struct PacketHdr;
   int16 data[N];  //Num channels are fixed
   uint16 crc;
}
同步字节在同步协议中不如在异步协议中那么重要,但它们仍然有帮助,特别是当嵌入式系统首次通电时,而且您不知道它得到的第一个字节是否在消息的中间

类型应该是一个枚举,告诉如何解释数据包。可以从类型推断大小,但如果显式发送,则接收器可以处理未知类型而不会阻塞。您可以使用“总数据包大小”或“要跟随的字节数”;后者可以使接收器代码更干净一些

最后的CRC增加了您拥有有效数据的更多保证。有时我在头中看到了CRC,这使得声明结构更容易,但将其放在末尾可以避免在发送消息时对数据进行额外的传递

发送方和接收方都应该在接收到数据包的第一个字节后开始超时,以防丢失一个字节。当嵌入式系统未连接且根本没有响应时,PC端还需要一个超时来处理这种情况


如果您确定两个平台都使用IEEE-754浮点(PC的do)并且具有相同的endianness,那么您可以使用浮点作为数据类型。否则,使用整数更安全,可以是原始A/D位,也可以是预设的刻度(即1位=.001V给出+/-32.267 V的范围)

因为您可能已经从所有不直接指向协议的响应中确定,滚动您自己的方法是您的最佳选择

所以,这让我思考,好吧,这里是我的一些想法--

考虑到该芯片有6个ADC通道,很可能您使用的是Rs-232串行通信(您的问题中有一个猜测),当然,有限的代码空间,定义一个简单的命令结构会有所帮助,正如Adam所指出的——您可能希望在芯片上将输入处理保持在最低限度,因此,二进制听起来很吸引人,但折衷的办法是易于开发和维护(从现在起6个月后,您可能不得不排除一个无效输入的问题)——超级终端是一个强大的调试工具——因此,这让我想到了如何实现一个具有良好可靠性的简单命令结构

一些一般性考虑--

保持命令不变
  V0=3.20
  V1=3.21
  V2= ...
  D1=0
  D2=1
  D3=...
  and then start over -- 
5=0 
6=9
2=5