2013-03-28 33 views
6

私のtermios設定は、read()を使用してシリアルポートから読み取った最初の文字を変更しています。私は、Linuxのボックスに話しているマイクロコントローラがあります。マイクロコントローラは、Linuxマシンから送信されたコマンドに応答します。次のようにセットアップは次のとおりです。シリアルポート読み込み後に最初の文字を変更するLinux termios

  • マイクロコントローラ(PIC24F)RS485ポート< - > UbuntuのPC - USBコンバータ<へ> RS485。

私がCutecomなどの端末プログラムを実行すると、すべてが計画どおりに動作します。私はPICにコマンドキャラクターを送りますが、私はコマンドラインプログラムを使うと最初のキャラクターが修正されていますが、応答があります。ここに私のコードです:

#include <string.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <termios.h> 

#define DEVICE "/dev/ttyUSB0" 
#define SPEED B38400 

int main() 
{ 
    struct termios tio; //to hold serial port settings 
    struct termios stdio; //so we can accept user input 
    struct termios old_stdio; //save the current port settings 
    int tty_fd; //file descriptor for serial port 
    int res, n, res2, read1, wri; 
    char buf[255]; 
    char buf2[255]; 

    //save the current port settings 
    tcgetattr(STDOUT_FILENO,&old_stdio); 

    //setup serial port settings 
    bzero(&tio, sizeof(tio)); 
    tio.c_iflag = 0; 
    tio.c_iflag = IGNPAR | IGNBRK | IXOFF; 
    tio.c_oflag = 0; 
    tio.c_cflag = CS8 | CREAD | CLOCAL; //8n1 see termios.h 
    tio.c_lflag = ICANON; 

    //open the serial port 
    tty_fd=open(DEVICE, O_RDWR | O_NOCTTY); 

    //set the serial port speed to SPEED 
    cfsetospeed(&tio,SPEED); 

    //apply to the serial port the settings made above 
    tcsetattr(tty_fd,TCSANOW,&tio); 

    for(n = 5; n > 0; n--) 
    { 
    printf("Please enter a command: "); 
    (void)fgets(buf2, 255, stdin); 
    (void)write(tty_fd, buf2, strlen(buf2));     
    printf("Ok. Waiting for reply."); 
    res = read(tty_fd, buf, 255);  
    printf("Read:%d START%d %d %d %d %dFINISH\n",res,buf[0],buf[1],buf[2],buf[3], 
    buf[4]);    
    } 

    //close the serial port 
    close(tty_fd); 

    //restore the original port settings 
    tcsetattr(STDOUT_FILENO,TCSANOW,&old_stdio); 

    return EXIT_SUCCESS; 
} 

ここに私が得ている結果の例です。

  • PICは "00000 \をn" は送信出力は次のとおりです。PICは "23456 \をn" は送信出力されると6 START-16 48 48 48 48FINISH
  • :読む:6 [スタート] - 読みます51 52 53 54FINISH
  • PICは送信14 "34567 \ n" は出力され:読む6 START-14 52 53 54 55FINISH
  • PIC "は45678は、n \" が出力される送信:読む:6 START-12 53 54 55 56FINISH
  • PICが「56789 \ n」を送信すると、出力は次のようになります。読み取り:6 START-12 54 55 56 57FINISH

何らかの理由で、最初の文字がいくつかのtermios設定によって混乱しています。 Cutexを実行すると、上記のテスト入力が正確に返されるので、termios設定でなければなりません。マニュアルページを何度も読んで、入力コントロールのすべての設定を試してみましたが、私が何をしてもこの問題を揺さぶってはいけません。

簡単な修正のために、データを1文字にシフトすることはできますが、これを避けたいと考えています。

誰もこのような問題を経験したことがありますか、それについて何か考えていますか?

多くのありがとうございます。

