2016-12-19 21 views
0

我用C語言編寫的Linux串口工作下面是我的UART設置在C Linux的串行端口工作,不能夠得到充分的數據

int fd; 
struct termios tty_attributes; 
fd = open(comport, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK); 

if(fd < 0) 
{ 
    perror("open comport error.\n"); 
    exit(EXIT_FAILURE); 
} 
else 
{ 

    if(tcgetattr(fd, &tty_attributes) == -1) 
    { 
     perror("tcgetattr termios function error.\n"); 
     exit(EXIT_FAILURE); 
    } 

    tty_attributes.c_lflag = 0; 
    tty_attributes.c_oflag = 0; 
    tty_attributes.c_iflag = 0; 
    tty_attributes.c_cflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); 
    tty_attributes.c_cflag |= CS8; 
    tty_attributes.c_cflag |= CLOCAL; 
    tty_attributes.c_cflag &= ~CREAD; 
    tty_attributes.c_oflag &= ~OPOST; 
    tty_attributes.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); 
    tty_attributes.c_cc[VMIN] = SIZE_STR_FRAME; 
    cfsetospeed(&tty_attributes, BAUDRATE);  //setting communication speed and other attributes 
    cfsetispeed(&tty_attributes, BAUDRATE); 
    tcflush(fd, TCIOFLUSH); 
    tcsetattr(fd, TCSANOW, &tty_attributes);  //change immediately 
    return fd; 
} 

}

而下面是我的代碼用於讀取的幀

char* frame_read(int fd) 
{ 
    char *ret = NULL; 
    int read_ret_val; 
    struct timeval time_val; 
    if (fd < 0) 
    { 
     printf("Before read over comm channel, channel must be initialize\n"); 
     exit(EXIT_FAILURE); 
    } 
    memset(frame, 0, SIZE); 
    fd_set rfds;  //read file discriptors 
    int return_val; 
    FD_SET(fd, &rfds); 

    setReceiveMode(fd, TRUE); 
    tcflush(fd, TCIFLUSH); 
    tcflush(fd, TCOFLUSH); //flush previous values 
    return_val = select((fd) + 1, &rfds, NULL, NULL, &time_val); 
    if (return_val == -1) 
    { 
     perror("select"); 
     exit(EXIT_FAILURE); 
    } 

    else if (return_val) 
    { 
     usleep(100 * 1000); 
     read_ret_val = read(fd, frame, SIZE); 
     if (read_ret_val < 0) 
     { 
      perror("read"); 
      exit(EXIT_FAILURE); 
     } 
     ret = frame; 
     //printf("inside else if of read\n"); 
    } 
} 

我有一個GPS模塊與所述UART連接,並且當我與小型機檢查我得到的全幀,但是當我接收通過UART(使用此代碼)我得到前16個字節ö NLY。 任何人都可以指出我的錯誤。? 這裏波特率是9600,幀是64字節,SIZE是64字節,我用的緩衝區也是64字節。請原諒我格式化錯誤,如果有的話。

我的main.c文件

int main(int argc, char *argv[]) 
{ 
    int i=0,j=0; 
    char *readb; 
    unsigned char data[34]; 
    static int fd = -1; 
    struct struct_base_gps *gps; 
    int command=0; 
    char COMM_PORTNAME[13]; 
    strcpy(COMM_PORTNAME, argv[1]);// give the first port number for GPS receiving 
    if((fd = init_comm_channel(COMM_PORTNAME)) < 0) 
    { 
     exit(EXIT_FAILURE); 
     printf("port is not opened\n"); 
    } 
    else 
    { 

    printf("port is open for communication:\n"); 
    readb = frame_read(fd); 
    for (i=0;i<=34;i++) 
     { 
      data[i] = *(readb +j); 
     printf("the data is %x\n",data[i]); 
     j++; 
    } 
    } 
    close (fd); 

}

