22

COM10 に接続された外部センサーから受信したデータを収集する小さなアプリケーションを作成しようとしています。ポートを開き、for ループを使用して一定期間データをファイルにストリーミングする小さな C# コンソール オブジェクトとアプリケーションを正常に作成しました。

このアプリケーションを変換して、代わりに dataReceived イベントを使用してストリーミングしたいと考えています。Top 5 SerialPort Tipsを読んだ後でも、これを機能させることができず、何が欠けているのかわかりません。すべてのコードが Main にあるようにコンソール アプリケーションを書き直して、以下に貼り付けます。ハードウェアによってポートにデータが送信されていることがわかっているにもかかわらず、イベント ハンドラー port_OnReceiveDatazz が呼び出されない理由を教えてください。

ありがとう

@Gabe@Jason Down、および@abatishchevのすべての提案に感謝します。私は困惑しており、イベントハンドラーを機能させることができないようです。端末と関係があるのか​​もしれません。スレッドでポートを読み取り、データを直接ファイルにストリーミングするだけで済みます。


コード


namespace serialPortCollection
{   class Program
    {
        static void Main(string[] args)
        {
            
            const int bufSize = 2048;
            Byte[] buf = new Byte[bufSize]; //To store the received data.

            SerialPort sp = new SerialPort("COM10", 115200);
            sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler

            sp.Open();
            sp.WriteLine("$"); //Command to start Data Stream

            // Wait for data or user input to continue.
            Console.ReadLine();
           
            sp.WriteLine("!"); //Stop Data Stream Command
            sp.Close();
        }
        
       // My Event Handler Method
        private static void port_OnReceiveDatazz(object sender, 
                                   SerialDataReceivedEventArgs e)
        {
            SerialPort spL = (SerialPort) sender;
            const int bufSize = 12;
            Byte[] buf = new Byte[bufSize];
            Console.WriteLine("DATA RECEIVED!");
            Console.WriteLine(spL.Read(buf, 0, bufSize));
        }
    }
}
4

8 に答える 8

15

あなたの問題は次の行だと思います: **

sp.DataReceived + = port_OnReceiveDatazz;

すべきではありません:

sp.DataReceived + = new SerialDataReceivedEventHandler(port_OnReceiveDatazz);

**気にしないでください、構文は問題ありません(私が最初にこの質問に答えたとき、ショートカットを認識していませんでした)。

また、シリアルポートに対して次のオプションをオンにする必要があるという提案もあります。

sp.DtrEnable = true;    // Data-terminal-ready
sp.RtsEnable = true;    // Request-to-send

また、ハンドシェイクをRequestToSendに設定する必要がある場合もあります(ハンドシェイク列挙を介して)。


アップデート:

最初にポートを開いてから、イベントハンドラーを割り当てる必要があるという提案を見つけました。多分それはバグですか?

したがって、これの代わりに:

sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);
sp.Open();

これを行う:

sp.Open();
sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);

それがどうなるか教えてください。

于 2009-01-21T18:54:04.087 に答える
8

まず、現在使用しているコンストラクターではなく、次のコンストラクターを使用することをお勧めします。

new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);

次に、本当にこのコードを削除する必要があります:

// Wait 10 Seconds for data...
for (int i = 0; i < 1000; i++)
{
    Thread.Sleep(10);
    Console.WriteLine(sp.Read(buf,0,bufSize)); //prints data directly to the Console
}

代わりに、ユーザーがキーなどを押すまでループします。

namespace serialPortCollection
{   class Program
    {
        static void Main(string[] args)
        {
            SerialPort sp = new SerialPort("COM10", 115200);
            sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler

            sp.Open();
            sp.WriteLine("$"); //Command to start Data Stream

            Console.ReadLine();

            sp.WriteLine("!"); //Stop Data Stream Command
            sp.Close();
        }

       // My Event Handler Method
        private static void port_OnReceiveDatazz(object sender, 
                                   SerialDataReceivedEventArgs e)
        {
            SerialPort spL = (SerialPort) sender;
            byte[] buf = new byte[spL.BytesToRead];
            Console.WriteLine("DATA RECEIVED!");
            spL.Read(buf, 0, buf.Length);
            foreach (Byte b in buf)
            {
                Console.Write(b.ToString());
            }
            Console.WriteLine();
        }
    }
}

また、データ受信イベントハンドラーのリビジョンに注意してください。実際にバッファーを出力する必要があります。

更新1


