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

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

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

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

mbed

mbed(エンベッド)は、Webサイト上でC++を使って開発を行う、ワンボードマイコンのプロトタイピングツールです。PCに開発環境をインストールする必要がなく、Webにアクセスできればどこにいても開発を行うことができます。

Q&A

解決済

2回答

17094閲覧

C# シリアル通信での受信に関して

kawauso

総合スコア56

C#

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

mbed

mbed(エンベッド)は、Webサイト上でC++を使って開発を行う、ワンボードマイコンのプロトタイピングツールです。PCに開発環境をインストールする必要がなく、Webにアクセスできればどこにいても開発を行うことができます。

0グッド

0クリップ

投稿2019/07/03 09:43

編集2019/07/04 03:21

お世話になります。

行いたいこと
mbed(送信)とC#(受信)でシリアル通信を行いたいと思っております。
mbed: 「abced...xyz\n」という文字列を送信
c#: 上記の文字列を一括で受信したい

問題点
下記に示すソースコードで検証した場合、文字列を一括ではなく、14文字区切り単位でしか受信できません。

コンソール(受信例)
abcdefghijklmn
opqrstuvwxyzab
cdefghijklmnop
qrstuvwxyzabcd
...

質問
14文字区切り単位ではなく、「abced...xyz\n」という風に一括で受信したいと考えております。
解決策をご存知の方は、ご教示いただければ幸いです。
よろしくお願い致します。

環境
C#: .NET FW 4.6.1, VS Pro 2017
mbed: NXP LPC1768

以下、ソースコード
▼受信側C#

C#

1public SerialPort Port; 2 3public void main(){ 4 Port = new SerialPort(port, 9600, Parity.None, 8, StopBits.One); 5 Port.Open(); 6 Port.DataReceived += SrialPortDataReceived; 7} 8 9private void SrialPortDataReceived(object sender, SerialDataReceivedEventArgs e) 10{ 11 var sp = sender as SerialPort; 12 if (Port.BytesToRead > 0) 13 { 14 byte[] b = new byte[Port.BytesToRead]; 15 sp.Read(b, 0, b.Length); 16 17 string text = System.Text.Encoding.ASCII.GetString(b).Replace("\n", ""); 18 Console.WriteLine(text); 19 } 20}

▼送信側mbed

Cpp

1#include "mbed.h" 2 3Serial pc(USBTX, USBRX); // tx, rx 4 5int main() { 6 while(1) { 7 pc.printf("abcdefghijklmnopqrstuvwxyz"); 8 wait_ms(50); 9 } 10}

修正後

C#

1 public SerialPort Port; 2 3 public void main() 4 { 5 var port = GetPortName(); 6 if (port != null) 7 { 8 try 9 { 10 Port = new SerialPort(port, 9600, Parity.None, 8, StopBits.One); 11 Port.Open(); 12 while (true) 13 { 14 var msg = Port.ReadLine(); 15 Console.WriteLine(msg); 16 } 17 } 18 catch (ArgumentException ae) 19 { 20 Console.WriteLine(ae); 21 } 22 catch (SystemException se) 23 { 24 Console.WriteLine(se); 25 } 26 } 27 } 28 29 private IEnumerable<string> GetSerialDeviceNames() 30 { 31 // System.Managementを参照に追加 32 var pnpEntity = new ManagementClass("Win32_PnPEntity"); 33 var comRegex = new Regex(@"(COM[1-9][0-9]?[0-9]?)"); 34 35 return pnpEntity 36 .GetInstances() 37 .Cast<ManagementObject>() 38 .Select(managementObj => managementObj.GetPropertyValue("Name")) 39 .Where(nameObj => nameObj != null) 40 .Select(nameObj => nameObj.ToString()) 41 .Where(name => comRegex.IsMatch(name)); 42 } 43 44 private string GetPortName() 45 { 46 foreach (string device in GetSerialDeviceNames()) 47 { 48 if (device.Contains("mbed")) 49 { 50 var com = new Regex(@"[^0-9]").Replace(device, ""); 51 int num; 52 if (int.TryParse(com, out num)) 53 { 54 return ("COM" + num); 55 } 56 } 57 } 58 59 return null; 60 }

Cpp

1#include "mbed.h" 2 3Serial pc(USBTX, USBRX); // tx, rx 4 5int main() { 6 while(1) { 7 pc.printf("abcdefghijklmnopqrstuvwxyz\n"); 8 wait_ms(50); 9 } 10}

エラー
...
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
'Hoge.exe' (CLR v4.0.30319: Caracol.exe): 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.resources\v4.0_4.0.0.0_ja_b77a5c561934e089\System.resources.dll' が読み込まれました。モジュールがシンボルなしでビルドされました。
例外がスローされました: 'System.IO.IOException' (System.dll の中)
System.IO.IOException: スレッドの終了またはアプリケーションの要求によって、I/O 操作が中止されました。
場所 System.IO.Ports.SerialStream.EndRead(IAsyncResult asyncResult)
場所 System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout)
場所 System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count)
場所 System.IO.Ports.SerialPort.InternalRead(Char[] buffer, Int32 offset, Int32 count, Int32 timeout, Boolean countMultiByteCharsAsOne)
場所 System.IO.Ports.SerialPort.ReadTo(String value)
場所 System.IO.Ports.SerialPort.ReadLine()

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

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

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

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

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

