簡體   English   中英

在Linux中使用C使用USB串行電纜從傳感器進行串行讀取

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

我一直在嘗試使用USB到串行轉換器讀取與樹莓派接口的串行溫度傳感器的響應。

我可以看到對傳感器設備的寫入似乎有效。 但是,當我嘗試從串行芯片回讀時,讀取失敗並顯示為-1。

我確實嘗試過使用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);
}

上面的功能似乎按預期方式寫入了串行端口,但是當我嘗試讀取時,讀取失敗並顯示-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];
}

使用Realterm Windows應用程序,所有寫入和讀取似乎都可以正常工作。

從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.

對於串行連接,最終結果將是:如果您要求從串行端口讀取一定數量的字節,並且沒有等待的字符,則讀取將以-1返回,並且'errno'可能是EAGAIN或EWOULDBLOCK。

因此,您的usleep(8000)可能是試圖等待足夠長的時間以使設備響應,但該設備可能沒有適合您的數據。 尤其是在進行adc操作的過程中,可能需要8ms以上的時間。

您可以做幾件事:

您可以(以偽代碼):

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

不幸的是,這樣做的一個副作用是,如果溫度傳感器向您發送一個長字符串,而在溫度傳感器仍在寫入時您的程序為read()s,則會得到部分字符串。 因此,如果知道等待接收的字符串的長度,則可以使用ioctl()來查找等待等待的字符數:

ioctl(fd, FIONREAD, &bytes_avail);

因此偽代碼看起來更像:

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);
}

如果溫度傳感器發送以換行符或回車符結尾的ascii字符串,則代碼看起來會有所不同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM