1

ロボットを制御するアプリケーションを書いています。ポートを開閉するボタンクリックメソッドがあります。

private void cONNECTToolStripMenuItem_CheckStateChanged(
                 object sender, EventArgs e)
{
    if (cONNECTToolStripMenuItem.Checked)
    {
        cONNECTToolStripMenuItem.Text = "DISCONNECT!";
        ports.connect();
    }
    else
    {
        cONNECTToolStripMenuItem.Text = "CONNECT!";
        ports.disconnect();
    }
}

さらに、シリアルポートからのデータが受信された後に呼び出される DataReceived イベントハンドラーがあります。

private void serialPort_DataReceived(
                 object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    string data = sp.ReadExisting();

    mainForm.addData(data);
} 

このイベント ハンドラーが addData(data) 関数を呼び出そうとしたとき

public void addData(string data)
{
    //if (!this.Disposing || !this.IsDisposed || 
    //    !this.listBox1.Disposing || !this.listBox1.IsDisposed)
    if (this.listBox1.InvokeRequired)
    {
        SetTextCallback d = new SetTextCallback(addData);
        this.Invoke(d, new object[] { data });
    }
    else
        listBox1.Items.Add(data);         
}

クロススレッド エラーが発生したため、関数の内容を InvokeRequired 条件にラップしました。

1. ports.disconnect() 関数を呼び出そうとするとプログラムがクラッシュする

public void disconnect()
{
    serialPort.Close();
}

ポート クラス:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;

namespace server_client
{
    public class COM_Port
    {
        private Main_Form mainForm;
        public SerialPort serialPort;

        //MySQL - 1, XML File - 2, None - 0
        public int writeStatus;

        public COM_Port(Main_Form form)
        {
            mainForm = form;

            //by default niekur neirasineja nebent pasirenka
            writeStatus = 0;

            //sukuriam serialPort kintamaji
            serialPort = new SerialPort();

            //nustatom duomenis portui
            serialPort.BaudRate = 9600;
            serialPort.DataBits = 8;
            serialPort.StopBits = StopBits.One;
            serialPort.ReadTimeout = 500;
            serialPort.WriteTimeout = 500;


        }

        ~COM_Port()
        {
            disconnect();
            serialPort.Dispose();
        }

        public void connect()
        {
            if (!serialPort.IsOpen)
                if (serialPort.PortName != "") 
                    serialPort.Open();
                else
                    MessageBox.Show("Please choose COM Port in settings.");
        }

        public void disconnect()
        {
            //serialPort.DiscardInBuffer();
            //serialPort.DiscardOutBuffer();
            serialPort.Close();
        }

        public void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            string data = null;

            SerialPort sp = (SerialPort)sender;

            if (sp.IsOpen)
                data = sp.ReadExisting();
            else
                data = null;

            //perduoda duomenis atvaizdavimui i maina
            if (data != null)
            {
                mainForm.addData(data);

                switch (writeStatus)
                {
                    //neirasyti
                    case 0:
                        break;
                    //irasyti i mysql
                    case 1:
                        MySQL mysql = new MySQL();
                        break;
                    //irasyti i xml file
                    case 2:
                        File file = new File();
                        break;
                    default:
                        break;
                }
            }
        } 
    }
}

ポートを閉じた後も、ロボットはまだデータを送信しており、DataReceived イベント ハンドラはシリアル ポートのバッファからそのデータを取得しようとしています。

あなたの助けのために、このラブレターを読んでくれてありがとう:)。

4

3 に答える 3

1

私は次のハンドラを使用します

private void SerialComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
 if (!SerialPortPendingClose)
 { SerialComPort.Read(InputData, 0, 512); }
 //Do something with InputData
 else
 { SerialComPort.DataReceived -= SerialComPort_DataReceived;} //to ensure this will be called only once
}
于 2015-06-05T05:49:31.787 に答える
1

これは、大量のデータを受信した場合に発生します。DataReceivedイベント ハンドラーは常にビジーで、バッファーを読み取ろうとします。このハンドラでReadExisting()は、実行時間が最も長くなります。DataReceivedハンドラの実行中はポートを閉じることができません。ReadExisting()この待機時間中にDataReceivedイベントが再び発生するため、終了を待つことはできません。

ReadExisting()したがって、たとえば次のように、ポートを閉じる前に呼び出しを停止する必要があります。

最初に新しいSerialPortインスタンスを構築します

 SerialComPort = new SerialPort();
 SerialComPort.DataReceived += new SerialDataReceivedEventHandler(SerialComPort_DataReceived);
 SerialComPort.ReadTimeout = 100; //[ms] Time out if Read operation does not finish
 bool SerialPortPendingClose=false;

次に、DataReceivedハンドラーは次のようになります。

byte[] InputData = new byte[512]; 
private void SerialComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
     if (!SerialPortPendingClose)
     { SerialComPort.Read(InputData, 0, 512); }
     //Do something with InputData
}

最後に、以下を使用してポートを閉じます。

SerialPortPendingClose = true;
Thread.Sleep(SerialComPort.ReadTimeout); //Wait for reading threads to finish
SerialComPort.Close();
SerialPortPendingClose = false;
于 2015-01-21T17:28:18.990 に答える