C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[10]: SerialPort 受信できない


(過去ログ 167 を表示中)

[トピック内 14 記事 (1 - 14 表示)]  << 0 >>

■96596 / inTopicNo.1)  SerialPort 受信できない
  
□投稿者/ tkit (1回)-(2020/12/23(Wed) 16:55:30)

分類:[C#] 

初めて、C#にて、計測器とRS232C接続し、計測値を取得するアプリを作成中です。
計測器に送信コマンドを送ると既定の動作をするのですが、
[*IDN?]コマンドでIDを受信するのですが、受信できません。
TeraTermでは、送受信可能でしたので、コードの問題です。
C#にて受信できないまま終了後、TeraTerm接続で受信内容が表示されます。
ですので、送信は問題ないのですが、受信ができない状況です。
SerialPort設定は、C#、TeraTerm共通です。

解決するため、お力をお貸しください。


環境
Win10 64bit
VisualStudio2019
.NETFramework,Version=v4.7.2
接続:PC-USB_COM変換-インターリンクケーブル-Agilent_34401A



コード


using System;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Component1 COM = new Component1();
            COM.Open();
            COM.Send();
            Console.WriteLine("WAIT");
            Console.ReadKey();
            //COM.Receive();
            COM.Close();
        }
    }
}

using System;
using System.ComponentModel;
using System.IO.Ports;
using System.Text;

namespace ConsoleApp1
{
    public partial class Component1 : Component
    {

        public Component1()
        {
            InitializeComponent();
            serialPort1.PortName = "COM6";
            serialPort1.BaudRate = 9600;
            serialPort1.DataBits = 8;
            serialPort1.Parity = Parity.None;
            serialPort1.StopBits = StopBits.One;
            serialPort1.ReadTimeout = 2000;
            serialPort1.NewLine = "\n";
        }

        public Component1(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }

        public void Open()
        {
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
                Console.WriteLine("既に開いています。");
                return;
            }
            serialPort1.Open();
            Console.WriteLine("OPEN");
        }

        public void Send()
        {
            try
            {
                serialPort1.Write("*IDN?" +"\n");
                Console.WriteLine("Send");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
         }

        public void Receive()
        {
            try
            {
                string rec = serialPort1.ReadLine();
                Console.WriteLine(rec);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            
        }

        public void Close()
        {
            serialPort1.DiscardOutBuffer();
            serialPort1.Close();
            Console.WriteLine("CLOSE");
        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            try
            {
                string rec = serialPort1.ReadExisting();
                Console.WriteLine(rec);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}


引用返信 編集キー/
■96597 / inTopicNo.2)  Re[1]: SerialPort 受信できない
□投稿者/ shu (1238回)-(2020/12/23(Wed) 17:25:41)
No96596 (tkit さん) に返信

serialPort1_DataReceived
イベントの割り当てをおこなっていますでしょうか?

serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);

参考:
https://docs.microsoft.com/ja-jp/dotnet/api/system.io.ports.serialport.datareceived?view=dotnet-plat-ext-5.0
引用返信 編集キー/
■96601 / inTopicNo.3)  Re[2]: SerialPort 受信できない
□投稿者/ tkit (2回)-(2020/12/24(Thu) 09:21:25)
No96597 (shu さん) に返信
> ■No96596 (tkit さん) に返信
>
> serialPort1_DataReceived
> イベントの割り当てをおこなっていますでしょうか?
>
> serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);

ご指摘ありがとうございます。
コンストラクタ内[serialPort1.NewLine = "\n";]直下に↑のコードを追記しました。
ですが、イベントが発生しません。

コメントアウトを外し、ステップインで[Receive]メソッドを実行、
読み出し前には、計測器のバッファに戻り値が入るよう、数秒待ってから実行しています。

ReadExistingでは、文字数0の文字列である""を受信、
ReadLineでは、デリミタをCR、LF、CRLFそれぞれで確認するも、全てタイムアウトとなります。

上記それぞれの結果後、TeraTerm接続でIDN?の戻り値が取得できます。

