none
シリアルポートで複数バイトがリードできない。 RRS feed

  • 質問

  • シリアルポートクラスのReadメソッドを利用して複数バイトの受信をしたいのですが
    1バイトしか受信できません。うまく受信できる方法を教えてください。

    なおC言語でAPI(ReadFile)を使用する方法では
    問題なく受信できました。


    byte [] ReadData = new byte [15];
    byte [] WriteData = new byte [15];
    --------
        省略
    --------
    try

         serialPort1.Write(WriteData,0,5);  //マイコンにデータ送信
    }
    catch
    {
         MessageBox.Show("Write Error"); 
       return; 
    }

    try
    {
       int nread;
       nread=serialPort1.Read(ReadData,0,10);  //マイコンからの5バイトをリード
      if(nread!=0)  //nreadが1しか返ってこない 1バイトめのリードデータは正しく受信できている
     {
              -------
     }
     else
      {
         MessageBox.Show("Errir 0Byter Read");
         return;
      }
    }
    catch
    {
         MessageBox.Show("Read Error");
         return;
    }



    2009年6月26日 23:57

回答

  • 書かれているコードそのままであるなら正常な動作をしています。
    APIのReadFileでは指定したバイト数が読み取られるかエラー発生まで制御が戻りません。(FILE_FLAG_OVERLAPPEDでなければ)
    5バイト読み取り指定したなら5バイト揃うまでは制御は戻りません。

    SerialPortクラスのReadではその時点で読み取り可能であったバイト数を読み取って制御が戻ります。
    (ただし最低1バイト読み取るまでは制御が戻らない)

    書かれているコードでは
    serialPort1.Write(WriteData,0,5);
    は書き込みが終わるまで制御が戻らないが、書き込みが終わるとすぐに次のコードが実行されます。
    書き込み直後に
    nread=serialPort1.Read(ReadData,0,10);
    を実行しても、1バイト受信したら制御が戻ってきてしまいます。

    ですから、
    1.マイコン側の処理時間と通信速度を考慮した受信に必要な待ち時間を入れる
    2.目的のバイト数になるまでループで取り出しを繰り返す
    3.受信処理をDataReceivedイベントにする
    のいずれかの方法で読み取りを行ってください。
    • 回答の候補に設定 suntower 2009年6月29日 9:25
    • 回答としてマーク 高橋 春樹 2009年7月7日 8:22
    2009年6月27日 1:25

