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

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

ただいまの
回答率

90.84%

  • C#

    6257questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Fromアプリからシーケンサ(三菱製)とシリアル通信を行った場合、4byteしかデータを受信できない

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 200

dashi

score 4

 dodox86さん、coco_bauerさん、pepperleafさん ご指摘ありがとうございます。

追加情報を添付させていただきます。

PC⇔シーケンサをRS-232ケーブルで接続し、デバイス(本件ではM)を読みだそうとしています。
ハンドシェイクについて、Handshake.None(※0)~Handshake.RequestToSendXOnXOff(※3) まで、
全通り振ってみましたが、結果は変わりませんでした。

尚、問題なく送受信できるTeraTerm上の設定は、
以下の通りとなりWondowsFormアプリで設定した内容と同じと考えております。
ボーレート :115200
データ     :8bit
パリティ   :odd
ストップ(s):1bit
フロー制御 :none

C#のソースコードを添付します。

        ★シリアル通信設定→送信→受信読み込み部分
        SerialPortContorl seriIns_plc = new SerialPortContorl();
        int ret = seriIns_plc.Open_plc("COM19");  ★シリアル通信設定
        if (Program.DefinedValue.PORT_OPEN != ret)
        {
            /* Open失敗 */
            seriIns_plc.Close();
            seriIns_plc.Dispose();
            seriIns_plc = null;
            return;
        }
        seriIns_plc.sendCmd_plc();
        for (;;) {
            System.Threading.Thread.Sleep(1000);
            Console.WriteLine("{0}", seriIns_plc.BytesToRead); ★ここで受信サイズを参照するも4しかでない
            if (seriIns_plc.BytesToRead > 0)
            {
                byte data = (byte)seriIns_plc.ReadByte(); ★受信部分
                Console.WriteLine("recv:{0}", data);
            }
        }

        ★通信設定部分
        public int Open_plc(string portName)
        {
            try
            {
                PortName = portName;
                BaudRate = 115200;
                DataBits = 8;
                Parity = Parity.Odd;
                StopBits = StopBits.One;
                //Encoding = Encoding.UTF8;
                //NewLine = "\r\n";

                Encoding = Encoding.GetEncoding("shift_jis");
                Handshake = Handshake.None;

                Open();

                ret = Program.DefinedValue.PORT_OPEN;
            }
            catch
            {
            }
            return 0;
        }

        //*******************************************
        // MCプロトコル
        //*******************************************
        static public byte PLC_SEND_CTLCODE_ENQ = 0x05;
        static public string PLC_SEND_FRAMENO_4C = "F8";
        static public string PLC_SEND_ADDRESSNO = "00";
        static public string PLC_SEND_NETWORKNO = "00";
        static public string PLC_SEND_PCNO = "FF";
        static public string PLC_SEND_UNITIO = "03FF";
        static public string PLC_SEND_UNITNO = "00";
        static public string PLC_SEND_UNITADR = "00";

        static public string PLC_SEND_READ_CMD = "0401";
        static public string PLC_SEND_SUB_CMD = "0000";
        static public string PLC_SEND_READ_DNO = "003062";
        static public string PLC_SEND_MCODE = "M*";

        ★データ送信部分
        public void sendCmd_plc()
        {
            byte[] convByte = new byte[1024];
            byte[] sendByte = new byte[1024];
            StringBuilder sendStr = new StringBuilder();

            sendStr.Append(PLC_SEND_FRAMENO_4C);    //F8
            sendStr.Append(PLC_SEND_ADDRESSNO);     //00
            sendStr.Append(PLC_SEND_NETWORKNO);     //00
            sendStr.Append(PLC_SEND_PCNO);          //FF
            sendStr.Append(PLC_SEND_UNITIO);        //03FF
            sendStr.Append(PLC_SEND_UNITNO);        //00
            sendStr.Append(PLC_SEND_UNITADR);       //00
            sendStr.Append(PLC_SEND_READ_CMD);      //0401
            sendStr.Append(PLC_SEND_SUB_CMD);       //0000
            sendStr.Append(PLC_SEND_MCODE);         //M*
            sendStr.Append(PLC_SEND_READ_DNO);      //003062
            sendStr.Append("0005");                 //デバイス点数(5点)

            convByte = Encoding.UTF8.GetBytes(sendStr.ToString());
            byte chkSum = 0;
            foreach(byte byteUnit in convByte)
            {
                chkSum += byteUnit;
            }
            byte[] chksum_4bit= { 0, 0 };
            chksum_4bit[0] = (byte)(chkSum >> 4);
            chksum_4bit[1] = (byte)(chkSum & 0xF);

            byte sendDataSize = 0;
            sendByte[0] = PLC_SEND_CTLCODE_ENQ;
            sendDataSize++;
            foreach (var byteUnit in convByte.Select((value,idx) => new { value, idx }))
            {
                sendByte[1 + byteUnit.idx] = byteUnit.value;
                sendDataSize++;
            }
            sendByte[sendDataSize] = btoa(chksum_4bit[0]);
            sendDataSize++;
            sendByte[sendDataSize] = btoa(chksum_4bit[1]);
            sendDataSize++;
            sendByte[sendDataSize] = 0x0D;
            sendDataSize++;
            sendByte[sendDataSize] = 0x0A;
            sendDataSize++;

            Write(sendByte, 0, sendDataSize); ★sendByteに格納されたデータをTeraTermから送信すると問題ない
        }

 問題事項

