繁体   English   中英

C#不断从串行端口请求和处理数据

[英]c# constantly requesting and processing data from serial port

长时间后,我需要再次编程。 我需要不断从汽车ecu(?数据)通过串行端口发送命令。

然后,我需要接收将要处理的数据,以将其显示在显示器上(想想带有诸如温度等汽车参数的赛车显示器)。 我需要经常这样做

我想知道在开始之前最好的方法是什么?

1个线程,用于不断询问和接收数据。主线程用于在屏幕上显示数据。 (将数据存储在缓冲区中并每分钟保存一次)

任何人都有任何提示指南,或者如何开始。 我测试了使用终端接收数据,并获取了数据,因此配置工作正常。

发送了? 数据=>我得到了数据。

您可以只使用SerialPort类并配置BaudRate,DataBits等。然后等待DataReceived事件触发:

public class SerialPortReader 
{
    public SerialPortReader(string yourPortName)
    {
        var serialPort = new SerialPort() {
            PortName = yourPortName,
            BaudRate = 57600; //This will control the rate at what you receive the data
         }

        serialPort.DataReceived += new SerialDataReceivedEventHandler(OnDataReceived);

        serialPort.Open();
    }
}

public void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var serialPort = (SerialPort)sender;
    // Process your data reading the stream with Read, ReadLine etc...
}

我们在SerialPort处理程序中使用的方法是,使AutoResetEvent在端口有响应时立即得到通知。

FrameWork的SerialPort类在集成的DataReceived事件中存在一些问题。 当没有完整的软件包可用时(如果您定义了答案长度),有时会触发该事件。 因此,您应该检查所需的答案长度。

我们的精简实施:

public class Serialport
{
    private SerialPort _serialPort;
    private List<byte> _buffer;
    private AutoResetEvent _autoResetEvent;
    private const int WriteTimeOut = 5;

    private event EventHandler ReceivedDataChanged;

    public Serialport()
    {
        _serialPort = new SerialPort();

        // set PortName, BaudRate etc

        _serialPort.Open();
        _serialPort.DiscardInBuffer();
        _serialPort.DiscardOutBuffer();
        _serialPort.DataReceived += ReceiveData;
    }

    private void ReceiveData(object sender, SerialDataReceivedEventArgs e)
    {
        var bytes = _serialPort.BytesToRead;

        byte[] buffer = new byte[bytes];
        if (_serialPort.IsOpen)
        {
            _serialPort.BaseStream.Read(buffer, 0, bytes);
            _buffer.AddRange(buffer);
        }

        ReceivedDataChanged?.Invoke(this, new ReceivedBytesEventArgs(_buffer.ToArray()));
        _buffer.Clear();
    }

    private void SendData(byte[] message, int answerLength)
    {
        _serialPort.ReceivedBytesThreshold = answerLength;
        _serialPort.WriteTimeout = WriteTimeOut;
        _serialPort.Write(message, 0, message.Length);
    }

    public string SendDataCommand()
    {
        if (_serialPort.IsOpen)
        {
            ReceivedDataChanged += InterpretAnswer;
            SendData(message, length);
            if (_autoResetEvent.WaitOne(100))
            {
                ReceivedDataChanged -= InterpretAnswer;
                //Data Received and interpreted and send to the caller
                return _requestAnswer;
            }

            ReceivedDataChanged -= InterpretAnswer;
        }

        return "Connection not open";
    }

    private void InterpretAnswer(object sender, EventArgs e)
    {
        // handle all interpretation
        // Set the event
        _autoResetEvent.Set();
    }
}

初始化并打开serialPort。 之后,我们连接所有需要的事件并调用SendDataCommand()方法。 此方法是从某些任务调用的公共可见方法。 这将调用方法SendData 一旦有答案,便触发事件并开始解释。 如果解释是在指定的时间内完成的( _autoResetEvent.WaitOne(msToWait) ),则结果将返回给调用方法。 这应该在单独的任务中完成,因此在等待答案时,ui不会阻塞

如前所述,这是一个非常简单的示例。 您应该在收到的SerialPort处理程序中进行更多检查,因为该事件存在一些问题。 通过这种方法,您将对业务逻辑有了更多的抽象。

希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM