เมื่อรับข้อมูล เหตุการณ์ [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 เพียงครั้งเดียวเท่านั้น แต่ละครั้งที่คุณคลิกปุ่ม ตัวจัดการอื่นจะถูกเพิ่ม ส่งผลให้มีการยิงหลายครั้งสำหรับการรับครั้งเดียว สิ่งนี้ไม่เกี่ยวอะไรกับมัลติเธรด ย้ายบรรทัดที่เชื่อมต่อตัวจัดการจากเหตุการณ์การคลิกปุ่มจนถึงเหตุการณ์โหลด:

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