2013-08-28 88 views
4

我負責創建一個HMI,它將使用USB端口與設備進行通信。我是新來的C#和WPF,所以我開始研究了一下,發現了幾個問題和主題在這個網站,這幫助我實現了我想要的起點:我能夠讀寫SerialPort類。串口通信缺少一個字節

爲了測試設備,我有一個UART可以回顯接收到的任何消息。我有一個簡單的文本框,一個按鈕和一個標籤。點擊按鈕後,它將框中輸入的文本發送到設備(如果沒有輸入文本,我有預定義的字節數組進行測試)。只要端口收到字節,標籤就會更新。

對於第一條消息,代碼運行正常(無所謂),但之後發送的任何消息幾乎總是返回缺少的字節。我不知道爲什麼會發生這種情況,我試着每次都放棄緩衝區,但無濟於事。

這裏是我的代碼:

using System.IO.Ports; 

namespace LearningSteps 
{ 
    /// <summary> 
    /// Interaction logic for Comm.xaml 
    /// </summary> 
    /// 
    public partial class Comm : Window 
    { 
     SerialPort port; 
     BackgroundWorker backgroundWorker1 = new BackgroundWorker(); 

     public delegate void AtualizaCallBack(string message); 

     public Comm() 
     { 
      InitializeComponent(); 
      //InitializeBackgroundWorker(); 
      port = new SerialPort("COM4",115200,Parity.None,8,StopBits.One); 
      port.RtsEnable = true; 
      port.DataReceived += 
      new SerialDataReceivedEventHandler(Recebido); 
      port.Open(); 

     } 

     private void Recebido(object sender, SerialDataReceivedEventArgs e) 
     { 
      SerialPort sp = (SerialPort)sender; 
      String indata = sp.ReadExisting(); 

      sp.DiscardOutBuffer(); 
      sp.DiscardInBuffer(); 

      my_label.Dispatcher.Invoke(new AtualizaCallBack(this.atualiza),new object[]{indata}); 

     } 

     private void bt_Click(object sender, RoutedEventArgs e) 
     { 
      if (txt1.Text.Length == 0) 
      { 
       byte[] vetor = new byte[] { 0x40, 0x45, 0x2B, 0x5C, 0x10 }; 
       port.DiscardOutBuffer(); 
       port.Write(vetor, 0, 5); 
      } 
      else 
      { 
       port.DiscardOutBuffer(); 
       port.Write(txt1.Text); 
      } 
     } 

     private void atualiza(string s) 
     { 
      my_label.Content = s; 
     } 

    } 
} 

而這裏的XAML:

<Window x:Class="LearningSteps.Comm" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Comm" Height="346" Width="404"> 
    <Grid Background="#FF9E9E9E"> 
     <Label x:Name="my_label" HorizontalAlignment="Left" Height="40" Margin="80,200,0,0" VerticalAlignment="Top" Width="240" Background="#FFD1D18D" FontSize="14" FontWeight="Bold" Foreground="#FF1D83BD" HorizontalContentAlignment="Center" Content="Lalala"/> 
     <TextBox x:Name="txt1" HorizontalAlignment="Left" Height="40" Margin="80,80,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="240" TextAlignment="Center" FontSize="14" FontWeight="Bold"/> 
     <Button x:Name="bt" Content="Enviar" HorizontalAlignment="Left" Height="40" Margin="140,140,0,0" VerticalAlignment="Top" Width="120" FontWeight="Bold" Foreground="#FF4084BD" Click="bt_Click"> 
      <Button.Background> 
       <LinearGradientBrush EndPoint="0,1" StartPoint="0,0"> 
        <GradientStop Color="#FFF3F3F3" Offset="0"/> 
        <GradientStop Color="#FFE6C041"/> 
        <GradientStop Color="#FFE8C382" Offset="1"/> 
       </LinearGradientBrush> 
      </Button.Background> 
     </Button> 
    </Grid> 
</Window> 

什麼可能這裏是問題的任何想法?

+1

你的主題說「缺少一個字節」。你的評論說「缺少字節」。請澄清。它總是第一個字節嗎?持續?你說「幾乎總是」。每一次,但第一次或只是通常?每次都有相同的字節數? –

+2

我永遠不會刷新你的接收緩衝區。如果你的環回發送了10個字節,但是你的接收處理程序是用前5個字節調用,而另外5個字節正在接收呢?您正在刷新緩衝區並可能丟棄一些數據。另外,請檢查實際收到的字節數和調試器中的實際內容。也許你的波特率被「僅僅一點點」所導致,導致一些無法在控制中顯示的損壞和字符。 – Steve

+0

抱歉鮑勃,在問這裏的問題時有點失落。如果我一直髮送不帶空格的行,它只是第一個字節/字母。如果我嘗試發送諸如「hello world」之類的東西,它可能會錯過一個以上的字節(讓整個單詞消失一次)。 在第一封郵件後,幾乎有95%的機會發生數據損壞。 –

回答

0
 String indata = sp.ReadExisting(); 
     sp.DiscardOutBuffer(); 
     sp.DiscardInBuffer(); 

這是非常不明智的,該端口將繼續在調用sp.ReadExisting()的時間來接收數據。在您使用的高波特率時,ReadExisting()返回時接收到另一個字節的非零概率。你的DiscardInBuffer()調用將會銷燬它。

刪除全部調用DiscardOutBuffer和DiscardInBuffer。他們做而不是刷新,他們只會導致隨機數據丟失。它們只能用於重置協議以清除驅動程序緩衝區,您沒有協議。

+0

謝謝,漢斯。我已經這樣做了,但主要問題仍然存在。 –

+0

我只知道你做錯了什麼,我不可能猜到你現在做錯了什麼。使用ReadExisting()也不會贏得任何獎勵,設備發送的換行符表示換行結束不會很好。將SerialPort.NewLine設置爲「\ n」並使用ReadLine()。 –

+0

非常感謝Hans!那樣做了!我已經按照你的說法設置了NewLine,也切換到WriteLine並將0x0A字節包含在我的數組的末尾,它現在可以順利運行! 給你的榮譽,善良的先生,如果我能的話,我會+1! –

0

串口通訊存在數據傳輸錯誤。您需要實施某種低層協議以確保通信成功。

例如,您可以在每個傳輸的數據幀中包含校驗和。如果該校驗和與接收到的數據的校驗和不匹配,則接收應用可以請求重新發送前一幀。

+0

是的,我想我會開始研究這個。謝謝你的提示。 –

+0

如果你不想自己寫你可以使用modbus。 [nmodbus - 開源庫](https://code.google.com/p/nmodbus/) – JeremiahDotNet

+0

謝謝,這將是最有幫助的 –

0

如果有人碰巧遇到同樣的問題,這裏是我選擇的解決方法。這是可怕的,並沒有解釋所有字節丟失的原因(雖然使用了不同的方法並且沒有緩衝區刷新,但我的項目也是這樣),但它可以作爲quickfix使用。

簡單地在每封郵件的開頭添加一個控制字符(在我的情況下,我可以使用'0',但也可以使用0x00或另一個)。在接收端,如果消息以該字符開始,忽略後者;否則,控制字符已被丟棄,並且有效接收的消息直接是「有效載荷」。

所以,在僞代碼(抱歉,如果我的僞代碼的Python),與'0'爲控制字符:

// Sender 
message = "hello" 
send("0" + message) 

// Receiver 
message = read_port() 
if message[0] == '0': 
    message = message[1:] 

請注意,這不是一個可行的解決方案,但只有一個修補程序。