2016-02-25 79 views
0

我正在嘗試使用C#在MSVS上創建串行通信工具。它與Photon MCU和藍牙適配器進行通信。MSVS C#SerialPort接收到數據丟失

當按下「開始」按鈕時,UI向Photon發送一個「1」,它首先發送當前時間戳並開始從函數發生器發送流數據。當按下「停止」按鈕時,它首先發送光子收到時10「2」(由於光子端的定時器問題),它停止發送函數發生器的數據。然後它休眠一秒鐘併發送一個「3」,它發送另一個當前時間戳。然後用戶界面放棄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個。

我的理論是,用戶界面以較慢(或延遲)的速率接收數據,即使在數據可以打印到調試輸出之前,它也會丟棄接收到的數據。我知道,由於與數據包關聯的計數器值,我收到的第一個和最後一個數據之間的所有數據全部存在。基本上如果我得到1〜500個數據點,我只能得到1〜100個數據點。我也嘗試過,只要發送1,2和3的白蟻,因爲UI應該是這樣的,我可以根據需要獲取所有數據。我沒有故意關閉BT。

我該怎麼做才能防止這種數據丟失?我在代碼中做錯了什麼,我不應該爲正確的藍牙協議做或做什麼?這是我第一次寫藍牙代碼,所以我很不熟悉它。

+0

如果不是全部調用睡眠模式,而是調用睡眠模式(50次),而不是循環調用20次,會有幫助嗎?我想可能接收事件想要觸發,但不能,因爲你已經凍結了主線程。 –

+0

您接收數據的方式可能非常錯誤。首先 - 你假設只有一行要閱讀。不要嘗試使用ReadLine並使用ReadExisting。其次 - 你只是把你讀到的任何東西放到一個字符串中,每當一個新的事件被觸發時就會被覆蓋。其中一些字符串可能(幾乎可以肯定)不能長時間處理它們。 –

回答

0

不知道這是你的問題的原因,但你的接收有一個非常大的陷阱。

每個接收事件只能讀取一行,並且在一個事件中可以有多行讀取,然後在最後累積並丟棄它們。

ReadLine旨在以類似於流的同步方式使用,您只需讀取一行,然後對其進行處理,然後再編寫,而不用於DataReceived事件。

你有兩個選擇:用serial.ReadLine()連續循環讀取一個新線程(它會阻塞,直到有新的一行可用)或更好的方法,讀取每個接收事件的串行緩衝區。

要那樣做,你可以做smething這樣的:

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); 
     } 
    } 

正如你所看到的,所接收到的數據被存儲用作緩衝時間列表(是的,一個數組,並使用緩衝區函數會更快,但對於小的消息,爲了簡單起見,大多數情況下列表就足夠了),然後將接收到的數據添加到緩衝區,並且當沒有剩餘字節時,列表將被處理以搜索字符串行。

還要注意讀是一個循環,我在同時執行此功能並沒有接收事件被解僱接收數據,其中存在這樣的情況已經運行,所以這樣做的更好的是創建一個循環讀取,同時有仍然是數據。

0

謝謝大家的迴應,他們都幫我解決了我的問題,但最終是什麼修正了它延遲發送「3」和放棄我的inBuffer和關閉接收連接之間的時間。

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

Thread.Sleep()沒有因爲它的性質禁用線程內的所有行動(我仍然需要)的工作,所以這種方法的工作就像一個魅力。我只是打電話await DelayBT我需要延遲。

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