2

我在尝试通过 USB 在 teensy 和 Raspberry Pi3 之间进行通信时遇到了一些麻烦。

当我发送 unsigned int 时,我收到的所有包含值 13 字节的数字都错误,该字节更改为值 10

例如 :

13 becomes 10;
269 becomes 266;
525 becomes 522;
781 becomes 778;
1037 1034;
1293 1290; 
1549 1546; 
1805 1802; 
etc...

但不是为了其他人...

不管我是在 pi 上使用我的程序还是发送 cat 命令/dev/ttyACMO。但是,当我在另一台计算机上执行相同操作时,一切正常。

我在另一台计算机上遇到了同样的问题,所以我认为问题来自我安装的错误库。

你有什么主意吗?

PS:teensy 上的代码很简单:

    unsigned int i = 0;
    while(true){
        Serial.write((char*) &i, 4);
        ++i;
        delay(500);
    }
4

1 回答 1

1

ASCII 十进制 10 是换行符 ( <LF>)。ASCII 十进制 13 是回车符 ( <LF>)。

你很可能是隐式<CR><LF><LF>转换的受害者;维基百科详细解释了它,但总而言之,它植根于技术历史:

  • 当计算机第一次被赋予文本输入/输出能力时,这不是通过显示器完成的,而是通过电传打字机完成的。电传打字机本质上是一种机械打字机,其中每个“键”也可以被电信号击中。

  • 打字机和电传打字机区分了将纸张推进一行(换行)和将车厢(打字头)返回到一行的开头。

  • ASCII 编码本质上是打字机功能到二进制模式的 1:1 映射。

最终效果是,为了在电传打字机上开始新行,您必须发送换行符<LF>)和回车符<CR>),两者的顺序并不重要,物理效果是几乎一样。

然而,不同的操作系统采用不同的默认约定如何存储和传输换行符:

  • MS-DOS 和继承 Windows 选择显式存储两者<CR><LF>按此顺序。

  • Unix 选择存储<LF>唯一并<CR><LF>在将其发送到电传打字机时将其转换为序列,反之亦然。Linux 采用了这个 Unix 约定。

当涉及到通过串行链路进行传输时,默认值始终是,对于换行符,(<CR>,<LF>)应该传输一对,期望另一端是电传打字机。这就是,这里可能发生的事情!通过网络传输的实际数据是 a<CR><LF>但继承了 Unix 方式的接收操作系统会默默地将其转换为普通的<LF>. 对于任何大于 255 的数字,这种转换将发生在它的低 8 个字节上,同时丢弃一个完整的字节。

当然,这个默认行为可以重新配置,即通过打开的串口上的termios/ioctl_ttyOPOST ,特别是输出和输入选项标志(即标志, ONLCR, ONLCR, OCRNL, ONLRET, INLCR, IGNCR, ICRNL)。

但是,我强烈建议您不要摆弄这些标志,而应牢记以下两个教训:

  • 纯文本是通用的交换格式! (即不要通过网络提交原始二进制文件,如果可以避免的话,但将其作为 - 也是人类可读的 - 文本发送)

  • 自由地阅读你收到的东西;发送的内容要保守! (即以某种方式编写程序,即读取数据不依赖于数据的严格顺序和格式,即可以容忍任何类型的换行序列或空格分隔字段的数量;但也以严格的常规方式发送数据,所以不太自由的接收者不会窒息它)

于 2018-10-07T13:03:21.407 回答