28/3/13 オースティン。

  • まず私のプログラム

    スピード38400ボーでのtermios設定がされています。:ここに興味がある人のために2つの出力があります行0;列0;ライン= 0; intr =;終了する。消去=;殺す=; eof =; eol =; eol2 =; swtch =;開始=;ストップ=; susp =; rprnt =; werase =; lnext =; flush =; min = 0;時間= 0; -parenb -parodd CS8 -hupcl -cstopb CREAD CLOCAL -crtscts IGNBRK -brkint IGNPAR -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon IXOFF -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel NL0 CR0 TAB0のBS0 VT0 FF0 -isig ICANON -iexten -echo -echoe -echok -echonl -noflsh -Xcase -tostop -echoprt -echoctl -echoke

  • そして、 cutecomが使用する設定

    速度38400ボー;行0;列0;ライン= 0; intr =^C; quit =^\;消去= ^?;殺す=^U; eof =^D; eol =; eol2 =; swtch =; start =^Q;ストップ=^S; susp =^Z; rprnt =^R; werase =^W; lnext =^V; flush =^O; min = 60;時間= 1; -parenb -parodd CS8 HUPCL -cstopb CREAD CLOCAL -crtscts IGNBRK -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc - ocrnl -onlcr -onocr -onlret -ofill -ofdel NL0 CR0 TAB0のBS0 VT0 FF0 -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -Xcase -tostop -echoprt -echoctl -echoke

私はまだすべてを進めており、進歩すると投稿を更新します。

29/3/13 まだ同じ問題があります。私はCutecomのソースコードを見つけて、彼らが使用するtermios設定に従っていました。それでも問題は存在します。その最初の文字が壊れている!!!!

  • 私のプログラムのTermios設定は以下の通りです。何らかの理由でフラッシュすることができません。

    速度38400ボー;行0;列0;ライン= 0; intr = ^?; quit =^\;消去=^H;殺す=^U; eof =^D; eol =; eol2 =; swtch =; start =^Q;ストップ=^S; susp =^Z; rprnt =^R; werase =^W; lnext =^V;フラッシュ=; min = 60;時間= 1; -parenb -parodd CS8 HUPCL -cstopb CREAD CLOCAL -crtscts IGNBRK -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc - ocrnl -onlcr -onocr -onlret -ofill -ofdel NL0 CR0 TAB0のBS0 VT0 FF0 -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -Xcase -tostop -echoprt -echoctl -echoke

  • そして、私の新しいコード:

    #include <stdlib.h> 
    #include <stdio.h> 
    #include <unistd.h> 
    #include <fcntl.h> 
    #include <termios.h> 
    #include <sys/ioctl.h> 
    
    #define DEVICE "/dev/ttyUSB0" 
    #define SPEED B38400 
    
    int main() 
    { 
    struct termios tio; //to hold serial port settings 
    struct termios stdio; //so we can accept user input 
        struct termios old_stdio; //save the current port settings 
        int tty_fd; //file descriptor for serial port 
        int retval, res, n, res2, read1, wri; 
        char buf[255]; 
        char buf2[255]; 
    
    
        tty_fd = open(DEVICE, O_RDWR | O_NDELAY); 
        if(tty_fd < 0) 
        { 
         perror(DEVICE); 
         exit(-1); 
        } 
        printf("Init 1 complete.\n"); 
    
        tcflush(tty_fd, TCIOFLUSH); 
    
        int f = fcntl(tty_fd, F_GETFL, 0); 
        fcntl(tty_fd, F_SETFL, f & ~O_NDELAY); 
    
        retval = tcgetattr(tty_fd, &old_stdio); 
        if(retval != 0) 
        { 
         perror(DEVICE); 
         exit(-1); 
        } 
        printf("Init 2 complete.\n"); 
    
        struct termios newtio; 
        retval = tcgetattr(tty_fd, &newtio); 
        if(retval != 0) 
        { 
         perror(DEVICE); 
         exit(-1); 
        } 
        printf("Init 3 complete.\n"); 
    
        cfsetospeed(&newtio, SPEED); 
        cfsetispeed(&newtio, SPEED); 
    
        newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS8; 
        newtio.c_cflag |= CLOCAL | CREAD; 
        newtio.c_cflag &= ~(PARENB | PARODD); 
        newtio.c_cflag &= ~CRTSCTS; 
        newtio.c_cflag &= ~CSTOPB; 
    
        newtio.c_iflag = IGNBRK; 
        newtio.c_iflag &= ~(IXON | IXOFF | IXANY); 
    
        newtio.c_lflag = 0; 
    
        newtio.c_oflag = 0; 
    
        newtio.c_cc[VTIME] = 1; 
        newtio.c_cc[VMIN] = 60; 
        newtio.c_cc[VINTR] = 127; 
        newtio.c_cc[VQUIT] = 28; 
        newtio.c_cc[VERASE] = 8; 
        newtio.c_cc[VKILL] = 21; 
        newtio.c_cc[VEOF] = 4; 
        newtio.c_cc[VSTOP] = 19; 
        newtio.c_cc[VSTART] = 17; 
        newtio.c_cc[VSUSP] = 26; 
        newtio.c_cc[VREPRINT] = 18; 
        newtio.c_cc[VFLSH] = 15; 
        newtio.c_cc[VWERASE] = 23; 
        newtio.c_cc[VLNEXT] = 22; 
    
    
        retval = tcsetattr(tty_fd, TCSANOW, &newtio); 
        if(retval != 0) 
        { 
         perror(DEVICE); 
         exit(-1); 
        } 
        printf("Init 4 complete.\n"); 
    
        int mcs = 0; 
        ioctl(tty_fd, TIOCMGET, &mcs); 
        mcs |= TIOCM_RTS; 
        ioctl(tty_fd, TIOCMSET, &mcs); 
    
        retval = tcgetattr(tty_fd, &newtio); 
        if(retval != 0) 
        { 
         perror(DEVICE); 
         exit(-1); 
        } 
        printf("Init 5 complete.\n"); 
    
        newtio.c_cflag &= ~CRTSCTS; 
    
        retval = tcsetattr(tty_fd, TCSANOW, &newtio); 
        if(retval != 0) 
        { 
         perror(DEVICE); 
         exit(-1); 
        } 
        printf("Init 6 complete.\n"); 
    
    
        for(n = 5; n > 0; n--) 
        { 
        printf("Please enter a command: "); 
        (void)fgets(buf2, 255, stdin); 
        (void)write(tty_fd, buf2, strlen(buf2)); 
        printf("Ok. Waiting for reply\n"); 
        res = read(tty_fd, buf, 255);  
        printf("Read:%d START%d %d %d %d %dFINISH\n",res,buf[0],buf[1],buf[2], buf[3], 
        buf[4]);    
        } 
    
        //restore the original port settings 
        tcsetattr(tty_fd, TCSANOW, &old_stdio); 
    
        close(tty_fd); 
    
        return EXIT_SUCCESS; //return all good 
    } 
    

