2013-08-07 21 views
31

私はFTDIを使用してUSBポート経由でデータを送受信しようとしているので、C/C++を使用してシリアル通信を処理する必要があります。私はのLinux(Ubuntu)で作業しています。Linux Cシリアルポート読み書き

基本的には、受信したコマンドを受信して​​いるデバイスに接続しています。私はそれらのコマンドを送信し、デバイスの応答を読み取る必要があります。両方のコマンドと応答はASCII文字です。

GtkTermを使ってすべてうまく動作しますが、Cプログラミングに切り替えると問題が発生します。

は、ここに私のコードです:

#include <stdio.h>  // standard input/output functions 
#include <stdlib.h> 
#include <string.h>  // string function definitions 
#include <unistd.h>  // UNIX standard function definitions 
#include <fcntl.h>  // File control definitions 
#include <errno.h>  // Error number definitions 
#include <termios.h> // POSIX terminal control definitions 

/* Open File Descriptor */ 
int USB = open("/dev/ttyUSB0", O_RDWR| O_NONBLOCK | O_NDELAY); 

/* Error Handling */ 
if (USB < 0) 
{ 
cout << "Error " << errno << " opening " << "/dev/ttyUSB0" << ": " << strerror (errno) << endl; 
} 

/* *** Configure Port *** */ 
struct termios tty; 
memset (&tty, 0, sizeof tty); 

/* Error Handling */ 
if (tcgetattr (USB, &tty) != 0) 
{ 
cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << endl; 
} 

/* Set Baud Rate */ 
cfsetospeed (&tty, B9600); 
cfsetispeed (&tty, B9600); 

/* Setting other Port Stuff */ 
tty.c_cflag  &= ~PARENB;  // Make 8n1 
tty.c_cflag  &= ~CSTOPB; 
tty.c_cflag  &= ~CSIZE; 
tty.c_cflag  |= CS8; 
tty.c_cflag  &= ~CRTSCTS;  // no flow control 
tty.c_lflag  = 0;   // no signaling chars, no echo, no canonical processing 
tty.c_oflag  = 0;     // no remapping, no delays 
tty.c_cc[VMIN]  = 0;     // read doesn't block 
tty.c_cc[VTIME]  = 5;     // 0.5 seconds read timeout 

tty.c_cflag  |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines 
tty.c_iflag  &= ~(IXON | IXOFF | IXANY);// turn off s/w flow ctrl 
tty.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw 
tty.c_oflag  &= ~OPOST;    // make raw 

/* Flush Port, then applies attributes */ 
tcflush(USB, TCIFLUSH); 

if (tcsetattr (USB, TCSANOW, &tty) != 0) 
{ 
cout << "Error " << errno << " from tcsetattr" << endl; 
} 

/* *** WRITE *** */ 

unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'}; 
int n_written = write(USB, cmd, sizeof(cmd) -1); 

/* Allocate memory for read buffer */ 
char buf [256]; 
memset (&buf, '\0', sizeof buf); 

/* *** READ *** */ 
int n = read(USB, &buf , sizeof buf); 

/* Error Handling */ 
if (n < 0) 
{ 
    cout << "Error reading: " << strerror(errno) << endl; 
} 

/* Print what I read... */ 
cout << "Read: " << buf << endl; 

close(USB); 

何が起こるかというとread()戻り0(バイトが全く読まない)、またはブロックタイムアウト(VTIME)までということです。 write()は何も送信しないので、私はこれが起こっていると仮定しています。その場合、デバイスはコマンドを受信せず、応答を受け取ることができません。実際には、私のプログラムが読書でブロックされている間にデバイスをオフにすると、実際に応答が得られます(デバイスはシャットダウン中に何かを送信します)。

奇妙なことは、右write()呼び出した後、この

cout << "I've written: " << n_written << "bytes" << endl; 

を追加していることを、私が受け取る:

I've written 6 bytes 

私が期待して正確に何です。 のように私のプログラムだけが動作しません。実際に私のデバイスはポートにを書き込むことができません。

私は異なるタイプのデータ型についても試しましたが(実際には何もしませんでしたが、cmd = "INIT \r"const charなどのstd :: stringを使ってみました)

誰かが私が間違っている場所を教えてもらえますか?

ありがとうございます。

EDIT:このコードの 以前バージョン

unsigned char cmd[] = "INIT \n"

またcmd[] = "INIT \r\n"を用います。デバイスのコマンドシンタクスが

<command><SPACE><CR>と報告されたため、私はそれを変更しました。

私はまた、読んでO_NONBLOCKフラグを避けようとしましたが、私は永遠にしかブロックしません。私はselect()を使ってみましたが、何も起こりません。試してみると、データが利用可能になるまで待機ループを作成しましたが、コードがループを終了することはありません。 Btw、またはusleep()が私が避ける必要があるものです。報告されたのは自分のコードの抜粋だけです。 完全なコードはリアルタイム環境(特にOROCOS)で動作する必要がありますので、私は本当にスリープのような機能を望んでいません。

答えて

54

私は自分の問題を解決したので、誰かが同様のものを必要とする場合は、正しいコードを投稿します。

オープンポート

int USB = open("/dev/ttyUSB0", O_RDWR| O_NOCTTY); 

設定パラメータ

struct termios tty; 
struct termios tty_old; 
memset (&tty, 0, sizeof tty); 

/* Error Handling */ 
if (tcgetattr (USB, &tty) != 0) { 
    std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl; 
} 

/* Save old tty parameters */ 
tty_old = tty; 

/* Set Baud Rate */ 
cfsetospeed (&tty, (speed_t)B9600); 
cfsetispeed (&tty, (speed_t)B9600); 