すべての返信

  • 書かれているコードそのままであるなら正常な動作をしています。
    APIのReadFileでは指定したバイト数が読み取られるかエラー発生まで制御が戻りません。(FILE_FLAG_OVERLAPPEDでなければ)
    5バイト読み取り指定したなら5バイト揃うまでは制御は戻りません。

    SerialPortクラスのReadではその時点で読み取り可能であったバイト数を読み取って制御が戻ります。
    (ただし最低1バイト読み取るまでは制御が戻らない)

    書かれているコードでは
    serialPort1.Write(WriteData,0,5);
    は書き込みが終わるまで制御が戻らないが、書き込みが終わるとすぐに次のコードが実行されます。
    書き込み直後に
    nread=serialPort1.Read(ReadData,0,10);
    を実行しても、1バイト受信したら制御が戻ってきてしまいます。

    ですから、
    1.マイコン側の処理時間と通信速度を考慮した受信に必要な待ち時間を入れる
    2.目的のバイト数になるまでループで取り出しを繰り返す
    3.受信処理をDataReceivedイベントにする
    のいずれかの方法で読み取りを行ってください。
    • 回答の候補に設定 suntower 2009年6月29日 9:25
    • 回答としてマーク 高橋 春樹 2009年7月7日 8:22
    2009年6月27日 1:25
  • 回答ありがとうございます。
    会社での仕事上での問題ですので
    月曜日に会社でやってみるか、
    シリアルポートのついたパソコンを
    2台持っているので、ハイパーターミナルと
    の実験で土日に実験してみるか、試してみます。

    2009年6月27日 4:22
  • 会社での名前がsuntowerで個人のsntwrと同一人物です。

    リードするバイト数があらかじめわかった上での受信としては
    ReadByteメッソッドを使ってうまく受信できました。

    5バイトが帰ってくるとわかっている場合

    byte [] ReadData = new byte [15];

    -----省略

    try
    {
          int i,rd;
          for(i=0;i<5;i++)
          {
                rd=serialPort1.ReadByte();
                ReadData[i]=(byte)rd;
          }
           ----------次の処理--------------
    }
    catch
    {
         MessageBox.Show("Read Error");
    }

    実際は汎用のテストソフトですので
    コマンドの仕様によっては受信長が変わりますが
    コマンド解析をしながら受信することによりく実装できそうです。

    • 回答の候補に設定 suntower 2009年6月29日 5:02
    2009年6月29日 0:46
  • こんにちは、フォーラムオペレータの高橋春樹です。

    gekkaさん、こんにちは。
    アドバイスありがとうございました。

    sntwr(suntower)さん、こんにちは。
    MSDNフォーラムのご利用有難うございます。

    具体的なサンプルコードがあると、
    情報を探している皆さんの参考となるので、大変助かります(^-^)

    問題が解決したようなので大丈夫と思いますが、
    勝手ながらgekkaさんの投稿に、回答マークを付けさせてもらいました。
    次回はsntwrさんのほうで、有用な投稿に回答マークを付けて頂くと幸いです。

    今後ともMSDNフォーラムをよろしくお願いします!


    マイクロソフト株式会社 フォーラム オペレータ 高橋春樹
    2009年7月7日 8:22
  • 回答の候補の設定のところを押したはずですが、
    やり方が間違ってますか???

    今まではVC6でC++言語とWIN32APIの古いやり方
    WinMain関数とダイアログボックスベースのソフトで
    プログラムを組んでいました。
    MFCは嫌いなのであえて使用しない。
    これが一番信頼性のあるプログラムがかけるし
    スピードは速い。Windowsの仕組みがわかる。
    だだコード量が増えてしまうのと
    API関数を理解していないとだめ、
    他の人が見てもわからない(VBしかわからない人とか)
    という欠点があります。
    VisualC++2008Expressにリソースエディタがつけば
    理想ですね。Proは持っていますが
    他の人(無償版しかない)が流用できない。

    本当は.NETが必要のないネイティブなアプリケーション
    でWindowの設計が楽なC++の開発ソフトがあれば理想。
    WindowsのAPIも呼びやすいですし。
    そうなるとボーランドのものになってします。
    TurboC++Explorerあたりが無償でありますので
    そっちをたまに使ってみたりします。

    でも他の人が流用できるようにと考慮するとC#が無難なところ
    ということで使用してます。APIの呼び出しが面倒ですけど。

    2009年7月9日 4:04
  • suntowerさん、こんにちは。
    フォーラムオペレータの高橋春樹です。

    内容的に解決したと思ったので、少し時間を置いた後に、
    勝手ながら、私の方で回答マークを付けさせてもらいました。

    投稿者の方によっては、有用な情報にもかかわらず、回答マークを付け忘れている方もいらっしゃいます。
    回答マークを付けて頂くことにより、同じような問題で悩んでいる方が情報を検索したときに
    情報が見つけ易くなるというメリットがあります。

    フォーラムを利用している皆さんの為にも、問題が解決したときは、
    有用な情報を投稿して下さった方に、回答マークを付けて頂きたいと思います。

    すこし分かりにくいのですが、"回答の候補に設定"はスレッドを作成した方以外の方が、
    回答マークの候補として設定する事を前提にしています。
    なので、もし質問者さんが問題が解決した、と思われたときは、
    "回答としてマーク"の方を使用して頂きたいと思います。

    ご理解の程、よろしくお願いします。


    マイクロソフト株式会社 フォーラム オペレータ 高橋春樹
    2009年7月9日 9:28