現在、デバイス(M3062)に対してシリアル通信(RS-232)にて一括読み出し操作を実施しているが、
応答データがいくら待っても4byteしか受信できない。
(BytesToReadをループでモニタし続けているが4byteから増えない)

尚、シーケンサとのデータ送受信はC#で組んだWindow From上で実施しているが、
このForm上から発行するデータ(要求伝文)をダンプしてTeraTerm上から発行すると
問題なくデータを受信できる。

このことからC#のプログラム上のシリアル通信設定周りに問題があるのではないかと
推測している。

ただ、原因となりそうな箇所が見受けられず困っている状況のため、
アドバイスをいただきたい。

 送信データ(要求伝文)

0x05 = コントロールコード(ENQ)
0x46 0x38 = 4Cフレーム(F8)
0x30 0x30 = 局番号(00)
0x30 0x30 = ネットワーク番号(00)
0x46 0x46 = PC番号(FF)
0x30 0x33 0x46 0x46 =要求先ユニットI/O番号(03FF) 
0x30 0x30 = 要求先ユニット局番号(00)
0x30 0x30 = 自局番号(00)
0x30 0x34 0x30 0x31 = コマンド(0401)
0x30 0x30 0x30 0x30 = サブコマンド(0000)
0x4d 0x2a = デバイスコード(M )
0x30 0x30 0x33 0x30 0x36 0x32 = デバイス番号(3062)
0x30 0x30 0x30 0x35 = デバイス点数(0005)
0x36 0x35 =チェックサム 
0x0d 0x0a =コントロールコード(CR+LF)

 受信データ

・Formアプリで受信(★問題発生時)
→0x02 0x46 0x38 0x30
★途中までしか受信できていない(4byteしかない)

・TeraTermで受信(★問題なし時)
02
46 38 
30 30 30 30 
46 46 
30 33 46 46 
30 30 30 30 

30 30 30 30 
30 30 30 30 
30 30 38 30 
30 30 30 30 
30 30 30 30 

03    
34 34 
0D 0A 

 使用環境情報

・製品名:シーケンサ(iQ-R ,Q,L,QnA,A)
・形名:Q00UJCPU(※三菱製)

・通信使用PC=Windows7(64bit)
・シーケンサCPU=Q00UJCPU
・通信方式=RS-232(MCプロトコル)
・MCプロトコル形式=形式4(ASCII)
・参照資料1(sh080001)
→QnUCPUユーザーズマニュアル(機能解説・プログラム基礎編)
・参照資料2(sh080003)
→MELSECコミュニケーションプロトコル リファレンスマニュアル

        シーケンサとのシリアル通信設定
        public int Open_plc()
        {
            try
            {
                PortName = "COM19";
                BaudRate = 115200;
                DataBits = 8;
                Parity = Parity.Odd;
                StopBits = StopBits.One;

                Open();
            }
            catch {}
            return 0;
        }
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • Wind

    2018/06/20 10:44

    ReceivedBytesThresholdプロパティで、5Byte以上を受信するように設定してみてはどうでしょうか?

    キャンセル

  • dashi

    2018/06/20 11:13

    g_uoさん ReadBufferのサイズは4096byteです

    キャンセル

  • dashi

    2018/06/20 11:15

    Windさん ReceivedBytesThresholdを4よりも大きな値を設定するとDataReceivedイベントが発生しません。(4byte以上データを受信できていないため)

    キャンセル

回答 4

checkベストアンサー

+3

※直接の回答ではありません。さまざまな改善の提案があると思いますので、以下も参考程度に。

  • 仮想、あるいはUSBシリアル変換ドライバーの一部で、信号線を操作しないとうまく動作しないケースがあった気がします。SerialPort.DtrEnableSerialPort.RtsEnableなどをセットしてみて状況が変わるか試してみてはいかがでしょうか。※USBシリアル変換ドライバーが、有名どころのFTDI製であればそう問題は発生しないと思いますが。。。

  • 問題切り分けの為、SerialPortクラスを継承して独自実装部分を除外し、シンプルにサンプルプログラムのように作ってみる。.NET Framework 2.0 コア機能解説 ~ 第 2 回 シリアルポートのサポート ~

  • 環境の違うマシンで試してみる。

