Последовательное считывание с датчика с помощью USB-последовательного кабеля в Linux с использованием C - PullRequest
0 голосов
/ 24 декабря 2018

Я пытался прочитать ответы от последовательного датчика температуры, подключенного к моему Raspberry Pi, используя конвертер USB в последовательный порт.

Я вижу, что запись в сенсорное устройство, кажется, работает.Однако, когда я пытаюсь прочитать обратно с последовательного чипа, чтение не удается с -1.

Я пытался использовать ту же скорость передачи данных 9600 8 бит без настройки четности с помощью программы realterm и смог читать и записывать шестнадцатеричные значения, как и ожидалось, пожалуйста, укажите мне правильное направление.

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, все операции записи и чтения, кажется, работают нормально

1 Ответ

0 голосов
/ 24 декабря 2018

Из открытой страницы (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.

Для последовательного соединения конечным результатом будет то, что если вы попросите прочитать некоторое количество байтов из последовательного порта, и не будет символов, ожидающих, затем read вернется с -1, и 'errno', вероятно, будет EAGAIN или EWOULDBLOCK.

Так что ваш usleep (8000), вероятно, был попыткой подождать достаточно долго, чтобы устройство ответило, но устройство может не иметьданные для вас;особенно если он находится в середине операции АЦП, это может занять более 8 мс.

Вы можете сделать несколько вещей:

Вы можете (в псевдокоде):

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

К сожалению, одним из побочных эффектов этого является то, что, если датчик температуры отправляет вам длинную строку и ваша программа читает (), пока датчик температуры все еще пишет, вы получите частичную строку.Поэтому, если вы знаете длину строки, которую вы ожидаете получить, вы можете использовать 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, оканчивающуюся переводом строки или возвратом каретки, код будет выглядеть иначе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...