我需要收到NewLine上的SerialPort事件

时间:2012-10-01 13:38:10

标签: c# .net serial-port

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

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

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

有人能给我一个暗示吗?

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

4 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:0)

提示:

SerialPort类具有属性NewLine,用于设置用于解释对ReadLine方法的调用结束的值。

答案 3 :(得分: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;
            }
        }
    }

}
}