guest

回答2

0

ベストアンサー

https://docs.microsoft.com/ja-jp/dotnet/api/system.io.ports.serialport.readbuffersize?view=netframework-4.8#System_IO_Ports_SerialPort_ReadBufferSize

SerialPort.ReadBufferSize は、SerialPort 固有の設定と、Windows で後から設定した値と、どちらか小さい方を返します。
もしかして対象の SerialPort が、そもそも14文字分しかバッファを持っていない、なんてことはないですかね。

※SerialPort クラスは初期値として ReadBufferSize に 4096 を使用しています

投稿2019/07/04 02:49

tacsheaven

総合スコア13703

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

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

kawauso

2019/07/04 06:59

回答ありがとうございます。 調べているとmbed標準Serialライブラリはソフトウェアバッファを備えておらず、基本的にブロッキング通信になるとのことです。 mbed側でバッファ機能のあるAsyncSerial, BufferedSerialライブラリなどを使用してみましたが、一度に14文字分しか受信できませんでした。 TeraTermで受信すると一行ごとに受信できているように思えました。
kawauso

2019/07/04 07:14

デバイスマネージャー→ポート(COMとLPT)→mbed Serial Port(COMx)→プロパティ→ポートの設定→詳細設定 受信バッファー: 14 送信バッファー: 16 というふうになっていました。 14文字までしか受信できないとあきらめて、工夫するしかないのでしょうか。 何か案などございましたら教示いただければ幸いです。
tacsheaven

2019/07/04 07:19

14文字までしか受信できない、というのはハード的な制限と思われるので、取得したデータの中に\nがない→取得分を「自前のバッファ」に入れて、もう一度受信を行う、\nがある→\n までの部分を「自前のバッファ」に追記して、自前のバッファの内容を表示してクリアし、\n から後の部分を自前のバッファに入れてもう一度受信を行う、という形のポーリングをするような感じでしょうかね。
kawauso

2019/07/04 08:21

ありがとうございます。おかげさまで実装できました。
guest

0

DataReceivedイベントは使わないで、ReadLineメソッドを使いましょう
また、改行を\nだけにするなら、NewLineプロパティを\nにしておく必要があります

ReadLineメソッドでは、1行受信するまで戻ってきません

投稿2019/07/03 09:58

y_waiwai

総合スコア88024

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

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

y_waiwai

2019/07/03 10:23

って、送信側のコードでは改行が入ってないですが。 こちらの方も修正の必要がありますね
kawauso

2019/07/04 02:03

回答ありがとうございます。 質問文に修正後のプログラムを追記しました。 しかし、エラーが出力されてしまいます。 以前、DataReceivedイベント内でReadLineメソッドを使用したコードを書いた際にも同じエラーが出力されていました。 ご存知のことがあれば、教示いただければ幸いです。
y_waiwai

2019/07/04 02:07

送信側で、改行コードの \n が送信されてないんじゃないでしょうか pc.printf("abcdefghijklmnopqrstuvwxyz\n"); と修正しましょう
kawauso

2019/07/04 02:42

回答ありがとうございます。 質問文に記載した修正後プログラム(cpp)のようにしておりますが、同じエラーが出力されてしまいます。
y_waiwai

2019/07/04 02:48

提示されたエラーは外部から終了させられたときにでるもんなんで、提示のコードは関係なさげです ところで、 > Port = new SerialPort(port, 9600, Parity.None, 8, StopBits.One); 引数の port は定義が見当たりませんが、これはどうなってるんでしょうか
kawauso

2019/07/04 03:01

引数portに関しては、記載はしていませんがmbedという名前が含まれているCOM番号を取得するメソッドを実装しております。 portにはstring型の"COM9"などが格納されています。
y_waiwai

2019/07/04 03:04

なんかそういう提示されたコード以外のところのエラーかと思われますね コード全文は提示できませんか
kawauso

2019/07/04 03:22

プログラムを追記しました。 追記のエラー文にもあるように、途中までは問題なく受信できているようです。
y_waiwai

2019/07/04 03:34 編集

別スレッドで、当該ポートをクローズしたり開き直したりしてませんか。 タイムアウトでなんかしてるように見えますが
kawauso

2019/07/04 03:43

Openはtyrの中で一回しているだけです。いまのところPort.Close()とするコードは記述しておりません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問