Care este modalitatea corectă de citire a unui port serial folosind .NET framework? (Programare, C#, Port Serial,.Net 4.5)

Yannick Blondeau a intrebat.

Am citit o mulțime de întrebări aici despre cum să citesc date din porturile seriale folosind clasa .NET SerialPort, dar niciuna dintre abordările recomandate nu s-a dovedit complet eficientă pentru mine.

Iată codul pe care îl folosesc pentru moment:

SerialPort port = new SerialPort("COM1");
port.DataReceived += new SerialDataReceivedEventHandler(MyDataReceivedHandler);

Și gestionarul de evenimente:

void MyDataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    int count = port.BytesToRead;
    byte[] ByteArray = new byte[count];
    port.Read(ByteArray, 0, count);
}

Dar, uneori, încă îmi lipsesc unele date. Am încercat diferite modalități de citire a datelor în gestionarul de evenimente, dar fără succes.

Deoarece .NET 4.5 aduce noi posibilități de a face unele sarcini asincrone, cum ar fi cu ReadAsync care pare să poată fi utilizată pe un stream SerialPort, sunt curios să văd care ar fi abordarea recomandată pentru a gestiona aceste cazuri.

Comentarii

  • Întrebarea dumneavoastră este foarte vagă. „Încă îmi lipsesc unele date uneori” este ca și cum i-ai spune mecanicului tău „mașina mea face un zgomot ciudat uneori” și ai întreba cât costă repararea acestuia. Poate că acest răspuns la o întrebare conexă vă poate ajuta. Cu toate acestea, cred că trebuie să fiți mult mai specific dacă doriți ajutor; așa cum este, nu sunt multe lucruri la care nu se poate răspunde dacă vă uitați la alte întrebări pe acest subiect. –  > Por Ken White.
  • Aveți dreptate, voi pune un exemplu real pentru a ilustra mai bine ce se întâmplă… –  > Por Yannick Blondeau.
  • Implementarea unui protocol de comunicare serială pe RS232 sau 485 este o sarcină foarte, foarte dificilă. Este nevoie de MULTĂ experiență. Am implementat acest lucru încă din vremurile bune și vechi ale DOS și încă mă blochez în unele capcane comune. De ce nu încercați să găsiți o ofertă terță parte de încredere pentru a vă ocupa de comunicațiile seriale? Probabil că ei vor fi eliminat toate multele, multele, multele, multele bug-uri în care vei cădea tu însuți 🙂 Dacă acesta este un exercițiu, atunci mergeți mai departe, vă va da o mare satisfacție să stăpâniți în sfârșit comunicațiile seriale! 🙂 –  > Por Loudenvier.
3 răspunsuri
MethodMan

Ai putea încerca ceva de genul acesta de exemplu cred că ceea ce vrei să utilizezi este port.ReadExisting() Metoda

 using System;
 using System.IO.Ports;

 class SerialPortProgram 
 { 
  // Create the serial port with basic settings 
    private SerialPort port = new   SerialPort("COM1",
      9600, Parity.None, 8, StopBits.One); 
    [STAThread] 
    static void Main(string[] args) 
    { 
      // Instatiate this 
      SerialPortProgram(); 
    } 

    private static void SerialPortProgram() 
    { 
        Console.WriteLine("Incoming Data:");
         // Attach a method to be called when there
         // is data waiting in the port's buffer 
        port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); 
        // Begin communications 
        port.Open(); 
        // Enter an application loop to keep this thread alive 
        Console.ReadLine();
     } 

    private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
    { 
       // Show all the incoming data in the port's buffer
       Console.WriteLine(port.ReadExisting()); 
    } 
}

Sau este doriți să o faceți pe baza a ceea ce ați încercat să faceți , puteți încerca acest lucru

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

Comentarii

  • Vă mulțumim pentru ajutor, în cele din urmă am ales ReadExisting utilizată cu o colecție blocantă. Încă mai am de gând să încerc noua ReadAsync funcție totuși… –  > Por Yannick Blondeau.
  • metoda processData() nu necesită un mutex? Adică, evenimentul datareceived ar putea să se declanșeze din nou atunci când processData() este încă în curs de execuție? nu-i așa? Deci, am putea ajunge să avem două (sau chiar mai multe?) fire de execuție în interiorul metodei processData()…. –  > Por Gianluca Ghettini.
  • Nu am încercat în această măsură și, pe baza a ceea ce a menționat Yannick în comentariul său de mai sus, mă gândesc că nu ar fi o diferență dacă ar continua să citească Asynchronously –  > Por MethodMan.
utilizator1184321

Am folosit un cod similar cu @MethodMan, dar a trebuit să urmăresc datele pe care le trimitea portul serial și să caut un caracter de terminare pentru a ști când portul serial a terminat de trimis date.

private string buffer { get; set; }
private SerialPort _port { get; set; }

public Port() 
{
    _port = new SerialPort();
    _port.DataReceived += new SerialDataReceivedEventHandler(dataReceived);
    buffer = string.Empty;
}

private void dataReceived(object sender, SerialDataReceivedEventArgs e)
{    
    buffer += _port.ReadExisting();

    //test for termination character in buffer
    if (buffer.Contains("r
"))
    {
        //run code on data received from serial port
    }
}

Comentarii

  • ReadLine() face deja acest lucru pentru tine. Nu este nevoie să verificați dacă
    r
    –  > Por Faizan Mubasher.
  • Dacă utilizați ReadLine() și au fost trimise mai multe răspunsuri, este posibil să nu le citiți pe toate. ReadExisting() va citi mai multe linii dacă acestea se află în memoria tampon. –  > Por Peter Boone.
Vimukthi Sineth
    using System;
    using System.IO.Ports;
    using System.Threading;

    namespace SerialReadTest
    {
        class SerialRead
        {
            static void Main(string[] args)
            {
        Console.WriteLine("Serial read init");
        SerialPort port = new SerialPort("COM6", 115200, Parity.None, 8, StopBits.One);
        port.Open();
        while(true){
          Console.WriteLine(port.ReadLine());
        }

    }
}
}