動作環境が不明でしたが、Windowsのバージョン、.NET Frameworkのバージョン等も一応、示されたほうが良いと思います。
 

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/20 11:22

    SerialPort.DtrEnableをTrueに設定することで受信できるようになりました。
    誠にありがとうございました。
    SerialPort.DtrEnableを設定すると受信できる理由については調べてみようかと思います。

    本件はCloseさせていただきます。

    みなさま 本当にありがとうございました。

    キャンセル

  • 2018/06/20 11:29

    解決してよかったです。私の周りで実際に発生したことはなかったので、参考までにUSBシリアル変換器のメーカーやドライバーの型番など教えていただけますでしょうか。(お差支えなければで結構です)
    ドライバーの問題と言っている訳ではなく、コントローラー側やケーブルがRS-232C全結線していたりして、ドライバーもそれに対応しているのであれば当然センシティブでしょうから。

    キャンセル

  • 2018/06/20 11:44

    dodox86さん

    拙い質問に真摯に対応していただきありがとうございました。

    製品情報です
     メーカー:SANWA
    製品品番:USB-CVRS9

    ドライバーは以下からダウンロードしています。(Windows7 64bit版です)
     https://www.sanwa.co.jp/support/download/dl_driver_ichiran.asp?code=USB-CVRS9

    キャンセル

  • 2018/06/20 11:45

    どうもありがとうございます。参考にさせていただきます。

    キャンセル

  • 2018/06/20 21:07

    解決して良かったです。
    以前(と言っても10年以上前)、幾つかのUSB-シリアルケーブルを試した事がありますが、制御線(DTR etc.)まできちんとサポートしているは少なかったです。(特に国内メーカ) SANWAも当たり外れがあったような。その後は知りませんが。 DTR .. Data Terminal Ready .. 手抜き制御なら関係無いですが、これが有効で無いとデータを送らないのが正しい。某機器は、一定期間(数100ms)以内に応答しないと、勝手に切断するのもありました。

    キャンセル

  • 2018/06/20 21:18

    pepperleafさん、フォローと情報ありがとうございます。私もUSBシリアルを使うようになってからあまり制御線を意識しなくなってましたが、特に今回は相手方が産業用機器なので厳密に動作しているのですね。認識を新たにしました。

    キャンセル

  • 2018/06/20 21:28

    dodox86さん、
    産業機器といっても千差万別みたいです。今使っているのは、メーカーがライブラリを提供していて、この辺の細かなことを考慮しなくても問題無く動いているようです。自分で実装していないので正確なところは不明ですが、アクセスそのものは、シンプル。ただ、困ったら、信号線のモニタは必須ですが。(以前、作ったツールはモニタ機能も付けた)

    キャンセル

0

先頭の 4byteは、正しそうなので、受信設定は問題ないと思います。
あるとすれば、ハンドシェイク設定でしょうか?

また、実際にどのようなコードで読出しを行っているのでしょうか?

[追記]
思わず、回答に書いてしまいましたが、コメントにすべき内容でした。
で、、、
SerialPortContorl クラスは、独自実装または、メーカー提供でしようか?
SerialPortのラッパぽいですが、、。
結構、早い速度ですが、遅くしたら、どうなるでしょうか? Console.WriteLine()を読込み中のところから、無くしても同様でしょうか?

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/20 09:22

    pepperleafさん

    情報が足りず申し訳ございません。
    ご認識の通り、SerialPortContorl クラスはSerialPortをラッパした独自実装クラスです。

    >結構、早い速度ですが、遅くしたら、どうなるでしょうか?
    「遅くしたら」とはシーケンサへコマンドを発行してから、
    受信(seriIns_plc.ReadByte())までの時間のこととなりますでしょうか。

    以下★のSleep時間を延ばしても(10秒)結果は変わりませんでした。

    for (;;) {
    System.Threading.Thread.Sleep(1000); ★
    Console.WriteLine("{0}", seriIns_plc.BytesToRead);

    >Console.WriteLine()を読込み中のところから、無くしても同様でしょうか?
    Console.WriteLineを削除してみても結果は変わらずです。

    また、通信ボーレートを"19.2K","9.6K"の二つでも試してみましたが、
    こちらも現象が変わりませんでした。

    ozwkさん
    >seriIns_plc.BytesToReadはどう実装してますか?
    こちら上記に記載いたしましたが、SerialPortのパラメータとなります。
    よって、こちらでは実装等はしておりません。

    回答になっておりますでしょうか。

    キャンセル

0

まず、本当に4byte以上のレスポンスが帰ってきているのか、オシロなどで確認してはいかがでしょう
また、送信と受信のラインを分け、送信はC#のコードから、受信をTeraTermなどでさせるなどして受信を確認してみては。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

SerialPort.DtrEnableをTrueに設定することで問題を解決できました。

みなさま
本当にありがとうございました。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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

  • C#

    6257questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • トップ
  • C#に関する質問
  • Fromアプリからシーケンサ(三菱製)とシリアル通信を行った場合、4byteしかデータを受信できない