2016-09-14 238 views
2

下午好,傳輸二進制數據通過ttyACM

我有一個外圍設備,通過虛擬串行端口通過USB通信。一切正常基於Windows操作系統的通用串行ACM驅動程序,例如使用:https://www.kernel.org/doc/Documentation/usb/linux-cdc-acm.inf

在Linux下,它使用CDC ACM驅動程序。系統日誌中的所有內容似乎都可以正常工作,但通信卻表現得很奇怪。當我連接設備時,通信開始時約10個字節丟失。接下來,每個第二個命令都會收到。

我的問題是: 1)本設備的通信協議不使用ASCII,它是二進制的(它可以隨機包含控制字符等)。我應該使用stty來配置速度,數據位,停止位和奇偶校驗等,還是需要爲二進制通信設置更多的東西? (要忽略內核中的控制位並傳輸每個字節 - 原始數據。)

2)任何想法,如何測試linux ACM驅動程序是否正常工作,或者我應該爲我的CDC ACM設備嘗試哪些其他驅動程序?

感謝您的任何想法!當您嘗試通過串行端口,這可能會導致問題,如果他們實際上是二進制數據,不作爲行結束符給他們

+0

你只需要確保*的termios * **(一)**正確配置了非規範(又名*生*)模式,和**(B)**有軟件流量控制禁用。你根本不詳細;你用什麼軟件來執行這個數據傳輸?爲什麼它沒有正確配置端口? – sawdust

+1

'stty -F/dev/ttyACM0 raw'可能會起作用(如果傳輸程序不是在配置這些屬性)。請注意'raw'參數之前沒有連字符。這是一個參數設置而不是開關。如果你輸入'-raw',那麼你會否定這個命令的目的。 – sawdust

+0

我沒有任何軟件,我使用echo -ne「\ XXY」到/ dev/ttyACMx的寫字節和貓的/ dev/ttyACM記錄從端口讀取文件。爲了查看收到的數據,我通過xxd打開我的日誌文件。設置由stty完成。 我認爲原始參數可能是解決方案,謝謝! – JirkaRCK

回答

0

Linux會經常裂傷之類的行結束符字符(0x0A和0X0D)。

這裏是一個片段from Pololu,顯示如何正確地配置您的串行端口,然後發送和接收幾個字節。特別注意調用tcsetattr的部分。

#include <fcntl.h> 
#include <stdio.h> 
#include <unistd.h> 

#ifdef _WIN32 
#define O_NOCTTY 0 
#else 
#include <termios.h> 
#endif 

// Gets the position of a Maestro channel. 
// See the "Serial Servo Commands" section of the user's guide. 
int maestroGetPosition(int fd, unsigned char channel) 
{ 
    unsigned char command[] = {0x90, channel}; 
    if(write(fd, command, sizeof(command)) == -1) 
    { 
    perror("error writing"); 
    return -1; 
    } 

    unsigned char response[2]; 
    if(read(fd,response,2) != 2) 
    { 
    perror("error reading"); 
    return -1; 
    } 

    return response[0] + 256*response[1]; 
} 

// Sets the target of a Maestro channel. 
// See the "Serial Servo Commands" section of the user's guide. 
// The units of 'target' are quarter-microseconds. 
int maestroSetTarget(int fd, unsigned char channel, unsigned short target) 
{ 
    unsigned char command[] = {0x84, channel, target & 0x7F, target >> 7 & 0x7F}; 
    if (write(fd, command, sizeof(command)) == -1) 
    { 
    perror("error writing"); 
    return -1; 
    } 
    return 0; 
} 

int main() 
{ 
    const char * device = "/dev/ttyACM0"; // Linux 
    int fd = open(device, O_RDWR | O_NOCTTY); 
    if (fd == -1) 
    { 
    perror(device); 
    return 1; 
    } 

#ifdef _WIN32 
    _setmode(fd, _O_BINARY); 
#else 
    struct termios options; 
    tcgetattr(fd, &options); 
    options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF); 
    options.c_oflag &= ~(ONLCR | OCRNL); 
    options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 
    tcsetattr(fd, TCSANOW, &options); 
#endif 

    int position = maestroGetPosition(fd, 0); 
    printf("Current position is %d.\n", position); 

    int target = (position < 6000) ? 7000 : 5000; 
    printf("Setting target to %d (%d us).\n", target, target/4); 
    maestroSetTarget(fd, 0, target); 

    close(fd); 
    return 0; 
} 

您可能可以使用stty命令行實用程序做同樣的事情。