試しに、VISACOMを参照し送受信を行ったら、戻り値を受信できました。
ですが、VISACOMで行う場合、インストールが必要なため、C#のみの機能で行いたいと考えております。

何か足りないコードや作法があるのでしょうか?

引用返信 編集キー/
■96603 / inTopicNo.4)  Re[1]: SerialPort 受信できない
□投稿者/ 774RR (854回)-(2020/12/24(Thu) 10:51:47)
オイラの経験上は serialPort1 のプロパティの初期化が足らない気がする。
serialPort1.WriteTimeout = 200; /* BaudRate 等から決まる適切な値が必要 */
serialPort1.Handshake = Handshake.None;
serialPort1.RtsEnable = false;
あたりは無いとはまるパターン。

計測器から返事がないと思っているときの失敗パターンは2つ
そもそもコマンドが送れていない(から計測器としては返事のしようが無い)
送れているけど待ちが足らない、またはデリミタ等が違っていて受け取れない

プロトコルアナライザーちゃんで実信号を読んでみるといろいろわかるっス。
実機がないなら com0com あたりを使ってみるのも良いだろう
(ウチの社内マシンにインストールするのは管理部の許可が下りなかった)

この手の測定器具が用意できない場合は、計測器側を「計測結果を常に送る」モードにしたらいい
計測器→PCの受信側のデバッグが簡単にできるっス。

引用返信 編集キー/
■96611 / inTopicNo.5)  Re[2]: SerialPort 受信できない
□投稿者/ みい (122回)-(2020/12/24(Thu) 13:51:56)
送信できていないか受信できていないかの判断として
IDN?コマンドでなくREAD?のように相手機器本体に
反応が出るコマンドを送信してみるのも1つの手です。
引用返信 編集キー/
■96615 / inTopicNo.6)  Re[3]: SerialPort 受信できない
□投稿者/ tkit (3回)-(2020/12/24(Thu) 14:50:57)
ありがとうございます。

774RRさんの情報を基に、コード修正後の状況は以下となります。

・測定器のデリミタはLFだったので、コード修正

・送信コマンドに対し、DMM側での処理は問題無く処理していそう。
 リセット、レンジ切替が出来ており、ID読み出しにて、受信バッファにデータが入っている。

・測定器をオンリーモードにし、常に計測値を吐き出すように設定
 TeraTermでは計測値受信を確認。
 C#側ではDataReceiveイベントが発生しない。

・com0comにて、C#-TeraTerm間での送受信を確認。
 TeraTermから文字列+LFで、C#のDataReceiveイベントが発生を確認。

上記より、H/Wの問題は無いと思っており、抽象的な表現ですが、C#環境で測定器の受信バッファを覗けていないように感じます。
フロー制御関係もいじりましたが、変化も無く・・・

お力添え、お願いいたします。
 
引用返信 編集キー/
■96616 / inTopicNo.7)  Re[4]: SerialPort 受信できない
□投稿者/ tkit (4回)-(2020/12/24(Thu) 14:59:19)
現在のコードです。

using System;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Component1 COM = new Component1();
            if (COM.Open() == false) { return; }
            //if (COM.Send() == false) { return; }
            Console.WriteLine("WAIT");
            Console.ReadKey();
            //if (COM.Receive() == false) { return; }
            COM.Close();
        }
    }
}


using System;
using System.ComponentModel;
using System.IO.Ports;
using System.Text;

namespace ConsoleApp1
{
    public partial class Component1 : Component
    {

        public Component1()
        {
            InitializeComponent();
            serialPort1.PortName = "COM6";
            
            serialPort1.BaudRate = 9600;
            serialPort1.DataBits = 8;
            serialPort1.Parity = Parity.None;
            serialPort1.StopBits = StopBits.One;
            serialPort1.Handshake = Handshake.None;
            serialPort1.RtsEnable = false;
            serialPort1.DiscardNull = false;
            serialPort1.WriteTimeout = 1000;
            serialPort1.ReadTimeout = 20000;
            serialPort1.NewLine = "\n";
            
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
        }

