c/c++语言开发共享从c中的串口读取会破坏线路

我正在尝试用C编写一个小程序,它将使用select命令从串口读取,以便它阻塞并等待输入。 它正在工作,除了它不断分裂线,我不知道为什么。 该设备的编程不会破坏线路,并且可以与实际的终端程序一起使用。 我之前从未在C中进行过串口通信,而且我在Mac上,所以这对我来说都是新手。 我真的不知道在哪里可以找到出错的地方。

我有一些代码可以找到并列出串口。 为了简单起见,我会把它留下来,所以如果有一个没有意义的变量,那可能就是原因。 以下是打开端口,设置属性并尝试从中读取的代码,以及来自Apple网站的复制注释(对不起):

/* this is based on a combination of https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c * and https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html */ static int OpenSerialPort(const char *deviceFilePath, int speed) { int fileDescriptor = -1; struct termios options; memset(&options, 0, sizeof(options)); // init it // Open the serial port read/write, with no controlling terminal, // and don't wait for a connection. // The O_NONBLOCK flag also causes subsequent I/O on the device to // be non-blocking. // See open(2) ("man 2 open") for details. fileDescriptor = open(deviceFilePath, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fileDescriptor == -1) { printf("Error opening serial port %s - %s(%d).n", deviceFilePath, strerror(errno), errno); goto error; } // Note that open() follows POSIX semantics: multiple open() calls to // the same file will succeed unless the TIOCEXCL ioctl is issued. // This will prevent additional opens except by root-owned processes. // See options(4) ("man 4 options") and ioctl(2) ("man 2 ioctl") for details. if (ioctl(fileDescriptor, TIOCEXCL) == kMyErrReturn) { printf("Error setting TIOCEXCL on %s - %s(%d).n", deviceFilePath, strerror(errno), errno); goto error; } // Set raw input (non-canonical) mode, with reads blocking until either // a single character has been received or a one second timeout expires. // See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios") // for details. cfmakeraw(&options); options.c_cc[VMIN] = 1; options.c_cc[VTIME] = 5; // The baud rate, word length, and handshake options can be set as follows: cfsetspeed(&options, speed); // Set 19200 baud options.c_cflag = (options.c_cflag & ~CSIZE) | CS8; // 8-bit chars // disable IGNBRK for mismatched speed tests; otherwise receive break // as 00 chars options.c_iflag &= ~IGNBRK; // disable break processing options.c_lflag = 0; // no signaling chars, no echo, // no canonical processing options.c_oflag = 0; // no remapping, no delays options.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl options.c_cflag |= (CLOCAL | CREAD);// ignore modem controls, // enable reading options.c_cflag &= ~(PARENB | PARODD); // shut off parity options.c_cflag |= false; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CRTSCTS; // Cause the new options to take effect immediately. if (tcsetattr(fileDescriptor, TCSANOW, &options) == kMyErrReturn) { printf("Error setting options attributes %s - %s(%d).n", deviceFilePath, strerror(errno), errno); goto error; } // turn on blocking if (fcntl(fileDescriptor, F_SETFL, 0) == kMyErrReturn) { printf("Error clearing O_NONBLOCK %s - %s(%d).n", deviceFilePath, strerror(errno), errno); goto error; } // Success: return fileDescriptor; // Failure: error: if (fileDescriptor != kMyErrReturn) { close(fileDescriptor); } return -1; } int main(void) { int fileDescriptor; kern_return_t kernResult; // these are Apple-specific io_iterator_t serialPortIterator; // Apple char deviceFilePath[MAXPATHLEN]; fd_set fdset; // make a file descriptor set FD_ZERO (&fdset); // init it char buf[1000]; // some strings are big kernResult = GetDevices(&serialPortIterator); printf("Devices on this system:n"); kernResult = ListDevicePaths(serialPortIterator, deviceFilePath, sizeof(deviceFilePath)); IOObjectRelease(serialPortIterator); // Release the iterator. // Open the modem port, initialize the modem, then close it. if (!deviceFilePath[0]) { printf("No modem port found.n"); return EX_UNAVAILABLE; } fileDescriptor = OpenSerialPort("/dev/cu.usbmodem1d1111", B230400); FD_SET (fileDescriptor, &fdset); // add to file descriptor set // now we're going to use select to only read from the file handle when there's data available while (1) { if (select (FD_SETSIZE, &fdset, NULL, NULL, NULL) < 0) // this will block the program until something is on the line { printf("select errorn"); } read(fileDescriptor, buf, 1000); printf("%sn", buf); memset(buf, '', 1000); } // let's try to read from the serial port /* for (int i = 0; i <= 10; i++) { char buf [100]; int n = read(fileDescriptor, buf, sizeof buf); printf("%sn", buf); //usleep ((7 + 25) * 100); }*/ close(fileDescriptor); printf("Modem port closed.n"); return EX_OK; } 

预期产量:

  This is sample output. Hello. 

我在上述程序中实际获得的内容:

  Thi s is sam ple output. Hel lo. 

或类似的东西。 每次都不一样。 有时它工作正常。 这似乎是随机的。

所以我的问题是:我做错了什么? 我需要做什么代码,除了一条毯子“所有这些?” 我不明白的是什么? 我承认我并不真正理解这些库是如何工作的。 我假设(我知道,我知道)他们负责流量控制和错误等等。 但话说回来,我复制过的例子并没有完全解释,所以我不知道。 我只是不知道发生了什么。

    它不断分裂线,我不明白为什么。

    如果要从串行端口读取行,则必须对其进行配置才能执行此操作。
    相反,您已将其配置为非规范和非阻止模式。
    该代码根本不符合您声明的意图。

    从Linux termios 手册页引用:

    在规范模式中:
    输入逐行提供。 键入其中一个行分隔符(NL,EOL,EOL2;或行首的EOF)时,输入行可用。 除EOF外,行分隔符包含在read(2)返回的缓冲区中。

    代码清楚地表明它使用的是非规范模式(即错误的模式):

     // Set raw input (non-canonical) mode, with reads blocking until either // a single character has been received or a one second timeout expires. // See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios") // for details. cfmakeraw(&options); options.c_cc[VMIN] = 1; options.c_cc[VTIME] = 5; 

    您需要删除这些行以获取规范模式并读取行而不是原始字节。

    如果您希望read()返回完整的行,那么程序将不得不等待输入。 这意味着您需要阻止I / O.

     // The O_NONBLOCK flag also causes subsequent I/O on the device to // be non-blocking. // See open(2) ("man 2 open") for details. fileDescriptor = open(deviceFilePath, O_RDWR | O_NOCTTY | O_NONBLOCK); 

    需要从open()系统调用中删除O_NONBLOCK选项。

    尽管至少有三个评论者写过,但可以配置Linux串口来读取行。 您正在使用真正的操作系统,而不是在微处理器上运行裸机。 您所要做的就是激活线路规则来扫描串行端口接收的字符。
    有关编程规范模式的完整详细信息,请参见POSIX操作系统的串行编程指南和termios 手册页。

    您的代码还有几个问题需要纠正:

    读取代码应该是这样的:

      rc = read(fileDescriptor, buf, sizeof(buf) - 1); if (rc < 0) { /* handle error condition */ } else { buf[rc] = ''; printf("%s", buf); } 

    由于buf []被分配为1000个字节,因此read()请求可以返回长达999个字符的行。

    问题是您正在读取任意数量的字节,然后以换行符分隔输出它们:

     read(fileDescriptor, buf, 1000); printf("%sn", buf); 

    你打开了描述符O_NONBLOCK ,我不确定你的fcntl调用是否足以清除它。 结果是read拉出但是那个时刻恰好缓冲了许多字符,然后打印它们后跟换行符。

    您可能不希望以阻塞模式read ,因为在读取1000个字符之前它可能不会返回。 这可能更接近你想要的:

     amt = read(fileDescriptor, buf, 1000); if (amt > 0) write(1,buff,amt); else break; 

    当然,应该有更多的error handling。

      以上就是c/c++开发分享从c中的串口读取会破坏线路相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/519642.html

      (0)
      上一篇 2020年12月5日
      下一篇 2020年12月5日

      精彩推荐