【问题标题】:Receive extra null byte when using serial port使用串口时收到额外的空字节
【发布时间】:2014-12-15 22:24:00
【问题描述】:

我在Linux上写一个串口数据传输的程序,但是发现每次发送方打开端口,接收方都会得到一个额外的空字节'\x00'

这里是发件人的代码:

#include <unistd.h>
#include <termios.h>
#include <fcntl.h>

int main(int argc, char* argv[]) {
  int fd_com_ = open("/dev/ttyAM0", O_RDWR | O_NOCTTY | O_NONBLOCK);

  struct termios attrs_;
  attrs_.c_iflag = IGNBRK;
  attrs_.c_oflag = 0;
  attrs_.c_cflag = (CLOCAL | CREAD);
  attrs_.c_cflag |= CS8;
  attrs_.c_lflag = 0;
  attrs_.c_cc[VMIN] = 0;
  attrs_.c_cc[VTIME] = 0;
  cfsetspeed(&attrs_, B115200);

  tcsetattr(fd_com_, TCSANOW, &attrs_);

  const char *s = "abcd";
  write(fd_com_, s, 4);
  sleep(1);
  write(fd_com_, s, 4);
  sleep(1);
  close(fd_com_);

  fd_com_ = open("/dev/ttyAM0", O_RDWR | O_NOCTTY | O_NONBLOCK);
  write(fd_com_, s, 4);

  return 0;
}

接收器具有相同的配置,但接收到"\x00abcdabcd\x00abcd"。如何解决这个问题,以便接收者可以得到"abcdabcdabcd"


更新:

接收方代码:

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>

int main(int argc, char* argv[]) {
  int fd_com_ = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK);

  struct termios attrs_;
  attrs_.c_iflag = IGNBRK;
  attrs_.c_oflag = 0;
  attrs_.c_cflag = (CLOCAL | CREAD);
  attrs_.c_cflag |= CS8;
  attrs_.c_lflag = 0;
  attrs_.c_cc[VMIN] = 0;
  attrs_.c_cc[VTIME] = 0;
  cfsetspeed(&attrs_, B115200);

  tcsetattr(fd_com_, TCSANOW, &attrs_);

  char buf[100];
  ssize_t sz;
  while(1) {
    sz = read(fd_com_, buf, 100);
    if (sz > 0) {
      for (ssize_t i=0; i<sz; i++) {
        printf("%02hhx\n", buf[i]);
      }
    }
    sleep(1);
  }

  return 0;
}

【问题讨论】:

  • 如果只打开和关闭端口,是否也会收到空字节?可以发一下接收代码吗?
  • @iharob 是的,在评论最后一个write 之后,接收者仍然得到一个空字节。我已经发布了接收者的代码。
  • 你能描述一下串口设置,什么连接在哪里。
  • @iharob 发送器在 ARM 板上运行,接收器在我的 PC 上。由于我的 PC 上没有串行端口,因此使用了 USB 串行设备。
  • 对不起,我不知道如何帮助你。它可能与您的特定设置有关,因为 write 函数正在发送正确的数据,并且代码对我来说看起来不错,所以不知道发生了什么。我多希望我能帮忙。我以前使用过串行端口,但从未遇到过这种行为。

标签: c linux serial-port


【解决方案1】:

请查看您的 ARM 板的文档,了解 ARM 的 UART 是如何连接的,以及它是如何在硬件中和您的平台驱动程序中配置的。

根据您的描述,我假设在打开 ARM 上的 UART 端口时,物理 UART(即 ARM 内的硬件外围模块或可能是外部有线 UART 芯片)被启用或从某个未知空闲状态恢复状态到 RS232 的正确 -12 伏空闲状态。这种转换可能足以让您 PC 的 UART 识别起始位并接收虚假字符。

您可能想使用示波器检查串行线路,看看实际打开端口时会发生什么。

【讨论】:

  • 好主意。 “打开”库函数通常配置引脚复用,而串行端口“关闭”时,引脚可能被配置为由 UART 以外的其他外设(可能是 GPIO)使用。当然,单片机和USB串口适配器之间一般使用TTL串口。与 RS-232 不同,对于 TTL 串行,空闲状态是正电压。
  • 也许你是对的。我测试了两台电脑之间的代码,问题就消失了。
  • 这就是为什么硬件工程师讨厌程序员的原因:程序员的新代码不起作用,所以他怀疑硬件有问题,即使代码充满了缺陷。 @BenVoigt 请指出一些具有“'open'库函数(通常配置引脚多路复用)”的代码。引脚复用是为了设计灵活性,很少用作动态重配置。该板需要反映 SoC 的多路复用。
【解决方案2】:

最初的\x0 表示发生奇偶校验或帧错误。 发生此错误是因为未正确设置 termios 字段。 所以初始线高/低状态和开始/停止位的数量和奇偶校验 没有正确设置。

您可能会阅读:http://man7.org/linux/man-pages/man3/termios.3.html 其中讨论了每个字段及其内容和含义。

(链接页面太长,无法在此处发布)

【讨论】:

  • 请不要对非代码内容使用代码格式(在本例中为缩进)。
  • 顺便说一句,如果停止位或奇偶校验配置错误,则不太可能正确传输以下数据。
  • 但是 0x0 字符很可能是(可能未配置的)任何类型接收错误(PE、FE)的替代字符
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-27
  • 1970-01-01
  • 2012-11-24
  • 2021-02-16
  • 1970-01-01
相关资源
最近更新 更多