0

我需要事件,它将在收到整行后调用我的函数,而不仅仅是一个字节。

.NET 中的 SerialPort 对象有 3 个事件:DataReceived、ErrorReceived、PinChanged。

当我使用 DataReceived 时 - 事件在 1 个字节后“触发”,或者在“ReceiveByteThreshold”属性中定义的“x”个字节后“触发”。线长可能会有所不同,所以我无法预测“x”。

有人可以给我一个提示吗?

我必须创建一些缓冲区,它将收集字节直到 LF/CRLF,或者有更好的解决问题的方法?

4

4 回答 4

7

你不能得到这个,唯一的选择是 SerialPort.ReceivedBytesThreshold 来延迟 DataReceived 事件处理程序调用,这对于可变长度响应是无用的。

解决方法非常简单,只需在 DataReceived 事件处理程序中调用 ReadLine()。这将阻塞工作线程,不会影响程序中发生的任何其他事情。在 ReadLine() 调用被阻塞时触发任何附加事件都没有危险,它在 SerialPort 类内部互锁。如果通信不够可靠,请在必要时使用 ReadTimeout 属性,以便 ReadLine() 不会永远阻塞。将其设置为接收最长可能响应的预期延迟的十倍。

于 2012-10-01T14:18:08.283 回答
4

你必须自己做。使用 DataReceived 并检查每个字节。收集缓冲区中的字节,直到获得换行符,然后在该点将缓冲区作为一行处理。

于 2012-10-01T13:47:58.740 回答
0

提示:

该类SerialPort有一个属性NewLine来设置用于解释对ReadLine方法的调用结束的值。

于 2012-10-01T14:01:02.240 回答
0

这是我快速实现的、非阻塞的、相同的线程解决方案。它是一个非常基本的状态机,它等待'\r' 和'\n',然后发送所有缓冲的字符进行解析。您可以通过更改状态机本身将其更改为您想要的任何换行符值。在这种方法中,您可以注册 OnNewLineReceived 事件并处理来自 SerialStringMessgae 事件处理程序的数据。没有尝试/捕获开销。没有死锁。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace NonBlockingSerialPortReadLine
{
    public partial class Form1 : Form
    {
    System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort();
    public event EventHandler OnNewLineReceived;
    System.Windows.Forms.Timer NewDataTimer = new System.Windows.Forms.Timer();
    int StateMachine = 0;
    StringBuilder stringBuffer = new StringBuilder();

    public Form1()
    {
        InitializeComponent();
        InitTimer();
        InitOnNewLineReceived();
    }

    private void InitTimer()
    {
        NewDataTimer.Interval = 50;
        NewDataTimer.Tick += NewDataTimer_Tick;
    }

    private void InitOnNewLineReceived()
    {
        OnNewLineReceived += Form1_OnNewLineReceived;
    }

    void Form1_OnNewLineReceived(object sender, EventArgs e)
    {
        SerialStringMessgae STM = e as SerialStringMessgae;
        string messgae = STM.message;

        // PARSE YOU MESSAGE HERE - the debug line below is not mandatory

        System.Diagnostics.Debug.WriteLine(messgae);
    }

    class SerialStringMessgae : EventArgs
    {
        public string message;
    }

    private void StartListeningButton_Click(object sender, EventArgs e)
    {
        StartListeningButton.Enabled = false;
        sp = new System.IO.Ports.SerialPort("COM4",57600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
        try
        {
            sp.Open();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
            return;
        }
        if (sp.IsOpen)
        {
            NewDataTimer.Enabled = true;
        }

    }

    void NewDataTimer_Tick(object sender, EventArgs e)
    {
        string newData = sp.ReadExisting();
        foreach (char c in newData)
        {
            switch (StateMachine)
            {
                case 0:
                    // waiting for '\r'
                    if (c == '\r')
                    {
                        StateMachine = 1;
                    }
                    else
                    {
                        stringBuffer.Append(c);
                    }
                    break;
                case 1:
                    // waiting for '\n'
                    if (c == '\n')
                    {
                        if (OnNewLineReceived != null)
                        {
                            SerialStringMessgae STM = new SerialStringMessgae();
                            STM.message = stringBuffer.ToString();
                            OnNewLineReceived(this, STM);
                        }
                    }
                    // after parsing the message we reset the state machine
                    stringBuffer = new StringBuilder();
                    StateMachine = 0;
                    break;
            }
        }
    }

}
}
于 2016-07-25T09:19:29.517 回答