爲SIZE是 的#define SIZE 64 和幀是 炭幀[64];

感謝您的反饋,我更新了代碼。

此外,更新幀圖片,我在終端以及與程序。可能它會清除更多。

Received the data from UART by program

minicom recived

+0

與您的問題無關,但在使用之前需要清除描述符集'rfds'。一個集合基本上是一個包含一個數組的結構,如果你沒有在集合上使用'FD_ZERO',你的第一件事就是數據將被初始化並且因此具有* indeterminate *值。 'time_val'也是同樣的問題,它必須被初始化爲你想要的超時時間。 –

+0

至於你的問題,你需要創建一個[最小化,完整和可驗證的例子](http://stackoverflow.com/help/mcve)並告訴我們。包括你如何調用這些函數和你使用的變量的定義。例如,什麼是「框架」?什麼是「尺寸」? –

+0

最後,通過串行通訊發送的數據是* streaming *。沒有固定的消息邊界或數據包。如果你需要,你需要自己實現它。這也意味着一次調用'read'我不會讀完整的消息(「frame」),或者它可能讀取多於一條消息(如果存在多個緩衝區)。您需要循環讀取,直到您收到至少一條消息,並且能夠在單個「讀取」調用中處理多個消息(並且最後一條消息可能是部分消息)。 –

回答

-1

嘗試用

memset(&tty_attributes,0,sizeof(tty_attributes)); 
    tty_attributes.c_iflag=0; 
    tty_attributes.c_oflag=0; 
    tty_attributes.c_cflag=CS8|CREAD|CLOCAL; 
    tty_attributes.c_lflag=0; 
    tty_attributes.c_cc[VMIN]=1; 
    tty_attributes.c_cc[VTIME]=5; 
+0

你應該解釋爲什麼,設置超時,代碼可以工作.... – LPs

+0

謝謝你的反饋。並且如果沒有解決,將在以上的@LPs示例之後嘗試:-) –

+0