私は自分のマシンで次のコードを正常に実行しました(COM33とCOM34の間にヌルモデムケーブルを使用)

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread writeThread = new Thread(new ThreadStart(WriteThread));
            SerialPort sp = new SerialPort("COM33", 115200, Parity.None, 8, StopBits.One);
            sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler

            sp.Open();
            sp.WriteLine("$"); //Command to start Data Stream

            writeThread.Start();

            Console.ReadLine();

            sp.WriteLine("!"); //Stop Data Stream Command
            sp.Close();
        }

        private static void port_OnReceiveDatazz(object sender, 
                                   SerialDataReceivedEventArgs e)
        {
            SerialPort spL = (SerialPort) sender;
            byte[] buf = new byte[spL.BytesToRead];
            Console.WriteLine("DATA RECEIVED!");
            spL.Read(buf, 0, buf.Length);
            foreach (Byte b in buf)
            {
                Console.Write(b.ToString() + " ");
            }
            Console.WriteLine();
        }

        private static void WriteThread()
        {
            SerialPort sp2 = new SerialPort("COM34", 115200, Parity.None, 8, StopBits.One);
            sp2.Open();
            byte[] buf = new byte[100];
            for (byte i = 0; i < 100; i++)
            {
                buf[i] = i;
            }
            sp2.Write(buf, 0, buf.Length);
            sp2.Close();
        }
    }
}

更新2


最近この質問のすべてのトラフィックを考えると。シリアルポートが正しく構成されていないか、デバイスが応答していないのではないかと思い始めています。

他の手段を使用してデバイスとの通信を試みることを強くお勧めします(私はハイパーターミナルを頻繁に使用します)。次に、機能するセットが見つかるまで、これらすべての設定(ビットレート、パリティ、データビット、ストップビット、フロー制御)を試してみることができます。デバイスのドキュメントでも、これらの設定を指定する必要があります。それらを理解したら、.NETSerialPortがこれらの設定を使用するように適切に構成されていることを確認します。

シリアルポートの設定に関するヒント:

次のコンストラクターを使用する必要があると言ったとき、必ずしもそれらのパラメーターではなく、その関数を使用することを意味していることに注意してください。デバイスのパラメータを入力する必要があります。以下の設定は一般的ですが、デバイスによって異なる場合があります。

new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);

また、デバイスと同じフロー制御を使用するように.NET SerialPortを設定することも重要です(他の人が以前に述べたように)。あなたはここでより多くの情報を見つけることができます:

http://www.lammertbies.nl/comm/info/RS-232_flow_control.html

于 2009-01-21T19:11:57.703 に答える
4

以前は動作していたモデムでまったく同じ問題が発生していましたが、ある日、DataReceived イベントの発生が停止しました。

私の場合の解決策は、非常にランダムに、RTSを有効にすることでした。

sp.RtsEnable = true;

なぜそれがこの特定のキットで機能したのか(実際にはコミュニケーションマンではありません)、なぜ機能して停止したのかわかりませんが、いつか他の誰かを助けるかもしれないので、念のため投稿してください...

于 2009-06-08T12:36:26.960 に答える
3

ちなみに、イベントハンドラーで次のコードを使用できます。

switch(e.EventType)
{
  case SerialData.Chars:
  {
    // means you receives something
    break;
  }
  case SerialData.Eof:
  {
    // means receiving ended
    break;
  }
}
于 2009-01-21T18:57:17.293 に答える
1

コンソール アプリケーションを使用しており、イベント ループが実行されていないため、これは機能しないと思います。イベント処理に使用されるイベント ループ/メッセージ ポンプは、Winforms アプリケーションの作成時に自動的にセットアップされますが、コンソール アプリの場合はセットアップされません。

于 2011-03-14T17:53:42.310 に答える
1

Console.ReadLine実際、コールバックの をブロックしている可能性が非常に高いConsole.Writelineです。MSDN のサンプルは、(コンソールをロックしない) ReadKey を使用することを除いて、ほとんど同じに見えます。

于 2014-03-12T13:28:50.247 に答える
0

.NET/C# および COM9 より上位の COM ポートを使用すると問題が発生することに注意してください。

参照: HOWTO: COM9 より大きいシリアル ポートを指定する

基礎となる CreateFile メソッドでサポートされている "\\.\COM10" という形式の回避策がありますが、.NET ではその回避策の形式を使用できません。SerialPort コンストラクターも PortName プロパティも、"\" で始まるポート名を許可しません。

C#/.NET で COM10 への信頼できる通信を得るのに苦労しています。たとえば、COM9 と COM10 にデバイスがある場合、COM10 向けのトラフィックは COM9 のデバイスに送信されます。COM9 上のデバイスを削除すると、COM10 トラフィックは COM10 上のデバイスに送信されます。

CreateFile によって返されたハンドルを使用して C#/.NET スタイルの SerialPort オブジェクトを作成する方法をまだ理解していません。その方法を知っていれば、C# から COM10+ を問題なく使用できると思います。

于 2016-10-02T04:45:19.967 に答える