web-dev-qa-db-fra.com

Comment lire et écrire à partir du port série

Je commence tout juste à apprendre à envoyer et recevoir des données de mon matériel via l'interface graphique C #.

Quelqu'un peut-il s'il vous plaît écrire un détail commentliredonnées du port série?

35
CHIENSION

SerialPort (port COM série RS-232) en C # .NET
Cet article explique comment utiliser la classe SerialPort .NET dans .NET pour lire et écrire des données, déterminer les ports série disponibles sur votre ordinateur et comment envoyer des fichiers. Il couvre même les affectations de broches sur le port lui-même.

Exemple de code:

using System;
using System.IO.Ports;
using System.Windows.Forms;

namespace SerialPortExample
{
  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 class
      new SerialPortProgram();
    }

    private 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
      Application.Run();
    }

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

J'ai passé beaucoup de temps à utiliser SerialPort class et j'ai donc décidé d'utiliser SerialPort.BaseStream class à la place. Vous pouvez voir le code source: SerialPort-source et SerialPort.BaseStream-source pour une compréhension approfondie . J'ai créé et utilisé le code présenté ci-dessous. 

  • La fonction principale public int Recv(byte[] buffer, int maxLen) A son nom et fonctionne comme la socket recv() "bien connue". 

  • Cela signifie que 

    • dans une main il a un délai d'expiration pour aucune donnée et jette TimeoutException.
    • En revanche, lorsque des données ont été reçues,
      • il reçoit des données jusqu'à maxLen octets 
      • ou délai d'attente court (6 ms théoriques) dans le flux de données UART

.

public class Uart : SerialPort

    {
        private int _receiveTimeout;

        public int ReceiveTimeout { get => _receiveTimeout; set => _receiveTimeout = value; }

        static private string ComPortName = "";

        /// <summary>
        /// It builds PortName using ComPortNum parameter and opens SerialPort.
        /// </summary>
        /// <param name="ComPortNum"></param>
        public Uart(int ComPortNum) : base()
        {
            base.BaudRate = 115200; // default value           
            _receiveTimeout = 2000;
            ComPortName = "COM" + ComPortNum;

            try
            {
                base.PortName = ComPortName;
                base.Open();
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine("Error: Port {0} is in use", ComPortName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Uart exception: " + ex);
            }
        } //Uart()

        /// <summary>
        /// Private property returning positive only Environment.TickCount
        /// </summary>
        private int _tickCount { get => Environment.TickCount & Int32.MaxValue; }


        /// <summary>
        /// It uses SerialPort.BaseStream rather SerialPort functionality .
        /// It Receives up to maxLen number bytes of data, 
        /// Or throws TimeoutException if no any data arrived during ReceiveTimeout. 
        /// It works likes socket-recv routine (explanation in body).
        /// Returns:
        ///    totalReceived - bytes, 
        ///    TimeoutException,
        ///    -1 in non-ComPortNum Exception  
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="maxLen"></param>
        /// <returns></returns>
        public int Recv(byte[] buffer, int maxLen)
        {
            /// The routine works in "pseudo-blocking" mode. It cycles up to first 
            /// data received using BaseStream.ReadTimeout = TimeOutSpan (2 ms).
            /// If no any message received during ReceiveTimeout property, 
            /// the routine throws TimeoutException 
            /// In other hand, if any data has received, first no-data cycle
            /// causes to exit from routine.

            int TimeOutSpan = 2;
            // counts delay in TimeOutSpan-s after end of data to break receive
            int EndOfDataCnt;
            // pseudo-blocking timeout counter
            int TimeOutCnt = _tickCount + _receiveTimeout; 
            //number of currently received data bytes
            int justReceived = 0;
            //number of total received data bytes
            int totalReceived = 0;

            BaseStream.ReadTimeout = TimeOutSpan;
            //causes (2+1)*TimeOutSpan delay after end of data in UART stream
            EndOfDataCnt = 2;
            while (_tickCount < TimeOutCnt && EndOfDataCnt > 0)
            {
                try
                {
                    justReceived = 0; 
                    justReceived = base.BaseStream.Read(buffer, totalReceived, maxLen - totalReceived);
                    totalReceived += justReceived;

                    if (totalReceived >= maxLen)
                        break;
                }
                catch (TimeoutException)
                {
                    if (totalReceived > 0) 
                        EndOfDataCnt--;
                }
                catch (Exception ex)
                {                   
                    totalReceived = -1;
                    base.Close();
                    Console.WriteLine("Recv exception: " + ex);
                    break;
                }

            } //while
            if (totalReceived == 0)
            {              
                throw new TimeoutException();
            }
            else
            {               
                return totalReceived;
            }
        } // Recv()            
    } // Uart
1
Yakov

Notez que l'utilisation d'un événement SerialPort.DataReceived est facultative. Vous pouvez définir le délai d'attente approprié à l'aide de SerialPort.ReadTimeout et appeler en continu SerialPort.Read() après avoir écrit quelque chose sur un port jusqu'à obtenir une réponse complète. 

De plus, vous pouvez utiliser SerialPort.BaseStream property pour extraire un Stream instance sous-jacent. L’avantage d’utiliser une Stream est que vous pouvez facilement utiliser divers décorateurs:

var port = new SerialPort();
// LoggingStream inherits Stream, implements IDisposable, needen abstract methods and 
// overrides needen virtual methods. 
Stream portStream = new LoggingStream(port.BaseStream);
portStream.Write(...); // Logs write buffer.
portStream.Read(...); // Logs read buffer.

Pour plus d'informations, consultez:

0
Leonid Vasilev