簡體   English   中英

MSVS C#SerialPort接收到的數據丟失

[英]MSVS C# SerialPort Received Data Loss

我正在嘗試使用C#在MSVS上創建一個串行通信工具。 它與Photon MCU和藍牙軟件狗進行通信。

當按下“開始”按鈕時,UI向光子發送一個“ 1”,它首先發送當前時間戳,並開始從函數發生器流式傳輸數據。 當按下“停止”按鈕時,它首先發送10個“ 2”(由於光子端的計時器發出),當光子收到時,它將停止傳輸函數發生器的數據。 然后它睡眠一秒鍾,然后發送“ 3”,並發送另一個當前時間戳。 然后,UI丟棄InBuffer中的數據並停止讀取數據。

connectBT與開始按鈕連接, disconnectBT與停止按鈕連接。

這是我現在擁有的代碼:

SerialPort serial = new SerialPort();
string recieved_data;
int startBuffer = 0;

private void connectBT(object sender, RoutedEventArgs e)
{
    startBuffer++; // keep track of BT open counter
    if (serial.IsOpen) Debug.WriteLine("BT Open");

    // first time BT is open and BT is not open
    if (!serial.IsOpen)
    {
        if (startBuffer == 1)
        {
            // COM port properties
            serial.PortName = "COM7";
            serial.BaudRate = 38400;
            serial.Handshake = Handshake.None;
            serial.Parity = Parity.None;
            serial.DataBits = 8;
            serial.StopBits = StopBits.One;
            serial.ReadTimeout = 200;
            serial.WriteTimeout = 50;
            serial.Open();
        }

        startButton.Content = "Recording";
        Send_Data("1"); // tell Photon to start sending data
        serial.DiscardInBuffer(); // discard whatever is in inbuffer
        serial.DataReceived += new SerialDataReceivedEventHandler(Recieve); // start receiving data
    }

    // after BT has been opened and start button has been pressed again
    else if (serial.IsOpen && startBuffer > 1)
    {
        startButton.Content = "Recording";
        Send_Data("1");
        serial.DiscardInBuffer();
        serial.DataReceived += new SerialDataReceivedEventHandler(Recieve);
    }
}

// stop button is pressed
private void disconnectBT(object sender, RoutedEventArgs e)
{

    // send "2" ten times to tell photon to stop transmitting function generator data
    int i = 0;
    while (i < 10)
    {
        Send_Data("2");
        Thread.Sleep(1);
        i++;
    }
    Thread.Sleep(1000);
    Send_Data("3"); // send a 3 to tell photon to send the last time stamp
    Thread.Sleep(1000);

    serial.DiscardInBuffer(); // discard in buffer
    serial.DataReceived -= Recieve; // stop receiving data
    //serial.Close(); // close BT
    startButton.Content = "Start";

}

private void Recieve(object sender, SerialDataReceivedEventArgs e)
{

    recieved_data = serial.ReadLine();
    Debug.WriteLine(recieved_data);

}

我遇到一個問題,當我按“停止”按鈕時,從藍牙發送的最后一塊數據丟失了。 按下停止按鈕時,我永遠不會收到應該收到的最后一個時間戳。 根據我們的數學計算,我們應該每秒接收500個點(500Hz),但是我只能接收大約100個點。

我的理論是UI會以較慢(或延遲)的速率接收數據,而serial.DiscardInBuffer甚至在可以將數據打印到Debug輸出之前serial.DiscardInBuffer丟棄接收到的數據。 我知道一個事實,因為與數據包關聯的計數器值,我收到的第一個和最后一個之間的所有數據都在那里。 基本上,如果我要接收1〜500個數據點,我只會收到1〜100。 我還嘗試了白蟻發送1,2和3的嘗試,因為UI應該是這樣,我可以根據需要獲取所有數據。 我不是故意關閉BT。

我該如何防止這種數據丟失? 我在我的代碼中為正確的藍牙協議不應該做或正在做的錯誤在做什么? 這是我第一次編寫藍牙代碼,所以我對此並不熟悉。

不知道這是否是您造成問題的原因,但是您的Receive有一個很大的陷阱。

每個“接收”事件僅讀取一行,而在一個事件上,可能有多行要讀取,因此最后將對其進行累加和丟棄。

ReadLine旨在以同步方式使用,就像流一樣,您可以在其中讀取一行,然后對其進行處理,然后再編寫,而不用於DataReceived事件。

您有兩個選擇:使用serial.ReadLine()在連續循環讀取中旋轉一個新線程(它將阻塞直到有新行可用),或者采用更好的方法,在每個Receive事件上讀取串行緩沖區。

為此,您可以執行以下操作:

    List<byte> tmpBuffer = new List<byte>();
    static byte newLineB = Encoding.ASCII.GetBytes("\n")[0];

    void Receive(object sender, SerialDataReceivedEventArgs e)
    {

        lock (tmpBuffer)
        {
            while (serial.BytesToRead > 0)
            {
                byte[] segment = new byte[serial.BytesToRead];
                serial.Read(segment, 0, segment.Length);
                tmpBuffer.AddRange(segment);
                ProcessBuffer();

            }

        }

    }

    private void ProcessBuffer()
    {
        int index = 0;

        while ((index = tmpBuffer.IndexOf(newLineB)) > -1)
        {
            string line = Encoding.ASCII.GetString(tmpBuffer.Take(index + 1).ToArray());

            //Do whatever you need to do with the line data
            Debug.WriteLine(line);

            tmpBuffer.RemoveRange(0, index + 1);
        }
    }

如您所見,接收到的數據存儲在用作緩沖區的臨時列表上(是的,數組和使用Buffer函數會更快,但是對於小消息和簡單起見,在大多數情況下列表就足夠了),接收到的數據將添加到緩沖區,並且在沒有更多字節剩余時,將在搜索字符串行時處理列表。

還要注意,讀取是在循環中進行的,我在執行函數的情況下運行了接收數據且未觸發接收事件的情況,因此這樣做最好是創建一個循環以在仍有數據時讀取。

謝謝大家的答復,它們都幫助我找到了解決我問題的方法,但最終解決了該問題,這延遲了發送“ 3”與丟棄我的inBuffer以及關閉Receive連接之間的時間。

async Task DelayBT()
{
    await Task.Delay(100);
}

Thread.Sleep()不能工作,因為它的本質是禁用線程中的所有操作(我仍然需要),因此該方法像一個魅力一樣起作用。 我只是在需要延遲的地方打電話給await DelayBT

希望這可以幫助遇到我的問題的任何人。

暫無
暫無

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

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