I私は何ができるのか、どこから取り除かなければならないのか全く分かりません。

+0

読み込みで6が読み込まれたと表示されたときに最初の5バイトだけを報告する理由はありますか? RS-482とUSBの組み合わせを介して送信されるものを監視して、マイクロコントローラが実際にあなたが期待するバイトを送信しているかどうか、または情報が変更されているかどうかを調べる手段がありますか?私はRS-482で作業していませんでした(ただし、私はRS-232を覚えています)。しかし、制御文字やメッセージフレーミングがありますか?読んだ最初のバイトが 'expected&0xEE'によって修正されたようです... –

+0

こんにちはジョナサン、私は6番目のバイトを報告していない理由は、\ nです。 termiosに標準モードを使用しているので、読み込みは\ nになると戻ります。同じLinuxマシンで動作しているCutecomを使用してセットアップを正常に実行できなかった場合、私はtermiosの反対側を見ています。私は仮定が危険であることを知っていますが、この状況では私のPIC、485-to-USBコンバータはCutecom内部で動作するので正常に動作していると考えることは安全だと思います。あなたはどこから来ているのかわからないので、 "expected&0xEE"について詳しく説明してください。よろしく。 –

+0

私が一貫して実行した他のテストでは、最初の文字から64が減算されていました。 read()がbuf [0]に格納される結果に64を追加すると、正しいASCII値が得られます。これに関する混乱していたことは、正しい値のASCII値が6番目のビットが設定されていないことでした。だから、どこかで&0x1011111が実行されたと思っても、そのアイデアはサポートされませんでした。私は値についていくつかの操作を試みましたが、どんな種類のパターンも識別できませんでした。 –

答えて

2

コードのクイックスキャンで明らかに間違ったことはありません。 8ビットの値で作業する予定がある場合は、unsigned char buf[]に移動することを検討してください。

Cutecomで動作するプログラムがあるので、自分のプログラムをデバッグするためのリファレンスとしてtermios設定を使用できます。

Cutecomが/dev/ttyUSB0上で実行されていることで、ttyの設定をダンプするために、別の端末で次のコマンドを実行します。

stty -a -F /dev/ttyUSB0 

は、あなたのプログラムを実行するときに同じことを行うと、二つの構成との違いを探してください。 Cutecomで報告されたものと正確に一致するように、プログラムの端末設定を設定してみてください。

アップデート:ここで、問題を解決しようとするいくつかのより詳細なものであるしていない

のtermiosの設定を固定しているため。どこかにタイミングの問題があると私は思います。 Cutecomコンソールで入力すると、一度に1文字ずつデバイス間にミリ秒単位で送信します。プログラムを使用するときは、コマンドを入力した後で、ドライバが許す限り速やかに文字を送信して、文字の完全なバッファを送信します。 PICプログラムがデータストリームのタイミングを処理できないか、または1つの代わりに2つのストップビットが必要になり、結果的に奇妙なリターンコードが発生する可能性があります。

おそらく、始めるのに最適な場所は元に戻っています。オシロスコープまたはロジックアナライザを取得し、PICによって送信されているデータが実際に正しいことを確認します。ビットレベルの波形を理解して、スタートビットとストップビットを考慮する必要があります。 Cutecomとプログラムの両方の波形を比較します。ロジックアナライザを使用している場合は、使用するクロックがボーレートのいくつかの高い倍数であることを確認してください。例えば32乗算器である。

デバッグのもう1つの方法は、straceを使用して、ドライバによって返された文字が実際には間違っていることを確認し、それがプログラムに問題ではないことを確認することです。 straceを使うと、あなたのプログラムの未処理の読み込み/書き込みと、カーネルが返すものを見ることができます。プログラム実行中にすべてのシステムコールをダンプするには、strace -o ~/tmp/strace_output.txt -ttt -xx your_programを使用してください。場合によっては、プログラムをストレインするプロセスによって、タイミングエラーを表示するのに十分な時間がかかることがあります。読み書きのタイミングをCutecomのstraceと比較することができます。テストのためだけに文字列を送信するが、各文字間に少量の遅延を与える独自のwrite()関数を追加することができます。

+0

これは、2つの設定を比較するのには良い出発点でしたが、私のコードをまだ変更できない設定に変更しました。 –

+0

@MitchGulliver更新プログラムをお寄せいただきありがとうございます。デバッグに役立つ情報をいくつか追加して私の答えを更新しました。 –

+0

オースティンフィリップスに感謝します。私はいくつかのユニ・ワークを完成させる必要がありますが、私はこのプロジェクトをやり直すときに私はあなたの提案を試みます。スコープを購入する時間もあるかもしれません。私が進歩すると、私は自分の投稿を更新するでしょう。 –

0

私はそれを最後に試しました。これはそれを修正したものです:

  • (void)write(tty_fd、buf2、1);

問題は修正されていますが、それが何をしていたのかは100%確実ではありません。問題は私のプログラムが\ nをマイクロコントローラの書き込みに追加することでした。私がCutecomと私のプログラムの両方でstraceをやったとき、私はCutecomが "1"と書いているのに対し、私のプログラムは "1 \ n"と書いています。私はCutecomを使用して文字を送信するときに、ユーザープロンプトで例1を入力してEnterキーを押すので、十分に考えなかった。 PIC側では、私のプログラムは次のようになります:

while(1) 
{ 
    WATCHDOG(); 

    if(flag == 1) 
    { 
     char *start = str2; 
     RS485_TXEN1(); 
     indicator = UART1_getch(); //get character sent from PC 
     switch(indicator) 
     { 
      case '1' :      
        UART1_putstr("00000\n"); 
        DAC_Write(DAC_CH_2, 4095); 
        break; 
      case '2' :      
        UART1_putstr("23456\n"); 
        DAC_Write(DAC_CH_2, 0); 
        break; 
      case '3' : 
        UART1_putstr("34567\n"); 
        break; 
      case '4' :      
        UART1_putstr("45678\n"); 
        break; 
      case '\n' : 
        UART1_putch('\n'); 
        break; 
      default :   
        UART1_putstr("56789\n");     
        break; 
     } 
     RS485_RXEN1(); 
     flag = 0; 
    } 
} 

文字がUART RXに到着すると、割り込みが生成されます。この割り込みサービスルーチンで "flag"を設定し、main()で受信したコマンドを処理します。最初の文字がどのように変更されているかはわかりませんが、 "case '\ n':のためにいくつかの上書きまたは書き込み割り込みが発生したようです。"

最後に単純な修正が加えられ、Linuxシステムとデバッグの作業の貴重な教訓もありました。提案をした皆様に感謝します。 Linuxボックスとマイクロコントローラのインタフェースを開始したい人には、上記のコードが役に立つでしょう。

関連する問題