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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

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

Q&A

解決済

4回答

9262閲覧

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

dashi

総合スコア14

C#

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

0グッド

2クリップ

投稿2018/06/19 10:36

編集2018/06/19 11:37

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

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

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

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

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

C#

1 ★シリアル通信設定→送信→受信読み込み部分 2 SerialPortContorl seriIns_plc = new SerialPortContorl(); 3 int ret = seriIns_plc.Open_plc("COM19"); ★シリアル通信設定 4 if (Program.DefinedValue.PORT_OPEN != ret) 5 { 6 /* Open失敗 */ 7 seriIns_plc.Close(); 8 seriIns_plc.Dispose(); 9 seriIns_plc = null; 10 return; 11 } 12 seriIns_plc.sendCmd_plc(); 13 for (;;) { 14 System.Threading.Thread.Sleep(1000); 15 Console.WriteLine("{0}", seriIns_plc.BytesToRead); ★ここで受信サイズを参照するも4しかでない 16 if (seriIns_plc.BytesToRead > 0) 17 { 18 byte data = (byte)seriIns_plc.ReadByte(); ★受信部分 19 Console.WriteLine("recv:{0}", data); 20 } 21 } 22 23 ★通信設定部分 24 public int Open_plc(string portName) 25 { 26 try 27 { 28 PortName = portName; 29 BaudRate = 115200; 30 DataBits = 8; 31 Parity = Parity.Odd; 32 StopBits = StopBits.One; 33 //Encoding = Encoding.UTF8; 34 //NewLine = "\r\n"; 35 36 Encoding = Encoding.GetEncoding("shift_jis"); 37 Handshake = Handshake.None; 38 39 Open(); 40 41 ret = Program.DefinedValue.PORT_OPEN; 42 } 43 catch 44 { 45 } 46 return 0; 47 } 48 49 //******************************************* 50 // MCプロトコル 51 //******************************************* 52 static public byte PLC_SEND_CTLCODE_ENQ = 0x05; 53 static public string PLC_SEND_FRAMENO_4C = "F8"; 54 static public string PLC_SEND_ADDRESSNO = "00"; 55 static public string PLC_SEND_NETWORKNO = "00"; 56 static public string PLC_SEND_PCNO = "FF"; 57 static public string PLC_SEND_UNITIO = "03FF"; 58 static public string PLC_SEND_UNITNO = "00"; 59 static public string PLC_SEND_UNITADR = "00"; 60 61 static public string PLC_SEND_READ_CMD = "0401"; 62 static public string PLC_SEND_SUB_CMD = "0000"; 63 static public string PLC_SEND_READ_DNO = "003062"; 64 static public string PLC_SEND_MCODE = "M*"; 65 66 ★データ送信部分 67 public void sendCmd_plc() 68 { 69 byte[] convByte = new byte[1024]; 70 byte[] sendByte = new byte[1024]; 71 StringBuilder sendStr = new StringBuilder(); 72 73 sendStr.Append(PLC_SEND_FRAMENO_4C); //F8 74 sendStr.Append(PLC_SEND_ADDRESSNO); //00 75 sendStr.Append(PLC_SEND_NETWORKNO); //00 76 sendStr.Append(PLC_SEND_PCNO); //FF 77 sendStr.Append(PLC_SEND_UNITIO); //03FF 78 sendStr.Append(PLC_SEND_UNITNO); //00 79 sendStr.Append(PLC_SEND_UNITADR); //00 80 sendStr.Append(PLC_SEND_READ_CMD); //0401 81 sendStr.Append(PLC_SEND_SUB_CMD); //0000 82 sendStr.Append(PLC_SEND_MCODE); //M* 83 sendStr.Append(PLC_SEND_READ_DNO); //003062 84 sendStr.Append("0005"); //デバイス点数(5点) 85 86 convByte = Encoding.UTF8.GetBytes(sendStr.ToString()); 87 byte chkSum = 0; 88 foreach(byte byteUnit in convByte) 89 { 90 chkSum += byteUnit; 91 } 92 byte[] chksum_4bit= { 0, 0 }; 93 chksum_4bit[0] = (byte)(chkSum >> 4); 94 chksum_4bit[1] = (byte)(chkSum & 0xF); 95 96 byte sendDataSize = 0; 97 sendByte[0] = PLC_SEND_CTLCODE_ENQ; 98 sendDataSize++; 99 foreach (var byteUnit in convByte.Select((value,idx) => new { value, idx })) 100 { 101 sendByte[1 + byteUnit.idx] = byteUnit.value; 102 sendDataSize++; 103 } 104 sendByte[sendDataSize] = btoa(chksum_4bit[0]); 105 sendDataSize++; 106 sendByte[sendDataSize] = btoa(chksum_4bit[1]); 107 sendDataSize++; 108 sendByte[sendDataSize] = 0x0D; 109 sendDataSize++; 110 sendByte[sendDataSize] = 0x0A; 111 sendDataSize++; 112 113 Write(sendByte, 0, sendDataSize); ★sendByteに格納されたデータをTeraTermから送信すると問題ない 114 }

問題事項

現在、デバイス(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コミュニケーションプロトコル リファレンスマニュアル

C#

1 シーケンサとのシリアル通信設定 2 public int Open_plc() 3 { 4 try 5 { 6 PortName = "COM19"; 7 BaudRate = 115200; 8 DataBits = 8; 9 Parity = Parity.Odd; 10 StopBits = StopBits.One; 11 12 Open(); 13 } 14 catch {} 15 return 0; 16 } 17 18

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2018/06/19 11:09 編集

参照資料ですが、マニュアル類は三菱のサイトに登録しないとダウンロードできないので、回答者さんらは回答しづらいと思います。 フロー制御のありなしを含む通信設定だけでも提示されたほうが良いかと。あと、Readの処理に原因が無いとも限らないので、コードを提示されてはいかがでしょうか。 .NET Frameworkのシリアル通信は場合によってはクセがありそうです。参考:https://social.msdn.microsoft.com/Forums/ja-JP/833e62eb-763d-42b4-a039-52db1953b3d8/c12398serialport12463125211247312395123881235612390360742183912391?forum=csharpgeneralja
coco_bauer

2018/06/19 11:14

システムの構成が判らない。 デバイス(M3062)、シーケンサー、PC(?)がどのように接続されていて、何が何に対してどういう操作をしているのか理解できません。マイクロコントローラ(M3062)もプログラムを持っているだろうし。
ozwk

2018/06/19 11:51

seriIns_plc.BytesToReadはどう実装してますか?
dashi

2018/06/20 00:28 編集

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

2018/06/20 00:25

普通にserialPort1_DataReceivedイベントで受信してみてはどうでしょうか?
dashi

2018/06/20 00:43 編集

Windさん 以下のようにDataReceivedイベントを登録しましたが、 結果は変わりませんでした。     ★イベント登録 seriIns_plc.DataReceived += new SerialDataReceivedEventHandler(SerialRecvData_Plc); seriIns_plc.ReadTimeout = 2000; ★DataReceivedイベント受信関数 private void SerialRecvData_Plc(object sender, SerialDataReceivedEventArgs e) { Console.WriteLine("{0}", seriIns_plc.BytesToRead); for(int i = 0; i < seriIns_plc.BytesToRead; i++) { byte data = (byte)seriIns_plc.ReadByte(); Console.WriteLine("recv:{0}", data); } }
ozwk

2018/06/20 01:10

「ここで受信サイズを参照するも4しかでない」-> 4byteしか受信できていないなら、ループ回るたびに1byte読み出しているので、4->3->2->1->0となるはずですが、どうですか?
dodox86

2018/06/20 01:14

.NET Framework SerialPortクラスを使用したことは何度もありますが、経験の無い挙動ですね。 回答に至らないのでコメントのみですが、PC側のシリアル端子はもろシリアル(D-SUB9ピン)か、USB/シリアル変換でしょうか。 (ドライバーの影響かと思いつつも、teraterm で問題が無いのだから、.NET Frameworkを含むミドルウェアかアプリのせいだとは思いますが)
Wind

2018/06/20 01:18

「MCプロトコル形式=形式4(ASCII)」とあるので、BytesToReadでは無くReadLineで文字列(ASCII)として読み込んでみてはどうでしょうか?末尾はCRLFですし。
g_uo

2018/06/20 01:21

teratermで問題ないとのことですから解決には至らないとは存じますが、Windowsのデバイスマネージャから、シリアルポートのドライバ設定を確認してみてください。ボーレート等の設定は一致していますか?もし異なっている場合は、質問文の設定に合わせてみてください。
dashi

2018/06/20 01:34 編集

ozwkさん >1byte読み出しているので、4->3->2->1->0となるはずですが、どうですか? はい、その通りの挙動となります。 期待動作としては、17byteの受信データとなりますが、現状何をやってもBytesToReadには4しか設定されません。
dashi

2018/06/20 01:54 編集

dodox86さん PC側にはUSB/シリアル変換で実施しています。 ドライバーも念のため再インストールしてみましたが、結果は変わらない状況です。 .NET Framework のVersionを4、3.5まで下げてみましたが、現象は変わりませんでした。(もともとは4.6.1を使用しています)
dashi

2018/06/20 01:37

Windさん おっしゃる通り末尾はCR+LFなのですが、先頭4byteしか受信できないためReadLine()では読み込みできません。(CR+LFを受信できないためタイムアウトとなります)
dashi

2018/06/20 01:40

g_uoさん ご指摘のデバイスマネージャーの設定を合わせてみましたが結果は変わりませんでした。
g_uo

2018/06/20 01:43

ご確認ありがとうございました。わからんス。一応確認ですが、ReadBufferのサイズが4byteになっているとかはないですかね?
Wind

2018/06/20 01:44

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

2018/06/20 02:13

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

2018/06/20 02:15

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

回答4

0

ベストアンサー

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

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

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

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

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

投稿2018/06/20 01:57

dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dashi

2018/06/20 02:22

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

2018/06/20 02:29

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

2018/06/20 02:45

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

2018/06/20 12:07

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

2018/06/20 12:18

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

2018/06/20 12:28

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

0

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

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

投稿2018/06/20 02:23

dashi

総合スコア14

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

投稿2018/06/20 02:08

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

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

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

投稿2018/06/19 11:19

編集2018/06/19 13:56
pepperleaf

総合スコア6383

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dashi

2018/06/20 00: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のパラメータとなります。 よって、こちらでは実装等はしておりません。 回答になっておりますでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問