-1用於暗示非POSIX代碼。請參閱[正確設置終端模式](http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_12.html#SEC237) 和[用於POSIX操作系統的串行編程指南](http: //www.cmrr.umn.edu/~strupp/serial.html) – sawdust

0

The Man

返回值

012展望

成功時返回讀取的字節數(零表示文件的末尾 ),文件位置按此數字前進。 如果這個數字小於要求的字節數 ,那麼它是 不是錯誤的;這可能發生,例如因爲較少的字節是 實際可用現在(也許是因爲我們接近於最終OF- 文件,或者是因爲我們是從管道讀取,或從終端),或 因爲閱讀()被一個信號中斷。另見注。

重點煤礦

所以,你不能指望一個整體框架可以通過一個單一的讀取進行檢索。 你應該直到收到循環中的所有字符預期,例如:

int total_rec = 0; 
char temp[SIZE]; 
while(total_rec < SIZE) 
{ 
    read_ret_val = read(fd, temp, SIZE); 
    if (read_ret_val != -1) 
    { 
     if ((total_rec + read_ret_val) >= SIZE) 
     { 
      read_ret_val = SIZE - total_rec; 
     } 
     memcpy(&frame[total_rec], temp, read_ret_val); 
     total_rec += read_ret_val; 
    } 
    else 
    { 
     perror("error reading serial line: "); 
    } 
} 
+0

: - 感謝您的反饋,所以我應該循環'讀'直到預期的字符被接收? –

+0

看看我的小例子。 – LPs

+0

是的,我會根據這個 –

0

大多數GPS模塊和一般設備的串行接口通過線發送你的數據線。爲此,您可以使用您明確禁用的規範模式。

典型模式,如manual

指出在規範模式:

輸入由線提供線。當輸入一行分隔符時(NL,EOL,EOL2;或EOF 開始行),輸入行可用。 除EOF的情況外,行分隔符包含在由read(2)返回的緩衝區中。

我張貼的代碼來設置串行接口的速度和奇偶校驗啓用經典模式:

int set_interface_attribs(int fd, int speed, int parity) 
{ 
    // setup based on stty < /dev/ttyACM0 (cfg.txt) output which 
    // worked for ABSniffer in pyserial implementation 
    // otherwise module responded only once for every two prompts 
    struct termios tty; 
    int rc; 
    memset(&tty, 0, sizeof tty); 
    if (tcgetattr(fd, &tty) != 0) 
    { 
    log_info("error from tcgetattr %s\r\n", strerror(errno)); 
    return -1; 
    } 

    rc = cfsetospeed(&tty, speed); 
    if (rc == - 1) return -1; 
    rc = cfsetispeed(&tty, speed); 
    if (rc == - 1) return -1; 

    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars 
    // disable IGNBRK for mismatched speed tests; otherwise receive break 
    // as \000 chars 
    tty.c_cc[VMIN] = 0; // read doesn't block 
    tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout 

    tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, 
    // enable reading 
    tty.c_cflag &= ~(PARENB | PARODD); // shut off parity 
    tty.c_cflag |= parity; 
    tty.c_cflag &= ~CSTOPB; 
    // tty.c_iflag |= ICRNL | BRKINT; //ICRNL 
    tty.c_iflag |= IGNCR; 
    tty.c_cflag &= ~CRTSCTS; 
    // tty.c_oflag |= OPOST | ONLCR; 
    // tty.c_iflag |= ISIG | ICANON | IEXTEN; 
    tty.c_lflag |= ISIG | IEXTEN | ICANON; 
    tty.c_lflag &= ~ECHO; 
    tty.c_cc[VEOF] = 0x0; 
    tty.c_cc[VEOL] = 0x0; 

    if (tcsetattr(fd, TCSANOW, &tty) != 0) 
    { 
    log_info("error from tcsetattr %s\r\n", strerror(errno)); 
    return -1; 
    } 
    return 0; 
} 

這裏是你如何使用它:

rc = set_interface_attribs(fd, B9600, 0); 

從現在的數據應該是可用線路按行。所有的錯誤和可能的返回值在read manual中解釋。假設沒有錯誤,讀取一些任意大小的緩衝區應返回EAGAIN(資源暫時不可用),返回代碼-1或字節到換行符'\ n'。

+0

規範模式不使用VMIN和VTIME。在tcgetattr()之前,memset()是多餘的。 – sawdust

+0

hi @sawdust: - 感謝您的回答。你能舉出一個示例代碼,以便我可以嘗試一下。 –

+0

hi @pbn: - thx for answer,我試過這段代碼。但它不起作用。另外,使用'tcflush(fd,TCOFLUSH);'來刷新prev會很好。值。再次感謝您的重播。 –

0

你原來的代碼有許多問題,它導致「獲得第16個字節只有」

  • 代碼(張貼)僅執行單一的read()系統調用(而不是不斷循環讀取設備中的數據)。

  • 輸入顯然是分隔與回車換行終止行ASCII文本,但你的程序使用非規範方式閱讀,而不是規範的模式。 @pbn的假設由minicom輸出確認。

  • 你的程序使用串行終端在非阻塞模式中,而不是阻塞模式,和求助於使用的select()usleep()函式調用等待數據的到來。

  • termios的初始化(除了不是符合POSIX)具有幾個錯誤,包括不當施加到CFLAG構件IFLAG符號,字符尺寸的位不與〜CSIZE清除,並且CREAD是不啓用。

  • 你的讀出程序不必要地刷新(即丟棄)所有接收到的,但的select()呼叫之前未讀取的數據到。

用於打開和配置串行終端(用於阻擋規範模式)修改後的程序:

#define BAUDRATE B9600 

int init_comm_channel(char *comport) 
{ 
    struct termios tty_attributes; 
    int fd; 

    fd = open(comport, O_RDWR | O_NOCTTY); 
    if (fd < 0) { 
     perror("open comport error.\n"); 
     return (-2); 
    } 
    if (tcgetattr(fd, &tty_attributes) == -1) { 
     perror("tcgetattr termios function error.\n"); 
     return (-3); 
    } 
    tty_attributes.c_cflag |= CLOCAL | CREAD; 
    tty_attributes.c_cflag &= ~CSIZE; 
    tty_attributes.c_cflag |= CS8;   /* 8-bit characters */ 
    tty_attributes.c_cflag &= ~PARENB;  /* no parity bit */ 
    tty_attributes.c_cflag &= ~CSTOPB;  /* only need 1 stop bit */ 
    tty_attributes.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ 

    tty_attributes.c_lflag |= ICANON | ISIG; /* canonical input */ 
    tty_attributes.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN); 

    tty_attributes.c_iflag &= ~INPCK; 
    tty_attributes.c_iflag |= IGNCR; 
    tty_attributes.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL); 
    tty_attributes.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */ 

    tty_attributes.c_oflag &= ~OPOST; 

    cfsetospeed(&tty_attributes, BAUDRATE);  //setting communication speed and other attributes 
    cfsetispeed(&tty_attributes, BAUDRATE); 
    tcflush(fd, TCIOFLUSH); 

    if (tcsetattr(fd, TCSANOW, &tty_attributes) < 0) { 
     perror("tcsetattr function error.\n"); 
     return (-4); 
    } 
    return fd; 
} 