        public Component1(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }

        public bool Open()
        {
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
                Console.WriteLine("既に開いています。");
                Console.ReadKey();
                return false;
            }
            try
            {
                serialPort1.Open();
                Console.WriteLine("OPEN");
                if(serialPort1.BreakState==true)
                {
                    Console.WriteLine(serialPort1.BreakState);
                    serialPort1.BreakState = false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
                return false;
            }
        }

        public bool Send()
        {
            try
            {
                serialPort1.Write("CONF:VOLT:AC" + "\n");
                Console.WriteLine("SEND");
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
                return false;
            }
         }

        public bool Receive()
        {
            try
            {
                string rec = serialPort1.ReadLine();
                Console.WriteLine("RECEIVE:" + rec);
                Console.ReadKey();
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
                return false;
            }
            
        }

        public void Close()
        {
            serialPort1.DiscardOutBuffer();
            serialPort1.Close();
            Console.WriteLine("CLOSE");
            Console.ReadKey();
        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            try
            {
                string rec = serialPort1.ReadLine();
                Console.WriteLine("RECEIVE:"+rec);
                //Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
                
            }
        }
    }
}

引用返信 編集キー/
■96618 / inTopicNo.8)  Re[5]: SerialPort 受信できない
□投稿者/ みい (123回)-(2020/12/24(Thu) 15:33:36)
受信関連のプロパティ
ReceivedBytesThresholdプロパティ
受信イベントが発生するバイト数
既定は1のはずなので大丈夫だとは思いますが、
念のため指定してみてください。
ReadBufferSizeプロパティ
受信バッファサイズ
既定値は 4096 なので特に指定しなくても大丈夫なはず

引用返信 編集キー/
■96619 / inTopicNo.9)  Re[5]: SerialPort 受信できない
□投稿者/ 774RR (855回)-(2020/12/24(Thu) 15:59:54)
USB/COM 変換器 (CDC) を使ったりしてると RS232 側転送と USB 側 BULK 転送の時間差で
受信データが *+1.234V<CR> であったとしても PC ソフトから見て受信完了判定が

*+1 の3バイト受信 で1イベント発生(1回の受信完了判定)
.2 の2バイト受信 で1イベント発生(1回の受信完了判定)
34V<CR> の4バイト以下略
その後タイムアウト判定
になったりするのはよくある話なので、オイラは ReadLine() を使わない主義。

タイムアウトにならない範囲で Read() で受け取れたバイト列は全部結合して
タイムアウトになったら今回1回の受信を終了
ってしたほうが安定すると思う。

ってか通信プロトコル上の送受信データが全部 ASCII 7bit の範囲内であることは要確認
C# / VB.NET の内部コードは UTF-16 なので serialPort1.Write("A"); の内部処理は
U+0041 の UTF-16LE 表記 41 00 を ASCII の 41 に変換してバス上 41 が送信される

serialPort1.Read() や ReadLine() の内部処理は
バス上 62 を受信したら ASCII の 62 と思って UTF-16LE の 62 00 に変換し "b" を得る

だから「真にバイト列」が必要な場合に C# の System.Char や System.String を使っちゃうと
いつ誰がどこでどんな変換をするかを意識しておかないと思わぬところでバグるよ。
通信内容が全部 ASCII 7bit 範囲なら問題ないけど

ASCII 8bit 文字っつか値がありうるなら、オイラは byte をお勧めするっス

引用返信 編集キー/
■96620 / inTopicNo.10)  Re[6]: SerialPort 受信できない
□投稿者/ tkit (5回)-(2020/12/24(Thu) 16:01:56)
No96618 (みい さん) に返信
> 受信関連のプロパティ
> ReceivedBytesThresholdプロパティ
> 受信イベントが発生するバイト数
> 既定は1のはずなので大丈夫だとは思いますが、
> 念のため指定してみてください。
> ReadBufferSizeプロパティ
> 受信バッファサイズ
> 既定値は 4096 なので特に指定しなくても大丈夫なはず
>

