0

我的程序从串口获取不可靠数据时遇到问题,我相信https://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport#comments

本文有一些答案 - bytestoread 值似乎不稳定,当数据存在时并不总是调用回调,并且所有默认串行端口功能都不可靠,包括 datareceived 事件。正是我在这个程序中所经历的。事实上,在所有关于串行端口的微软文档中,都有关于功能失败的免责声明和说明。当这些问题出现在您的应用程序中时,它没有解决这些问题。

但是,当我尝试使用文章中提供的解决方案时,它似乎永远输出相同的第一个字节:“pppppppppppppppppppppppppppp”我可以确认收到的第一个字节实际上是“p”,但为什么它没有删除那个字节在阅读并继续之后,或收到任何字节之后,我不知道。据我所知,它与文章中提出的解决方案完全相同。这是代码:

private void Form1_Shown(object sender, EventArgs e)
    {
        try
        {
            sp.Open();
            SPDataHelper();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }


private void SPDataHelper()
    {
        byte[] buffer = new byte[8000];
        Action kickoffRead = null;

        kickoffRead = delegate
        {
            sp.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
            {
                try
                {
                    int actualLength = sp.BaseStream.EndRead(ar);
                    byte[] received = new byte[actualLength];
                    Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
                    sp_DataReceived(System.Text.Encoding.UTF8.GetString(received));//not called by the actual serialport anymore
                }
                catch (IOException exc)
                {
                    WriteUUTWindow("Exception: "+exc.ToString());
                }
                kickoffRead();
            }, null);
        };
        kickoffRead();
    }

当我在赋值后在“实际长度”上放置一个断点时,它显示为 1,这表明它在第一个字节之后永远不会读取。之后再也不会到达该分配和回调的断点,但应用程序继续发送垃圾邮件“p”。知道这里发生了什么吗?

4

1 回答 1

2

如果您有兴趣使用BeginRead,请尝试以下方法 - 已使用条形码扫描仪进行测试:

创建一个类(名称:HelperSerialPort.cs)

选项 1

HelperSerialPort.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Ports;
using System.Diagnostics;

namespace SerialPortTest
{
    public enum PortBaudRate : int
    {
        Baud1200 = 1200,
        Baud2400 = 2400,
        Baud4800 = 4800,
        Baud9600 = 9600,
        Baud14400 = 14400,
        Baud19200 = 19200,
        Baud28800 = 28800,
        Baud38400 = 38400,
        Baud56000 = 56000,
        Baud57600 = 57600,
        Baud76800 = 76800,
        Baud115200 = 115200,
        Baud128000 = 128000,
        Baud230400 = 230400,
        Baud250000 = 250000,
        Baud256000 = 256000
    };

    public class HelperSerialPort
    {
        public SerialPort Port { get; private set; } = null;

        private string _dataReceived = string.Empty;

        public HelperSerialPort(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
        {
            Initialize(portName, baudRate);
        }

        private void Initialize(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
        {
            //create new instance
            this.Port = new SerialPort();

            //set properties
            Port.BaudRate = (int)baudRate;
            Port.DataBits = 8;
            Port.Parity = Parity.None; //use 'None' when DataBits = 8; if DataBits = 7, use 'Even' or 'Odd'
            Port.DtrEnable = true; //enable Data Terminal Ready
            Port.Handshake = Handshake.None;
            Port.PortName = portName;
            Port.ReadTimeout = 200; //used when using ReadLine
            Port.RtsEnable = true; //enable Request to send
            Port.StopBits = StopBits.One;
            Port.WriteTimeout = 50;

            //open
            Port.Open();

            Listen();
        }

        private void Listen()
        {
            byte[] buffer = new byte[65536];

            IAsyncResult result = Port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
            {
                try
                {
                    if (Port.IsOpen)
                    {
                        int bytesRead = Port.BaseStream.EndRead(ar);

                        byte[] received = new byte[bytesRead];
                        Buffer.BlockCopy(buffer, 0, received, 0, bytesRead);

                        _dataReceived = System.Text.Encoding.UTF8.GetString(received);
                        Debug.WriteLine("Info: " + DateTime.Now.ToString("HH:mm:ss:fff") + " - _dataReceived: " + _dataReceived);

                        Listen();
                    }
                    
                }
                catch (IOException ex)
                {
                    Debug.WriteLine("Error (Listen) - " + ex.Message);
                }
            }, null);
        }

        public void Dispose()
        {
            if (Port != null)
            {
                Port.Close();
                Port.Dispose();

                Port = null;
            }
        }
    }
}

更新

这是另一个似乎也可以正常工作的版本-它使用了您的代码的稍微修改的版本。

选项 2

HelperSerialPort.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Ports;
using System.Diagnostics;

namespace SerialPortTest
{
    public enum PortBaudRate : int
    {
        Baud1200 = 1200,
        Baud2400 = 2400,
        Baud4800 = 4800,
        Baud9600 = 9600,
        Baud14400 = 14400,
        Baud19200 = 19200,
        Baud28800 = 28800,
        Baud38400 = 38400,
        Baud56000 = 56000,
        Baud57600 = 57600,
        Baud76800 = 76800,
        Baud115200 = 115200,
        Baud128000 = 128000,
        Baud230400 = 230400,
        Baud250000 = 250000,
        Baud256000 = 256000
    };


