2016-11-01 2 views
0

Я пытаюсь прочитать данные из Xbee через последовательный порт. Если я инициализирую порт, вызвав xbee_init(), тогда я вызываю xbee_read() По какой-то причине я всегда не читаю никаких данных и получаю ошибку -1. Однако в тот момент, когда я использую стороннюю программу, такую ​​как gtkterm или последовательный монитор Arduino, чтобы посмотреть на порт, я вдруг начал читать данные из своей программы. Затем он будет работать правильно, пока я не закончу свою программу и не перезагружу ее, а затем вернется к чтению данных.Невозможно прочитать последовательные данные, если порт не открыт третьей стороной.

У кого-нибудь есть идея, почему это происходит? Я тестировал это как с Xbee, так и с Arduino, и это то же поведение. Я называю эти функции большей программой на C++. Благодаря!

#include <string.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <errno.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <fcntl.h> 
#include <termios.h> 
#include "../include/m545_wireless_communication/readXbee.h" 

int xbee_init (char *port, struct termios *tty) { 

    int fd=open(port,O_RDWR | O_NOCTTY | O_NONBLOCK); 

    if(fd == -1){return 0;} 
    else { 
     if(tcgetattr(fd, tty)!=0){return 0;} 
     else{ 
       cfsetospeed(tty, B57600); 
       cfsetispeed(tty, B57600); 

       tty->c_cflag &= ~PARENB; 
       tty->c_cflag &= ~CSTOPB; 
       tty->c_cflag &= ~CSIZE; 
       tty->c_cflag |= CS8; 
       tty->c_cflag &= ~CRTSCTS; 
       tty->c_cflag |= CLOCAL | CREAD; 

       tty->c_iflag |= IGNPAR | IGNCR; 
       tty->c_iflag &= ~(IXON | IXOFF | IXANY); 
       tty->c_lflag |= ICANON; 
       tty->c_oflag &= ~OPOST; 
       tcsetattr(fd, TCSANOW, tty); 

       } 
      } 

    return fd; 
} 


char* xbee_read (int fd, char *buffer) { 

    if(fd){ 
     int n=read(fd,buffer,11); 
     printf("%d\n", n); 
     return buffer; 
    }else{ 
     return NULL; 
    } 
} 

void xbee_close(int fd){ 
    close(fd); 
} 

Вот основная функция, которая вызывает мои функции xbee. Это часть проекта ROS, и этот узел предназначен для простого чтения данных из xbee через последовательный порт и публикации его в тему/xbee с частотой 10 Гц.

#include "ros/ros.h" 
#include "std_msgs/String.h" 
#include <sstream> 
#include <termios.h> 
#include "m545_wireless_communication/readXbee.h" 


int main(int argc, char **argv) 
{ 

    ros::init(argc, argv, "Broadcaster"); 

    ros::NodeHandle broadcasterHandle; 
    ros::Publisher broadPub = broadcasterHandle.advertise<std_msgs::String>("xbee", 1); 

    char *port = "/dev/ttyUSB1"; 
    struct termios tty; 
    char buffer[11]; 

    int fd = xbee_init(port,&tty); 

    ros::Rate loop_rate(10); 

    while (ros::ok()) 
    { 
    char *message = xbee_read(fd, buffer); 

    std_msgs::String msg; 

    std::stringstream ss; 
    ss << message; 
    msg.data = ss.str(); 

    ROS_INFO("I heard: %s", msg.data.c_str()); 

    broadPub.publish(msg); 

    ros::spinOnce(); 

    loop_rate.sleep(); 
    } 

    ROS_INFO("Closing Port"); 
    xbee_close(fd); 

    return 0; 
} 
+0

1) Примечание: Если 'c_cflag' поле кода является шире, чем' unsigned', то '& = ~ various_int_constants;' может быть проблемой. 'tty-> c_cflag | = PARENB; tty-> c_cflag^= PARENB; 'избегает этой редкой проблемы. 2) Отправьте код, который вызывает 'xbee_read()' и другие 2 функции. – chux

+0

Спасибо @chux вы положили меня на путь двойной проверки всех c_cflags – raab

+1

* «Я всегда читаю данные и получаю ошибку -1.» * - Тогда вам нужно получить доступ к глобальной переменной ** errno ** to получить информацию об ошибке. Коренная проблема заключается в том, что вы используете неблокирующий режим. См. Http://stackoverflow.com/questions/1613916/linux-serial-port-read-returning-eagain – sawdust

ответ

0

Я смог выяснить, что проблема заключалась в том, как я объявлял c_cflags. Xbee нужно читать в необработанном режиме, поэтому вместо того, чтобы устанавливать флаги, я просто использовал cfmakeraw(). Однако я все еще не уверен, что именно я делал неправильно или как открытие порта с помощью сторонних программ помогло подключению.

int xbee_init (char *port, struct termios *tty) { 

    int fd=open(port,O_RDWR | O_NOCTTY | O_NONBLOCK); 

    if(fd == -1){return 0;}//should be something better 
    else { 
     if(tcgetattr(fd, tty)!=0){return 0;} 
     else{ 
       // cfsetospeed(tty, B57600); 
       // cfsetispeed(tty, B57600); 

       // tty->c_cflag &= ~PARENB; 
       // tty->c_cflag &= ~CSTOPB; 
       // tty->c_cflag &= ~CSIZE; 
       // tty->c_cflag |= CS8; 
       // tty->c_cflag &= ~CRTSCTS; 
       // tty->c_cflag |= CLOCAL | CREAD; 
       // // tty->c_cflag |= PARENB; 
       // // tty->c_cflag ^= PARENB; 

       // tty->c_iflag |= IGNPAR | IGNCR; 
       // tty->c_iflag &= ~(IXON | IXOFF | IXANY); 
       // tty->c_lflag |= ICANON; 
       // tty->c_oflag &= ~OPOST; 

       cfmakeraw(&tty); 
       cfsetispeed(&tty, B57600); 

       tcsetattr(fd, TCSANOW, &tty); 

       } 
      } 

    return fd; 
} 
+1

Вы только маскируете проблему с корнем и имеете неполную конфигурацию termios. Пример кода см. В http://stackoverflow.com/questions/12437593/how-to-read-a-binary-data-over-serial-terminal-in-c-program/12457195#12457195. В противном случае изучите [Руководство по серийному программированию для операционных систем POSIX] (http://www.cmrr.umn.edu/~strupp/serial.html) – sawdust

Смежные вопросы