简体   繁体   English

在Linux中使用C使用USB串行电缆从传感器进行串行读取

[英]Serial reads from a sensor using USB-serial cable in linux using C

I have been trying to read the responses from a serial temperature sensor interfaced to my raspberry pi using a USB to serial converter. 我一直在尝试使用USB到串行转换器读取与树莓派接口的串行温度传感器的响应。

I can see that the writes to the sensor device seem to work. 我可以看到对传感器设备的写入似乎有效。 However when I try to read back from the serial chip the read fails with -1. 但是,当我尝试从串行芯片回读时,读取失败并显示为-1。

I did try to use the same baud rate 9600 8 bit no parity settings using realterm program and was able to read and write hex values as expected, kindly point me in the right direction. 我确实尝试过使用Realterm程序使用相同的波特率9600 8位无奇偶校验设置,并且能够按预期方式读取和写入十六进制值,请指出正确的方向。

void serial_write(char parameter,char value) {
    int fd;
    uint8_t bytes_wr;
    char wr_buffer[3];
    fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NDELAY); 

    if (fd == -1)
        ERROR("Error! in Opening ttyUSB0 \n");
    else
        DEBUG("ttyUSB0 Opened Successfully \n");

    struct termios SerialPortSettings;
    tcgetattr(fd, &SerialPortSettings);

    cfsetispeed(&SerialPortSettings,B9600);
    cfsetospeed(&SerialPortSettings,B9600);

    SerialPortSettings.c_cflag &= ~PARENB;
    SerialPortSettings.c_cflag &= ~CSTOPB;
    SerialPortSettings.c_cflag &= ~CSIZE;
    SerialPortSettings.c_cflag |=  CS8; 
    SerialPortSettings.c_cflag &= ~CRTSCTS;
    SerialPortSettings.c_cflag |= CREAD | CLOCAL;
    SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);  
    SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    SerialPortSettings.c_oflag &= ~OPOST;

    if ((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) 
        ERROR("ERROR ! in Setting attributes \n");
    else
        DEBUG("BaudRate=9600\tStopBits=1\tParity=none \n");

    wr_buffer[0] = write;
    wr_buffer[1] = parameter;
    wr_buffer[2] = value;

    bytes_wr = write(fd, wr_buffer,sizeof(wr_buffer));
    DEBUG("Total Bytes written: %d \n", sizeof(wr_buffer));

    close(fd);
}

The above function seems to write as expected to the serial port, however when I try to read, the reads fails with a -1 上面的功能似乎按预期方式写入了串行端口,但是当我尝试读取时,读取失败并显示-1

char serial_read(char parameter) {
    int fd, read_length, i;
    uint8_t bytes_wr;
    char wr_buffer[2];
    fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NDELAY); 

    if (fd == -1)
        ERROR("Error! in Opening ttyUSB0 \n");
    else
        DEBUG("ttyUSB0 Opened Successfully \n");

    struct termios SerialPortSettings;
    tcgetattr(fd, &SerialPortSettings);

    cfsetispeed(&SerialPortSettings,B9600);
    cfsetospeed(&SerialPortSettings,B9600);

    SerialPortSettings.c_cflag &= ~PARENB;
    SerialPortSettings.c_cflag &= ~CSTOPB;
    SerialPortSettings.c_cflag &= ~CSIZE;
    SerialPortSettings.c_cflag |=  CS8; 
    SerialPortSettings.c_cflag &= ~CRTSCTS;
    SerialPortSettings.c_cflag |= CREAD | CLOCAL;
    SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);  
    SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    SerialPortSettings.c_oflag &= ~OPOST;

    if ((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) 
        ERROR("ERROR ! in Setting attributes \n");
    else
        DEBUG("BaudRate=9600\tStopBits=1\tParity= none\n");

    wr_buffer[0] = read;
    wr_buffer[1] = parameter;

    bytes_wr = write(fd, wr_buffer,sizeof(wr_buffer));
    DEBUG("Total Bytes written: %d \n", sizeof(wr_buffer));
    usleep(8000);
    tcflush(fd,TCIFLUSH);
    char rd_buffer[4];
    read_length = read(fd, rd_buffer,sizeof(rd_buffer));
    DEBUG("Total bytes read = %d \n",read_length);

    for (i==0;i<read_length;i++){
        DEBUG("rd_buffer[%d]=%x \n",i,rd_buffer[i]);
    }
    close(fd);
    return rd_buffer[0];
}

With realterm windows application all writes and reads seem to work fine. 使用Realterm Windows应用程序,所有写入和读取似乎都可以正常工作。

From the open(2) manpage: 从open(2)联机帮助页:

   O_NONBLOCK or O_NDELAY
          When possible, the file is opened in nonblocking mode.
          Neither the open() nor any subsequent operations on the file
          descriptor which is returned will cause the calling process to
          wait.

For a serial connection, the end result will be that if you ask to read some number of bytes from the serial port and there are no characters waiting, then read will return with -1 and 'errno' will probably be EAGAIN or EWOULDBLOCK. 对于串行连接,最终结果将是:如果您要求从串行端口读取一定数量的字节,并且没有等待的字符,则读取将以-1返回,并且'errno'可能是EAGAIN或EWOULDBLOCK。

So your usleep(8000) was probably an attempt to wait long enough for the device to respond but the device may not have data for you; 因此,您的usleep(8000)可能是试图等待足够长的时间以使设备响应,但该设备可能没有适合您的数据。 especially if it is in the middle of an adc operation, it might take longer than 8ms. 尤其是在进行adc操作的过程中,可能需要8ms以上的时间。

There are a few things you can do: 您可以做几件事:

You can (in pseudo code): 您可以(以伪代码):

int retries=10;
while(retries--) {
    read_length = read(fd, rd_buffer,sizeof(rd_buffer));
    if(read_length > 0)
        break;
    usleep(1000);
}

Unfortunately, one side effect of this is that if the temperature sensor is sending you a lengthy string and your program read()s while the temperature sensor is still writing, you will get a partial string. 不幸的是,这样做的一个副作用是,如果温度传感器向您发送一个长字符串,而在温度传感器仍在写入时您的程序为read()s,则会得到部分字符串。 So if you know the length of string that you're waiting to receive, you could use an ioctl() to find out how many characters are waiting: 因此,如果知道等待接收的字符串的长度,则可以使用ioctl()来查找等待等待的字符数:

ioctl(fd, FIONREAD, &bytes_avail);

So the pseudo code would look more like: 因此伪代码看起来更像:

int retries=10;
int bytes_avail=0;
while(retries--) {
    if (ioctl(fd, FIONREAD, &bytes_avail) < 0) {
        fprintf(stderr, "ioctl failed\n");
        return;   // Do something here
    }
    if (bytes_avail >= sizeof(rd_buffer)) {
        read_length = read(fd, rd_buffer,sizeof(rd_buffer));
        if(read_length > 0)
            break;
    }
    usleep(1000);
}

If the temperature sensor sends an ascii string that is terminated with a newline or carriage-return, then the code would look different. 如果温度传感器发送以换行符或回车符结尾的ascii字符串,则代码看起来会有所不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM