質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.03%

c言語を用いたRS232C通信が停止してしまいます

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 6,490

score 7

c言語を用いてRS232C通信を行うプログラムが安定動作しません。
オシロスコープからの電圧値をpcに取り込むプログラムが必要となり,作成しています。現在,一応のところ送受信が出来ており,希望とする機能は実現できているのですが,しばらくプログラムを動作させていると,以下のような問題が発生します。

・数千件程度データを受信したところでプログラムが完全に応答しなくなる(ウインドウも閉じない,通信用ケーブルを物理的に外すとプログラムの停止は出来ます。)
・プログラム動作中に突然ブルースクリーンになる(エラーメッセージはまだ確認できていません)


使用している環境は以下のとおりです。

OS : win7 32bit
コンパイラ : Borland C++ Compiler 5.5
使用ケーブル : UC-SGT

ソースコードはいかに添付します。
私自身プログラミングには疎く,問題の原因がソフトなのか,ハードなのか検討も付いていない状態です。何かこれらの問題の原因について,気づいた事が有りましたら教えていただけると幸いです。

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <process.h>
#include <string.h> 

HANDLE h;

//クリップボードへのデータ受け渡し関数
void wclip(char a[]){
    HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, 256);
    strcpy((LPTSTR)hMem, a);
    OpenClipboard(NULL);
    EmptyClipboard();
    SetClipboardData(CF_TEXT, hMem);
    CloseClipboard();
}

//データ送信用スレッド
void sub( void *dummy ) {

    unsigned long nn;

    char ch1[22]=":MEAS:SOUR1 CH1\n";
    char ch2[22]=":MEAS:SOUR1 CH2\n";
    char ave[16]=":MEAS:MEAN?\n";
    int DataSize;
    COMSTAT Comstat; // 通信デバイス情報構造体
    DWORD dwErrorMask; // エラーコードを受け取る変数

    while( 1 ){

        DataSize = strlen( ch1 ); //データのサイズ取得
        do{
            ClearCommError( h , &dwErrorMask , &Comstat ); 
        }while( (128 - Comstat.cbOutQue)  <= DataSize );

        WriteFile( h, ch2, 22, &nn, 0);

        do{
            ClearCommError( h , &dwErrorMask , &Comstat ); 
        }while( (128 - Comstat.cbOutQue)  <= DataSize );

        WriteFile( h, ave, 16, &nn, 0);

        do{
            ClearCommError( h , &dwErrorMask , &Comstat ); 
        }while( (128 - Comstat.cbOutQue)  <= DataSize );

        WriteFile( h, ch1, 22, &nn, 0);

        do{
            ClearCommError( h , &dwErrorMask , &Comstat ); 
        }while( (128 - Comstat.cbOutQue)  <= DataSize );

        WriteFile( h, ave, 16, &nn, 0);
    }
}

//メイン文
void main() {
    int i=0;
    int j;
    int ret,count=0,DataSize;
    double voltage;
    char sBuf[1];
    char test[7]= "*idn?\n";
    

    char str[100];
    char out[100],output[100];
    unsigned long nn;
    DCB dcb;
    COMMTIMEOUTS cto;
    unsigned long dummy;

    clock_t now;

    /* ----------------------------------------------
        ファイルのクリエイト/オープン
    ---------------------------------------------- */
    // クリエイトしたファイルのファイルハンドラを返す
    h = CreateFile( "COM3", 
                            GENERIC_READ | GENERIC_WRITE,
                            0,
                            0,
                            OPEN_EXISTING,
                            0,
                            0 ); 
    if ( h == INVALID_HANDLE_VALUE ) {
        printf("Open Error of COM3 Port\n");
    }

    /* ----------------------------------------------
        シリアルポートの状態操作
    ---------------------------------------------- */
    GetCommState( h, &dcb );                         // シリアルポートの状態を取得
    
    dcb.BaudRate    = 115200;                         // 速度
    dcb.ByteSize    = 8;                             // データ長
    dcb.Parity         = NOPARITY;                        // パリティ(Even)
    dcb.StopBits    = 1;                             // ストップビット長
    
    SetCommState( h, &dcb );                         // シリアルポートの状態を設定

    /* ----------------------------------------------
        シリアルポートのタイムアウト状態操作
    ---------------------------------------------- */
    GetCommTimeouts( h, &cto );                     // タイムアウトの設定状態を取得
    cto.ReadIntervalTimeout            = 35;
    cto.ReadTotalTimeoutMultiplier    = 0;            // 1Byte毎のタイマ
    cto.ReadTotalTimeoutConstant    = 35;            // 1関数コール毎のタイマ
    cto.WriteTotalTimeoutMultiplier    = 0;            // 1Byte毎のタイマ
    cto.WriteTotalTimeoutConstant    = 0;            // 1関数コール毎のタイマ
    SetCommTimeouts( h, &cto );                     // タイムアウトの状態を設定


    // スレッド作成と起動
    _beginthread( sub, 0, &dummy );
    now = clock();


    /* ----------------------------------------------
        受信データの読み出し(1行分の文字列)
    ---------------------------------------------- */
    while(1) {

        ReadFile( h, sBuf, 1, &nn, 0 );                 // シリアルポートに対する読み込み
        if ( nn==1 ) {
            if ( sBuf[0]==10 || sBuf[0]==13 ) {     // '\r'や'\n'を受信すると文字列を閉じる
                if ( i!=0 ) {
                    str[i] =                         '\0';
                    i=0;
                    now = clock();
                    printf("%5d%10d    %s\n",count,now,str);

                    voltage = atof(str);

                    sprintf(output, "%d,%d,%.3f", count , now, voltage * 1000);

                    wclip(output);                        //クリップボードへ出力

                    count++;
                }

            } else { 
                str[i] = sBuf[0];
                i++;
            }
        }
        //ret = PurgeComm( h, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
    }

}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

以前DOSやマイコンボードでシリアル通信を行った経験ベースなので、参考程度にしかならないかと思いますが書かせて頂きます。
ケーブルを外すことでプログラムが停止することから、フロー制御ができておらずバッファオーバーフローが起きているような気もするので、1案としてBaudRateを下げてみるというのが有ります。
ケーブルはUSBシリアル変換なのですね。シリアルポートを直接接続する方式の方が相性が良いような気がしますが、PC側にポートが有るかがネックですね。
あとケーブルのドライバが有るようです。最新版にしてみてはどうでしょうか。
以上、ご参考までに。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/02/09 02:09

    回答ありがとうございます。
    まだ問題は未解決ですが,ご指摘の件について確認した結果について報告させていただきます。

    まず,ケーブルのドライバについてですが,デバイスマネージャーにて確認を行ったとこと,最新のものをインストールしていたようです。

    また,BaudRateを下げることについては,2400まで下げますと,動作自体は安定するようになりましたが,結局数千件データを受信すると停止してしまいます。また,ブルースクリーンが発生する件も未解決でした。

    また,通信対象であるオシロスコープや,使用しているケーブルにより,フロー制御は行えない状態になります。

    他の要素についても,自分なりに検討を進めてみます。

    キャンセル

  • 2015/02/10 06:00

    フリーズとブルースクリーンの原因について調査し,一応の問題解決が出来ましたので報告します。

    ReadFileの行でフリーズが起きているようでした,
    UC-SGTのドライバファイルに問題があったようです。

    ドライバを変更してテストするため,OSをXPに変更しXP用のドライバを使用して,
    再度同じプログラムを実行しましたが,50000件以上データの送受信を行ってもフリーズが起きないので,この状態で使用してみたいと思います。

    ありがとうございました。

    キャンセル

  • 2015/02/10 08:25

    解決に至って何よりです。お疲れ様でした。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る