簡體   English   中英

C#Windows表單-解析從串行端口接收的字符串

[英]C# Windows form - parsing string received from serial port

我正在使用C#開發Windows窗體應用程序,在其中我從串行端口接收數據,現在我有以下代碼(這只是解決我的問題的相關代碼):

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)     
{
      ReceivedData = serialPort1.ReadExisting();
      this.Invoke(new EventHandler(interp_string));       
}

private void interp_string(object sender, EventArgs e)      
{
      textReceive.Text += ReceivedData + "\n";
}

但是現在我需要將接收到的數據解析為小字符串。 ReceivedData變量是具有以下格式的多個字符串的組合:“值時間\\ n”,其中值從0到1024,時間以秒為單位(並且始終在增加),並具有4個小數位。 我需要將ReceivedData變量拆分為單獨的值,這是將其繪制在圖表中的相應時間。 考慮到使用ReadExisting,可能會發生一個字符串僅被部分讀取而其余字符串僅在下次觸發DataReceived事件時讀取的情況,但是我不介意是否丟失了一點數據,並不重要。

我已經嘗試使用ReadLine代替ReadExisting,並且設法拆分每個字符串並繪制數據,但是鑒於應用程序正在接收大量數據(每1毫秒一個字符串),應用程序無法跟上,即使它已經過了10秒鍾,應用程序仍在從第二秒開始打印數據,並且我按了一個按鈕以停止接收數據,該應用程序長時間保持打印值,我認為這些值是存儲在接收緩沖區中的值。 更改為ReadExisting是我發現的唯一實時讀取和打印所有內容的方法。

您始終可以在String類型中使用正則表達式,而不必單獨分割每一行。 正則表達式.NET匹配方法

假設您有以下攔截數據:

1250 154873210
1250 15487556574
1250 15487444
1250 154871111
1250 154875454524545444
1250 154873210
1250 15487556574
1250 15487444
1250 154871111
1250 154875454524545444
1250 154873210
1250 15487556574
1250 15487444
1250 154871111
1250 154875454524545444
1250 154873210
1250 15487556574
1250 15487444
1250 154871111
89877 154875454524545444
001 154873210
877 15487556574
15647 15487444
540 154871111
12 154875454524545444

使用正則表達式可以很容易地獲得成對的“值/時間”(如上面的鏈接中所述)。

所以您的常規將是:

(?'Value'\d+)\s*(?'Time'\d+\.\d+)

演示

C#示例:

        string ReceivedData = "1221 1111.1111\n1221 1111.1111";
        MatchCollection matches = Regex.Matches(ReceivedData, @"(?'Value'\d+)\s*(?'Time'\d+\.\d+)");
        Console.WriteLine("Matches found : "+matches.Count);
        foreach(Match Pairs in matches)
        {

            Console.WriteLine(String.Format("Match : Value -> {0} , Time -> {1}", Pairs.Groups["Value"], Pairs.Groups["Time"]));
        }

DataReceived事件可能會在字符串中間觸發,並且您可能尚未收到整個消息。 您需要知道要查找的內容,通常是換行(LF)或回車(CR)。 我使用StringBuilder構建字符串,下面是一個示例,其中LF表示我收到了完整的消息。 我將字符附加到字符串中,直到我知道完整的消息為止。 我快速清除了緩沖區,因為在評估時可以輸入下一個字符串。 對於這個簡單的示例,我只是調用一個函數來評估我的字符串,但是您可能要在這里使用委托。

StringBuilder sb = new StringBuilder();
char LF = (char)10;

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string Data = serialPort1.ReadExisting();

    foreach (char c in Data)
    {
        if (c == LF)
        {
            sb.Append(c);

            CurrentLine = sb.ToString();
            sb.Clear();

            //do something with your response 'CurrentLine'
            Eval_String(CurrentLine);
        }
        else
        {
            sb.Append(c);
        }
    }
}

收到完整的消息后,您可以根據需要對其進行評估。 我不確定您的數據是什么樣子,但是在我的示例中,我的消息以逗號分隔返回,因此我可以使用逗號作為分隔符將字符串拆分為字符串數組,並從消息中獲取每個值。

public void Eval_String(string s)
{
    string[] eachParam;
    eachParam = s.Split(',');

    if (eachParam.Length == 5)
    {
        //do something
        Console.WriteLine(eachParam[2]);
    }
}

編輯:這是有關如何使用隊列更新GUI的示例。

StringBuilder sb = new StringBuilder();
char LF = (char)10;
Queue<string> q = new Queue<string>();

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string Data = serialPort1.ReadExisting();

    foreach (char c in Data)
    {
        if (c == LF)
        {
            sb.Append(c);

            CurrentLine = sb.ToString();
            sb.Clear();

            q.Enqueue(currentLine);
        }
        else
        {
            sb.Append(c);
        }
    }
}

private void backgroundWorkerQ_DoWork(object sender, DoWorkEventArgs e)
{
    while (true)
    {
        if (backgroundWorkerQ.CancellationPending)
            break;

        if (q.Count > 0)
        {
            richTextBoxTerminal.AppendText(q.Dequeue());
        }

        Thread.Sleep(10);
    }
}

如果您從未與后台工作人員一起工作過,則只需創建一個新的backgroundworker對象,將supportsCancellation設置為true,然后為其添加一個DoWork事件。 然后,當您啟動表單時,可以將其告知.RunWorkerAsync()

if (!backgroundWorkerQ.IsBusy)
{
    backgroundWorkerQ.RunWorkerAsync();
}

請參閱: https ://docs.microsoft.com/zh-cn/dotnet/api/system.componentmodel.backgroundworker?view=netframework-4.7.2另請注意,backgroundworker在其自己的線程中,您很可能需要BeginInvoke它可以更新您的文本框。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM