如何让程序等待接收串口数据?

时间:2018-01-04 09:55:44

标签: c# serial-port

编辑:

我正在开发一个从串口接收数据的程序,数据将以" \ r \ n"结尾。我正在使用Data_Received事件从串口接收数据。

下面是我的程序,我尽量避免使用Thread.Sleep并使用线程等待数据完全接收,但步骤总是跳转到return "Error"步骤。

我想知道如何让程序在跳转到return "Error"步之前等待数据完全接收?

如果不使用线程,如果有人有更好的方法,那就没关系。

using System;
using System.Windows.Forms;
using System.IO.Ports;

namespace SerialPortExample
{

public partial class Form1 : Form
{ 


string port1ReceivedMessage = string.Empty;

internal delegate void SerialDataReceivedEventHandlerDelegate(
                 object sender, SerialDataReceivedEventArgs e); 

SerialPort comPort = new SerialPort();

string InputData = string.Empty;
delegate void SetTextCallBack(string text);

public Form1()
{
    InitializeComponent();

   comPort.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);

}

~Form1()
{
    comPort.Close();
}

public string SendDataAndReadData()
{
    port1ReceivedMessage = string.Empty;

    string sendData = "?";
    Send(sendData); // To send data

    Thread t = new Thread(ThreadProc);
    t.Name = "Thread_1";
    t.Start();

    //Thread.Sleep(1000);

    if(!string.IsNullOrEmpty(port1ReceivedMessage) && port1ReceivedMessage.Contains("\n"))
    {
        event_1.Set();
        return port1ReceivedMessage;
    }

    return "Error";


}

private void ThreadProc()
{

    event_1.WaitOne();

}

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    InputData = comPort.ReadExisting(); 

    if(InputData != string.Empty)
    {
      try
      {

      this.BeginInvoke(new SetTextCallBack(SetText), new object[] { InputData });
      }
     catch (TimeoutException timeoutEx)
     {
        //Skip exception handling codes
     }
     catch (Exception ex)
     {
        //Skip exception handling codes
     }
    }
}

private void SetText(string text)
{
    port1ReceivedMessage += text;
}

private void portOpenButton_Click(object sender, EventArgs e)
{
    comport = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
    comport.ReadTimeout = 2000;
    if (!comport.IsOpen)
    {
        comport.Open();
    }

 }

private void sendButton_Click(object sender, EventArgs e)
{
   SendDataAndReadData();
}

private void Send(string text)
{
    // Skip some text formatting codes 
    comPort.Write(text);
}

}

2 个答案:

答案 0 :(得分:1)

DataRecieved事件引发了一些randomely。当它发射时你不会总是得到整个弦。值得庆幸的是,一旦掌握了整个内容,就会知道您的消息是什么样的。你需要建立你的字符串,直到你看到一个/r/n,然后知道你拥有整个字符串后你需要做什么。

private StringBuilder sb;
private SerialPort sp;

public void init_state_machine()
{
    sp = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
    sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);

    sb = new StringBuilder();
    sb.Clear();
}

private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    string currentLine = "";
    string Data = sp.ReadExisting();

    Data.Replace("\n", ""); //remove new lines

    foreach (char c in Data)
    {
        if (c == '\r')
        {
            currentLine = sb.ToString();
            sb.Clear();

            Console.WriteLine(currentLine);
        }
        else
        {
            sb.Append(c);
        }
    }
}

至于发送,您只需进行发送,当设备响应时,您的DataRecieved事件将会触发。 DataRecieved事件已经在它自己的线程中,因此您不需要处理您尝试执行的所有线程化事件。

答案 1 :(得分:0)

请阅读:

If you must use .NET System.IO.Ports.SerialPort

这是Ben Voigt在sparxeng.com上撰写的2014年博客文章。

摘录:

  

说得客气一点,System.IO.Ports.SerialPort是由远远超出其核心竞争力的计算机科学家设计的。他们既不了解串行通信的特性,也不了解常见的用例,它表明了这一点。它也不能在运输之前的任何现实世界场景中进行测试,而不会发现存在记录的界面和未记录的行为的缺陷,并使用System.IO.Ports.SerialPort(以下称为IOPSP)进行可靠的通信是一场真正的噩梦。

  

最糟糕的违规System.IO.Ports.SerialPort成员,不仅不应该被使用,而且是深层代码味道的迹象,需要重新架构所有IOPSP使用:

     
      
  • DataReceived事件(100%冗余,也完全不可靠)
  •   
  • BytesToRead属性(完全不可靠)
  •   
  • Read,ReadExisting,ReadLine方法(处理错误完全错误,并且是同步的)
  •   
  • PinChanged事件(按顺序发送   尊重你可能想知道的每一件有趣的事情。)
  •   

  

并且没有人使用的一个成员因为MSDN没有给出任何例子,但对你的理智绝对是必不可少的:

     
      
  • BaseStream属性
  •   

尽管Ben Voigt负责,我们使用BytesToRead属性和ReadExisting() Thread.Sleep()。我们避免使用DataReceived()ReadLine()。这是我们的解决方法,我们也不知道BaseStream属性。

对于新项目,我建议使用BaseStream属性。