上記の通りコンストラクタ内に記述しましたがダメでした。
記述前にプロパティを確認しましたが、同値でした。
引用返信 編集キー/
■96621 / inTopicNo.11)  Re[7]: SerialPort 受信できない
□投稿者/ shu (1239回)-(2020/12/24(Thu) 16:21:44)
No96620 (tkit さん) に返信

InitializeComponent内で
serialPort1のインスタンスを作成していると思いますが
その中での設定に問題はないでしょうか?

InitializeComponentを呼ぶのを止め
serialPort1.PortName = "COM6";
の前でインスタンスを作成するようにした場合はどうでしょうか?
引用返信 編集キー/
■96622 / inTopicNo.12)  Re[8]: SerialPort 受信できない
□投稿者/ tkit (6回)-(2020/12/24(Thu) 17:13:14)
No96621 (shu さん) に返信
> ■No96620 (tkit さん) に返信
>
> InitializeComponent内で
> serialPort1のインスタンスを作成していると思いますが
> その中での設定に問題はないでしょうか?
>
> InitializeComponentを呼ぶのを止め
> serialPort1.PortName = "COM6";
> の前でインスタンスを作成するようにした場合はどうでしょうか?

やってみましたが、結果は同じく受信できませんでした。
.NETFrameworkのヴァージョンの影響やVSが壊れてるってことはあり得るでしょうか。

引用返信 編集キー/
■96629 / inTopicNo.13)  Re[9]: SerialPort 受信できない
□投稿者/ sima (1回)-(2020/12/26(Sat) 11:00:35)
No96622 (tkit さん) に返信
No96615 で提示されているソースで

シリアル通信を無手順(垂れ流し)で行おうとしているように見えますが、通信相手の装置が
垂れ流しで送受信できることは確認できているのでしょうか?

シリアル通信で、片方だけが受信する場合は無手順(垂れ流し)で問題ない場合がありますが、
通信がうまくいかない場合は DTR/DSR や CTS/RTS やの制御信号を使うことを意識して自分の
制御線の状態と相手の制御線の状態とを確認してみてはいかがでしょうか?
場合によっては相手の装置が自分の状態を示すのに RI や DCD も使っているかもしれません。

通常は 232C ケーブルはヌルモデム配線になっているものを使うでしょうから、ケーブルの
配線図から相互の信号線の結線関係はわかると思います。


引用返信 編集キー/
■96632 / inTopicNo.14)  Re[10]: SerialPort 受信できない
□投稿者/ tkit (7回)-(2020/12/28(Mon) 08:48:47)
No96629 (sima さん) に返信
>
> シリアル通信を無手順(垂れ流し)で行おうとしているように見えますが、通信相手の装置が
> 垂れ流しで送受信できることは確認できているのでしょうか?
>
> シリアル通信で、片方だけが受信する場合は無手順(垂れ流し)で問題ない場合がありますが、
> 通信がうまくいかない場合は DTR/DSR や CTS/RTS やの制御信号を使うことを意識して自分の
> 制御線の状態と相手の制御線の状態とを確認してみてはいかがでしょうか?
> 場合によっては相手の装置が自分の状態を示すのに RI や DCD も使っているかもしれません。
>
> 通常は 232C ケーブルはヌルモデム配線になっているものを使うでしょうから、ケーブルの
> 配線図から相互の信号線の結線関係はわかると思います。
>
>

アドバイスありがとうございます。

結果から申しますと、
「serialPort1.DtrEnable = true;」
の追記で送受信出来ました。

私のRS232Cに対する知識の無さと思い込みでCTS/RTSとDTR/DSRを混同しておりました。
改めて、計器の仕様、ピンアサイン等を確認、フロー制御とは何ぞや、を確認し気付きました。

C#を初めて触りだしましたが、この問題を解決していく中、皆様のアドバイスのおかげがあり、
一歩深く構成が理解できたと思っております。

改めて、皆様にお礼申し上げます。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -