向串口发送和接收数据

问题描述

我有一台麦哲伦扫描仪/秤。它通过 rs232 连接到我的电脑。当我在 ComTestSerial 程序上发送命令“S11”时,我收到了重量。但是,使用我的 vb.net 代码,我无法收到回复。结果我得到一个 TimeoutException。

发送命令的文件

Dim yy() As Byte = System.Text.Encoding.ASCII.GetBytes("S11" & vbLf)
Me.Port.Send(yy)
Dim input = Me.Port.Receive
Return Me.ExtractMeasurement(input)

从串口写入和读取的文件

public void Send(byte b)
    {
        byte[] bytes = new byte[1] { b };
        this.Send(bytes);
    }

    public void Send(byte[] bytes)
    {
        this.Send(bytes,bytes.Length);
    }

    public void Send(byte[] bytes,int offset,int count)
    {
        this._port.Write(bytes,offset,count);
    }

    public byte[] Receive()
    {
        int attempts = 1;
        Boolean dataReceived;

        try
        {
            while (!this.DataReceived && this._port.BytesToRead == 0 && attempts < 15)
            {
                System.Threading.Thread.Sleep(100);
                attempts++;
            }
        }
        finally
        {
            dataReceived = this.DataReceived;
            this.DataReceived = false;
        }

        if (!dataReceived && this._port.BytesToRead == 0) throw new TimeoutException();

        byte[] bytes = new byte[this._port.BytesToRead];
        this._port.Read(bytes,bytes.Length);

        return bytes;
    }

我不明白为什么 BytesToRead 和 BytesToWrite 在此之后保持 0._port.Write(bytes,count);

这是serialportconfig.xml文件

<PortName>COM3:</PortName>
<Baudrate>Baud_9600</Baudrate>
<DataBits>Eight</DataBits>
<Parity>None</Parity>
<StopBits>One</StopBits>
<FlowCtrl>CtsRts</FlowCtrl>

更新:我发现如果我发送 vbCr 而不是 vbLf 我有时会得到正确的响应。但问题是有时。我有时会收到 TimeoutException,有时会收到响应。我正在使用从 RS232 到 USB 的适配器。这可能是问题吗?

这里是所有与串口相关的代码

public class SerialPortAdapter
{
    #region Private Members

    private System.IO.Ports.SerialPort _port;

    private Object _dataReceivedLock = new Object();
    private Boolean _dataReceived;

    #endregion

    #region Constructor/Destructor

    public SerialPortAdapter(SerialCnfg config)
    {
        if (string.IsNullOrEmpty(config.PortName))
        {
            this._port = new System.IO.Ports.SerialPort();
        }
        else
        {
            string portName = config.PortName.TrimEnd(':');
            this._port = new System.IO.Ports.SerialPort(portName);
        }

        this._port.WriteTimeout = 2000;
        this._port.ReadTimeout = 2000;
        this._port.SetBaudrate(config.Baudrate);
        this._port.SetDataBits(config.DataBits);
        this._port.SetStopBits(config.StopBits);
        this._port.SetHandshake(config.FlowCtrl);
        this._port.SetParity(config.Parity);
    }

    ~SerialPortAdapter()
    {
        this.Close();
        this._port = null;
    }

    #endregion

    #region Public Properties

    public Boolean IsOpen
    {
        get { return this._port.IsOpen; }
    }

    public System.Text.Encoding Encoding
    {
        get { return this._port.Encoding; }
        set { this._port.Encoding = value; }
    }

    #endregion

    #region Public Methods

    public void open()
    {
        if (this.IsOpen) return;

        this.DataReceived = false;
        this.AttachPortHandlers();
        this._port.open();
    }

    public void Close()
    {
        if (!this.IsOpen) return;

        this._port.Close();
        this.DetachPortHandlers();
        this.DataReceived = false;
    }

    public void Send(byte b)
    {
        byte[] bytes = new byte[1] { b };
        this.Send(bytes);
    }

    public void Send(byte[] bytes)
    {
        this.Send(bytes,bytes.Length);

        return bytes;
    }

    #endregion

    #region Private Properties

    private Boolean DataReceived
    {
        get
        {
            lock (this._dataReceivedLock)
            {
                return this._dataReceived;
            }
        }
        set
        {
            lock (this._dataReceivedLock)
            {
                this._dataReceived = value;
            }
        }
    }

    #endregion

    #region Initialization/Finalization

    private void AttachPortHandlers()
    {
        this._port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.OnDataReceived);
    }

    private void DetachPortHandlers()
    {
        this._port.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(this.OnDataReceived);
    }

    #endregion

    #region Event Handlers

    private void OnDataReceived(Object sender,System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        this.DataReceived = true;
    }

    #endregion
}

解决方法

根据您发布的代码,您正在尝试处理自己的超时异常。 SerialPort 类有自己的内置超时(即,ReadTimeout、WriteTimeout),您可以在构造函数中设置它们。因此,您不需要其他方法来处理超时,因为它是多余的。此外,请远离 System.Threading.Sleep 方法,因为它会极大地浪费资源 Why is Thread.Sleep so harmful

我建议您稍微重构一下您的代码,以摆脱自我强加的 Throw TimeoutException。

这里只是一个建议:

public byte[] Receive()
{
    
    try
    {
        byte[] bytes = new byte[]{};

        while(_port.BytesToRead > 0)
        {
            bytes = new byte[this._port.BytesToRead];
            this._port.Read(bytes,bytes.Length);
        }
    }
    catch (TimeoutException ex)
    {
       Console.WriteLine(ex.Message);
    }
    finally
    {
        this.DataReceived = false;
    }

    return bytes;
}
,

如果您重新发送请求重量的命令(S11),麦哲伦似乎可以工作。所以我的解决方案是每当我在 this._port.Write(bytes,offset,count) 之后有 _port.bytesToRead=0 时,然后我重新发送命令 S11。最终,它会响应正确的结果。