    public class HelperSerialPort
    {
        public SerialPort Port { get; private set; } = null;

        private string _dataReceived = string.Empty;

        public HelperSerialPort(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
        {
            Initialize(portName, baudRate);
        }

        private void Initialize(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
        {
            //create new instance
            this.Port = new SerialPort();

            //set properties
            Port.BaudRate = (int)baudRate;
            Port.DataBits = 8;
            Port.Parity = Parity.None; //use 'None' when DataBits = 8; if DataBits = 7, use 'Even' or 'Odd'
            Port.DtrEnable = true; //enable Data Terminal Ready
            Port.Handshake = Handshake.None;
            Port.PortName = portName;
            Port.ReadTimeout = 200; //used when using ReadLine
            Port.RtsEnable = true; //enable Request to send
            Port.StopBits = StopBits.One;
            Port.WriteTimeout = 50;

            //open
            Port.Open();

            SPDataHelper();
        }


        private void SPDataHelper()
        {
            byte[] buffer = new byte[65536];
            Action kickoffRead = null;

            kickoffRead = delegate
            {
                IAsyncResult result = Port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
                {
                    try
                    {
                        if (Port.IsOpen)
                        {
                            int bytesRead = Port.BaseStream.EndRead(ar);

                            byte[] received = new byte[bytesRead];
                            Buffer.BlockCopy(buffer, 0, received, 0, bytesRead);

                            _dataReceived = System.Text.Encoding.UTF8.GetString(received);
                            Debug.WriteLine("Info: " + DateTime.Now.ToString("HH:mm:ss:fff") + " - _dataReceived: " + _dataReceived);

                            kickoffRead();
                        }

                    }
                    catch (IOException ex)
                    {
                        Debug.WriteLine("Error (SPDataHelper) - " + ex.Message);
                    }
                }, null);
            };

            kickoffRead();
        }

        public void Dispose()
        {
            if (Port != null)
            {
                Port.Close();
                Port.Dispose();

                Port = null;
            }
        }
    }
}

选项 3

这是一个使用 SerialPort 的选项DataReceived

HelperSerialPort.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Ports;
using System.Diagnostics;

namespace SerialPortTest
{
    public enum PortBaudRate : int
    {
        Baud1200 = 1200,
        Baud2400 = 2400,
        Baud4800 = 4800,
        Baud9600 = 9600,
        Baud14400 = 14400,
        Baud19200 = 19200,
        Baud28800 = 28800,
        Baud38400 = 38400,
        Baud56000 = 56000,
        Baud57600 = 57600,
        Baud76800 = 76800,
        Baud115200 = 115200,
        Baud128000 = 128000,
        Baud230400 = 230400,
        Baud250000 = 250000,
        Baud256000 = 256000
    };

    public class HelperSerialPort : IDisposable 
    {
        public SerialPort Port { get; private set; } = null;

        private string _dataReceived = string.Empty;

        public HelperSerialPort(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
        {
            Initialize(portName, baudRate);  
        }

        private void Initialize(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
        {
            //create new instance
            this.Port = new SerialPort();

            //set properties
            Port.BaudRate = (int)baudRate;
            Port.DataBits = 8;
            Port.Parity = Parity.None; //use 'None' when DataBits = 8; if DataBits = 7, use 'Even' or 'Odd'
            Port.DtrEnable = true; //enable Data Terminal Ready
            Port.Handshake = Handshake.None;
            Port.PortName = portName;
            Port.ReadTimeout = 200; //used when using ReadLine
            Port.RtsEnable = true; //enable Request to send
            Port.StopBits = StopBits.One;
            Port.WriteTimeout = 50;

            //subscribe to events
            Port.DataReceived += Port_DataReceived;
            Port.ErrorReceived += Port_ErrorReceived;

            //open
            Port.Open();

        }

        private void Port_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            Debug.WriteLine("Error: (sp_ErrorReceived) - " + e.EventType);
        }

        private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            _dataReceived = Port.ReadExisting();
            Debug.WriteLine("Info: " + DateTime.Now.ToString("HH:mm:ss:fff") + " - _dataReceived: " + _dataReceived);
        }

        public void Dispose()
        {
            if (Port != null)
            {
                //unsubscribe from events
                Port.DataReceived -= Port_DataReceived;
                Port.ErrorReceived -= Port_ErrorReceived;

                Port.Close();
                Port.Dispose();

                Port = null;
            }
        }
    }
}

用法

HelperSerialPort helper = new HelperSerialPort("COM1");

注意:确保Dispose在您完成 SerialPort 后调用。

于 2021-08-16T17:38:55.910 回答