用於讀取每系統調用的線訂正例程:

#define SIZE 64 
unsigned char frame[SIZE]; 

char *frame_read(int fd) 
{ 
    int read_ret_val; 

    if (fd < 0) { 
     printf("Before read over comm channel, channel must be initialize\n"); 
     exit (EXIT_FAILURE); 
    } 
    read_ret_val = read(fd, frame, SIZE - 1); 
    if (read_ret_val < 0) { 
     perror("read"); 
     exit (EXIT_FAILURE); 
    } 
    frame[read_ret_val] = 0; /* terminate string */ 
    return (frame); 
} 

訂正main()永久循環的例程:

int main(int argc, char *argv[]) 
{ 
    int fd; 
    char *readb; 
    char com_portname[13] = {0}; 

    if (argc > 1) 
     strcpy(com_portname, argv[1]); // give the first port number for GPS receiving 
    if ((fd = init_comm_channel(com_portname)) < 0) { 
     printf("port is not opened\n"); 
     exit (EXIT_FAILURE); 
    } 
    printf("port is open for communication:\n"); 
    do { 
     readb = frame_read(fd); 
     while (*readb > 0) 
      printf("the data is 0x%x\n", *readb++); 
     printf("The line is: %s", frame); 
    } while (1); /* loop for another line */ 
    close(fd); 
} 
+0

Hi @sawdust:謝謝你分享答案。我正在嘗試這個答案,並將分享結果。 +1在這裏回答:-)。 –

+0

嗨@sawdust: - 我知道你忙,我已經試過這段代碼。我很抱歉,因爲我得到的結果與終端收到的數據不同。 終端收到的數據是: - b5 62 01 07 5c 00 48 0b 8d 15 e0 07 0c 1d 04 19 30 37 61 00 00 00 dc 98 04 00 03 01 0b 05 a1 23 37 2e 5e 9d c7 07 08 31 0c 00 3f 81 0d 00 ad cd 00 00 3b aa 00 00 7b 01 00 00 e5 ff ff ff 23 00 00 00 7c 01 00 00 24 55 cd 00 01 0a 00 00 3a 81 84 00 06 01 00 e0 86 4c 22 00 00 00 02 00 00 00 00 80 28 1e b5 62. –

+0

但代碼輸出爲: - b5 62 50 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 69 c 0 0 fd a 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 與實際不同。你能建議編輯嗎? –