/* Setting other Port Stuff */ 
tty.c_cflag  &= ~PARENB;   // Make 8n1 
tty.c_cflag  &= ~CSTOPB; 
tty.c_cflag  &= ~CSIZE; 
tty.c_cflag  |= CS8; 

tty.c_cflag  &= ~CRTSCTS;   // no flow control 
tty.c_cc[VMIN] = 1;     // read doesn't block 
tty.c_cc[VTIME] = 5;     // 0.5 seconds read timeout 
tty.c_cflag  |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines 

/* Make raw */ 
cfmakeraw(&tty); 

/* Flush Port, then applies attributes */ 
tcflush(USB, TCIFLUSH); 
if (tcsetattr (USB, TCSANOW, &tty) != 0) { 
    std::cout << "Error " << errno << " from tcsetattr" << std::endl; 
} 

それは間違いではなかった

unsigned char cmd[] = "INIT \r"; 
int n_written = 0, 
    spot = 0; 

do { 
    n_written = write(USB, &cmd[spot], 1); 
    spot += n_written; 
} while (cmd[spot-1] != '\r' && n_written > 0); 

を書きます1バイトあたりのバイト数を書き込むために必要です。int n_written = write(USB, cmd, sizeof(cmd) -1)も正常に動作しました。最後に

をお読みください。

int n = 0, 
    spot = 0; 
char buf = '\0'; 

/* Whole response*/ 
char response[1024]; 
memset(response, '\0', sizeof response); 

do { 
    n = read(USB, &buf, 1); 
    sprintf(&response[spot], "%c", buf); 
    spot += n; 
} while(buf != '\r' && n > 0); 

if (n < 0) { 
    std::cout << "Error reading: " << strerror(errno) << std::endl; 
} 
else if (n == 0) { 
    std::cout << "Read nothing!" << std::endl; 
} 
else { 
    std::cout << "Response: " << response << std::endl; 
} 

この1つは私のために働きました。皆さん、ありがとうございました!

+0

あなたの行 'response.append(&buf);'は私のためにはコンパイルされません) 'while(buf!= '\ r' && n> 0);'これらのタイプミスや何か不足していますか? – josaphatv

+0

'int n_written = write(USB、cmd、sizeof(cmd)-1)'を送信することは大容量のバッファではうまくいきません。その場合、上記のようなループが必要ですが、 'n_written – Fritz

+0

'cfmakeraw()'はすでにたくさんの属性を設定していますが、あなたはループを終了させるために長さを使用する必要があります。これらの行は必要ありません: 'tty.c_cflag&=〜CSIZE; tty.c_cflag | = CS8; tty.c_cflag&=〜PARENB;' – rumpel

0

いくつかの受信機は、通常の2つの文字\r\nあるEOLシーケンスを、期待し、そうところで、上記の方法は、おそらく、より効率的である

unsigned char cmd[] = "INIT\r\n"; 

でライン

unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'}; 

を置き換えるあなたのコードにしてみてください。すべての文字を引用する必要はありません。

+0

また、一部のUSBドライブには高速書き込みキャッシュがあります。つまり、実際に正しく書き込まれる前にバッファに格納されていますか? – Magn3s1um

+0

チップをありがとうございますが、 '\ r \ n'は私の問題ではありません。私はそれを試したことがあります。他のアイデア? – Lunatic999

+0

@ Lunatic999私はあなたのコードをもう一度読み、 'int n_written = write(USB、cmd、sizeof(cmd)-1);という行を読んだだけです。 'int n_written = write(USB、cmd、strlen(cmd));'を使ってテストしても構わないでしょうか?これは私が働いているプログラムで、あなたのような非常によく似た設定、ttyUSBによる通信にあります。 – radarhead

0

1)initの後に/ nを追加します。すなわち、書き込み(USB、 "init \ n"、5);

2)シリアルポートの設定を再度確認してください。オッズは何かが間違っています。^Q/^ Sを使用しない、またはハードウェアのフロー制御が他の側がそれを期待しているわけではないという理由だけではありません。

3)ほとんどの場合:「はusleep(100000)を追加します。書き込み後を()ファイル・ディスクリプタは右どのくらい時間がかかり、ブロックまたは待機しない設定されています。?あなたはread() read()それを読むことができる前に応答を取得する前に応答を得るためには?を使用することを検討しましたを待つ何かのためにread()?たぶんタイムアウト?

編集先:

DTR/RTSラインが必要ですか?相手側にコンピュータデータを送信するよう指示するハードウェアフロー制御?例えば

int tmp, serialLines; 

cout << "Dropping Reading DTR and RTS\n"; 
ioctl (readFd, TIOCMGET, & serialLines); 
serialLines &= ~TIOCM_DTR; 
serialLines &= ~TIOCM_RTS; 
ioctl (readFd, TIOCMSET, & serialLines); 
usleep(100000); 
ioctl (readFd, TIOCMGET, & tmp); 
cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl; 
sleep (2); 

cout << "Setting Reading DTR and RTS\n"; 
serialLines |= TIOCM_DTR; 
serialLines |= TIOCM_RTS; 
ioctl (readFd, TIOCMSET, & serialLines); 
ioctl (readFd, TIOCMGET, & tmp); 
cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl; 
+0

ありがとうございました! 私はあなたの提案を試みましたが、何も変わりませんでした。私はより多くの情報で私の質問を編集しました...他のアイデア?もう一度ありがとうございます – Lunatic999

+0

usleep()はデバッグ/テスト用です。動作したらselect()に切り替えて、応答に必要な時間だけ待つことができます。 – guest

+0

どのように7バイトを書きましたか?それは "INIT \ r"の6バイトです...あなたは末尾のNULL文字を書いていますか?いくつかのシステムは、通信の終わりとしてNULL文字を解釈します... – guest

関連する問題