2009-03-13 19 views
12

Próbowałem używać Readline(), a dane zostały upuszczone, próbowałem używać Read(), ale nie jestem pewien, jak mieć metodę sprawdzania błędów, ponieważ mogę dostać kilka pakietów jedna po drugiej i nie mam możliwości dowiedzenia się, że nadchodzi kolejny pakiet. Między pakietami BytesToRead ma wartość 0, więc nie mogę z niego korzystać. Czy podczas odczytywania danych do bufora masz zegar lub spać, aby wszystkie pakiety mogły nadejść?Czytanie z portu szeregowego w C#

Jestem zagubiony. Nie wiem, co spróbować dalej.

Powinienem wspomnieć, że nie mam gwarancji, że łańcuch wypadający z portu szeregowego zostanie zakończony z \ n lub \ r lub \ r \ n. Po prostu potrzebuję sprawdzonego sposobu, aby odczytać WSZYSTKIE pakiety, które będą pochodzić z wagi, gdy użytkownik naciśnie PRINT na nim.

Ktoś odpowiedział tutaj z pomysłem, który mi się podobał - czekał na pewien czas na wszystkie pakiety, ale wymazał ich odpowiedź. Czy masz szansę na ponowne opublikowanie?

Odpowiedz

23

Czy próbowałeś/aś odsłuchać zdarzenia DataRecieved klasy SerialPort?

public class MySerialReader : IDisposable 
{ 
    private SerialPort serialPort; 
    private Queue<byte> recievedData = new Queue<byte>(); 

    public MySerialReader() 
    { 
     serialPort = new SerialPort(); 
     serialPort.Open(); 

     serialPort.DataReceived += serialPort_DataReceived; 
    } 

    void serialPort_DataReceived(object s, SerialDataReceivedEventArgs e) 
    { 
     byte[] data = new byte[serialPort.BytesToRead]; 
     serialPort.Read(data, 0, data.Length); 

     data.ToList().ForEach(b => recievedData.Enqueue(b)); 

     processData(); 
    } 

    void processData() 
    { 
     // Determine if we have a "packet" in the queue 
     if (recievedData.Count > 50) 
     { 
      var packet = Enumerable.Range(0, 50).Select(i => recievedData.Dequeue()); 
     } 
    } 

    public void Dispose() 
    { 
     if (serialPort != null) 
      serialPort.Dispose(); 
    } 
+0

Nie ma gwarancji, że dane faktycznie przeczytać na port szeregowy jest serialPort.BytesToRead. Sugerowałbym sprawdzenie zwracanej wartości serialPort.Read. – Roger

10

Przeszliśmy ten sam proces jakiś czas temu.

Jedynym sposobem na odczytanie "pakietów" jest posiadanie pojęcia, gdzie początek i koniec są w strumieniu.

Od msdn:

Ponieważ dane buforów klasy SerialPort i strumień zawarte w nieruchomości BaseStream nie, dwa może kolidować o ile bajtów są dostępne do odczytu. Właściwość BytesToRead może wskazywać, że istnieją bajty do odczytania, ale te bajty mogą być niedostępne dla strumienia zawartego w właściwości BaseStream, ponieważ zostały buforowane do klasy SerialPort.

Użyliśmy wątku backround (można użyć BackgroundWorker), aby odczytać dane do bufora. Jeśli nie możesz niezawodnie ustawić znaku kończącego za pomocą właściwości SerialPort.Newline (ponieważ, powiedzmy, zmienia się!), Będziesz musiał zaimplementować własny system wykrywania pakietów, ponieważ nie będziesz mógł korzystać z blokującego SerialPort.Readline () metoda.

Można odczytywać do bufora bajtów za pomocą SerialPort.Read() (lub ciąg znaków za pomocą metody SerialPort.ReadExisting()) i wygenerować zdarzenie po wykryciu poprawnego pakietu danych. Zauważ, że Read() (i zakładam ReadExisting()) opróżnia bufor SerialPort, więc będziesz musiał przechowywać dane w innym miejscu.

Jeśli ustawisz SerialPort.ReadTimeout, możesz obsłużyć wyjątek TimeoutException i mieć łatwy sposób obsługi warunków, w których urządzenie nie przesyła. Jest to dobry sposób na zresetowanie wykrycia pakietów, jeśli używasz stałej liczby bajtów lub jakiegoś innego nie kończącego się schematu. (Użyj SerialPort.DiscardInBuffer() na timeout, jeśli nie potrzebujesz częściowych pakietów).

Powodzenia

+0

z tego, co wiem, że nie ma schematu wykrywania. Spróbuję go przetestować - czekając na kilka milisekund przed przetworzeniem, aby umożliwić dostarczenie pakietów. Nie widzę żadnej innej alternatywy. Używałem ReadLine() przez 6 miesięcy, aż ktoś zauważy błąd, w którym dane zostaną usunięte. – sarsnake

+0

Używamy wielu wag przemysłowych i normalnie można ustawić znak zakończenia w urządzeniu. Czy masz kontrolę nad urządzeniami wejściowymi, abyś mógł na to patrzeć? ReadLine jest * znacznie * łatwiejsze :) –

+0

wykonujemy: \ n (ascii 13). Mam zamiar spróbować odczytać bajt danych za pomocą bajtu z SerialPort.ReadByte() i poszukać 13. Mam zamiar ustawić SerialPort.NewLine na \ n (mam to ustawione na \ r \ n teraz .... hmmm, może to jest problem.Dzięki! – sarsnake

3

Od bajtów może przyjść w każdej chwili, buforowanie danych przychodzących jest krytyczna.Więc powinno

  1. bufor danych przychodzących
  2. zeskanować swój bufor znaleźć kompletne dane
  3. usunąć używane dane z bufora

jestem po prostu zastanawiasz się, jeśli nadal występują problemy z port szeregowy. Jeśli tak, opracowałem język programowania portu szeregowego w języku C# i uważam, że rozwiązuje on prawie wszystkie problemy, z którymi wszyscy się spotykają.

Czy możesz go obejrzeć i wypróbować? Na przykład; możesz buforować przychodzące dane z portu szeregowego, jak poniżej i wykonywać operacje na łańcuchach.

state Init 
    // define a global variable 
    our $BUFFER = ""; 
    jump(Receive); 
end state 

state Receive 
    recv(); 
    $len = length($DATA_PACKET); 
    if("$len > 0") { 
    $BUFFER += $DATA_PACKET; 
    call(Parser); 
    } 
end state 

state Parser 
    // check if buffer matchs regular expression pattern 
    if(match($BUFFER, "(?<WILLDELETE>.*?<STX>(?<DATA>.*?)<ETX>(?<CHECKSUM>[0-9A-F]{2}))")) { 
    // Received complete data 
    $lenData = length($WILLDELETE); 
    $BUFFER = remove($BUFFER, 0, $lenData); 

    // Do operations with the other parsed fields. $DATA and $CHECKSUM in this example. 
    } 
end state 

Projekt jest dostępny bezpłatnie na stronie sourceforge. W razie pytań proszę pytać.

Project Homepage

Download Link

Powiązane problemy