串行 c 读入 linux 有问题

serial c to read in linux with issues

我正在尝试使用Odroid(单机板)在C中读取串口以通过usb电缆从arduino板获取数据。发布传感器数据就像 189。波特率为115200.

读取使用的主要代码:

#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/ipc.h>
#include <sys/shm.h>
#include "share.h"
#include <math.h>
#include <stdlib.h>
#pragma GCC diagnostic ignored "-Wwrite-strings"

/*
 * @brief Open serial port with the given device name
 *
 * @return The file descriptor on success or -1 on error.
 */
int open_port(char *port_device)
{
    int fd; /* File descriptor for the port */

    fd = open(port_device, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)
    {
        perror("open_port: Unable to open /dev/Servo_LIDAR ");
    }
    else
        fcntl(fd, F_SETFL, 0);

    return (fd);
}

int main()
{

//--------------------------------------------------------------------------------
    struct termios options;
    int fd=-1;
    char *u_port = "/dev/Servo_LIDAR";
    fd=open_port(u_port);
    if(fd==-1)
    {
       printf("port not open");
       return -1;
    }

    tcgetattr(fd, &options);
    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);

    //Enable the receiver and set local mode...
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~CSIZE; /* Mask the character size bits */
    options.c_cflag |= CS8; /* Select 8 data bits */

    //No parity
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    //Set the new options for the port...
    tcsetattr(fd, TCSANOW, &options);


    printf("Reading...\n"); 

   while(true) 
  {


    while(1)
    {       
        //sleep(0.5);
        char buff[1024]={0};
        char buf[1]={0};
        while(1) {  
           ssize_t res=read(fd, buf, 1);

           if(res==0) continue;  
           buf[res]=0;  

           strcat(buff,buf);
           if (buf[0] == '\n')  break; 
      }  
      printf("%s\n", buff); 
      usleep(70000);
    break;
    }
 }

    close(fd);


}

我有这样的约会:

187

187187187

188

188188

188188188

188

1888

188

18188

188

186187

187

187

每次应该是3个字节的数据,但我遇到了这样的问题。任何建议,谢谢。

有几件事我会尝试。首先是调整读取returns 0字节后的休眠。如果串行端口不是 buffered/interrupt 驱动,则 10ms 非常接近接收一个字节所需的时间(当前波特率是 11.52)。

第二个问题可能在输出端。您是否考虑过问题可能在那里?尝试每读取 10 次才打印一次,从而减少输出端的流量。

您的主要错误涉及语句:

    char buf[1]={0};
...  
       ssize_t res=read(fd, buf, 1);
...
       buf[res]=0;  

数组buf[]声明只有一个个元素长,即buf[0] 是数组的唯一元素。
read() 系统调用成功时的 return 值为 1,因为这是指定的计数。
然后您尝试通过写入 buf[1] 来终止接收到的文本,但这是一个尚未分配的元素。
数组 buf[] 需要至少 2 个元素长。

此错误的症状因编译器和主机系统而异。在使用 gcc 4.8.4 的 x86 笔记本电脑上,您的原始程序根本没有输出。

有关终止缓冲区数据的首选方法,请参阅


代码审查

  1. 所有系统调用,包括 tc[gs]etattr()read(),应该是检查错误 return 代码,尤其是当您的程序未按预期运行时。

  2. 您的 termios 配置不完整。您的程序将以任何先前配置的规范或非规范模式执行。这可能会产生意想不到的结果。

  3. 一次只读取一个字符(嵌套在多个 while 循环中)效率低下。规范读取可以 return 每个系统调用一行。学习"Two Styles of Input: Canonical or Not"

  4. 诸如usleep(70000)之类的程序延迟是多余的。 file/device 已打开以阻止读取,因此 read() 不会 return 直到数据可用。