при получении данных событие [serialport_datareceived] происходит более одного раза (с использованием виртуального последовательного порта)

Я пытаюсь отправить данные и получить через последовательную связь, используя программу виртуального последовательного порта. Но вот проблема... Предположим, что A передает данные, а B принимает данные.

Когда A отправляет данные в B, B получает данные дважды (событие serialport_datareceived происходит дважды!).

Каждый раз, когда B закрывает и снова открывает последовательный порт, событие serialport_datareceived увеличивается.

Я не могу понять, почему это происходит.

A(transmit)
BaudRate = 9600
Parity = None
DataBits = 8
StopBits = 1

    public transmit()
    {
        InitializeComponent();
        foreach (String s in System.IO.Ports.SerialPort.GetPortNames())
        {
            cBoxPort.Items.Add(s);          
        }
    }
    private void CBoxBaudRate_SelectedIndexChanged(object sender, EventArgs e)
    {
        serialPort1.BaudRate = Convert.ToInt32(cBoxBaudRate.Text);                          
    }
    private void CBoxStopBits_SelectedIndexChanged(object sender, EventArgs e)
    {
        serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cBoxStopBit.Text);   
    }
    private void CBoxDataBits_SelectedIndexChanged(object sender, EventArgs e)
    {
        serialPort1.DataBits = Convert.ToInt32(cBoxDataBits.Text);                          
    }
    private void CBoxParityBits_SelectedIndexChanged(object sender, EventArgs e)
    {
        serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), cBoxParity.Text);           
    }

    private void btnConnect_Click(object sender, EventArgs e)
    {
        try
        {
            serialPort1.PortName = cBoxPort.Text;
            serialPort1.BaudRate = Convert.ToInt32(cBoxBaudRate.Text);
            serialPort1.DataBits = Convert.ToInt32(cBoxDataBits.Text);
            serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cBoxStopBit.Text);
            serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), cBoxParity.Text);
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
            serialPort1.Open();

            txtReceive.AppendText("Connected\n");   
            btnConnect.Enabled = false;             
            btnClose.Enabled = true;
            btnSend.Enabled = true;
        }

        catch (Exception ex)
        {
            return;
        }
    }
    private void btnClose_Click(object sender, EventArgs e)
    {
        if (serialPort1.IsOpen)
        {
            serialPort1.Close();                        
            btnClose.Enabled = false;
            btnConnect.Enabled = true;
            btnSend.Enabled = false;
            txtReceive.AppendText("Disconnected\n");  
        }
    }

    private void btnSend_Click(object sender, EventArgs e)
    {
        byte[] bytesend = { 0x00 };
        Debug.WriteLine("111");
        serialPort1.Write(bytesend, 0, bytesend.Length);
    }

    private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        Debug.WriteLine("444");
    }

}

Б (получить)

    byte[] bytesend;

    //Initial Conditions(SerialPort)
    private void receive_Load(object sender, EventArgs e)
    {
        cBoxBaudRate.SelectedIndex = 0;     //BaudRate = 9600
        cBoxParity.SelectedIndex = 0;       //Parity = None
        cBoxDataBits.SelectedIndex = 0;     //DataBits = 8
        cBoxStopBit.SelectedIndex = 0;      //StopBits = 1
        cBoxPort.SelectedIndex = 1;         

        btnConnect.Enabled = true;
        btnClose.Enabled = false;
    }

    //Show usable CommPort
    public receive()
    {
        InitializeComponent();
        foreach (String s in System.IO.Ports.SerialPort.GetPortNames())
        {
            cBoxPort.Items.Add(s);
        }
    }

    //Connection
    private void btnConnect_Click(object sender, EventArgs e)
    {
        serialPort1.PortName = cBoxPort.Text;
        serialPort1.BaudRate = Convert.ToInt32(cBoxBaudRate.Text);
        serialPort1.DataBits = Convert.ToInt32(cBoxDataBits.Text);
        serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cBoxStopBit.Text);
        serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), cBoxParity.Text);
        serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
        serialPort1.Open();

        btnConnect.Enabled = false;
        btnClose.Enabled = true;
    }
    private void btnClose_Click(object sender, EventArgs e)
    {
        if (serialPort1.IsOpen)
        {
            serialPort1.Close();
            btnClose.Enabled = false;
            btnConnect.Enabled = true;
        }
    }

    private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        Debug.WriteLine("222");
    }

когда я отлаживаю этот код, вывод представляет 111 222 222. И когда я нажимаю кнопку закрытия и подключения, вывод представляет 111 222 222 222.


person kmg    schedule 14.02.2019    source источник
comment
На кнопках подключения вы подключаете событие DataReceived КАЖДЫЙ раз. Вы хотите сделать это только ОДИН РАЗ, как в событии Load() формы...   -  person Idle_Mind    schedule 14.02.2019
comment
Спасибо за ваш комментарий. а если не возражаете, не могли бы вы написать комментарий поточнее?   -  person kmg    schedule 14.02.2019
comment
Я слышал, что это происходит из-за многопоточности. Я прав? если это происходит из-за многопоточности, как это исправить?   -  person kmg    schedule 14.02.2019


Ответы (1)


Каждый раз, когда B закрывает и снова открывает последовательный порт, событие serialport_datareceived увеличивается.

Правильно, потому что, как я уже сказал, вы должны подключать событие DataReceived только ОДИН РАЗ. Каждый раз, когда вы нажимаете кнопку, добавляется другой обработчик, что приводит к многократному срабатыванию для одного приема. Это не имеет ничего общего с многопоточностью. Переместите строку, соединяющую обработчик с события нажатия кнопки, на событие Load:

private void transmit_Load(object sender, EventArgs e)
{
    serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived); // now it only gets called once
    // ... other existing code ...
}


private void btnConnect_Click(object sender, EventArgs e)
{
    try
    {
        serialPort1.PortName = cBoxPort.Text;
        serialPort1.BaudRate = Convert.ToInt32(cBoxBaudRate.Text);
        serialPort1.DataBits = Convert.ToInt32(cBoxDataBits.Text);
        serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cBoxStopBit.Text);
        serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), cBoxParity.Text);
        // serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);  // remove this line
        serialPort1.Open();

        txtReceive.AppendText("Connected\n");   
        btnConnect.Enabled = false;             
        btnClose.Enabled = true;
        btnSend.Enabled = true;
    }

    catch (Exception ex)
    {
        return;
    }
}

То же самое нужно сделать и в форме получения.

person Idle_Mind    schedule 14.02.2019
comment
Idle_Mind правильный. Вы можете написать свою программу для чтения только при нажатии кнопки или для чтения всякий раз, когда появляются данные, но не для обоих. Выберите тот, который лучше всего подходит для вашего приложения. - person skinnedKnuckles; 14.02.2019
comment
Он также мог сделать -= в своей функции закрытия. - person Baddack; 14.02.2019