22 votes

Comment puis-je utiliser l'événement dataReceived de l'objet portuaire SerialPort en C# ?

J'essaie de créer une petite application pour collecter les données reçues d'un capteur externe connecté à COM10. J'ai réussi à créer un petit objet de console C# et une application qui ouvre le port et transmet les données à un fichier pendant une période fixe en utilisant une boucle for.

Je voudrais convertir cette application pour utiliser l'événement dataReceived à la place du flux. Après avoir lu le Les 5 meilleures astuces de SerialPort Je n'arrive toujours pas à le faire fonctionner et je ne sais pas ce qui me manque. J'ai réécrit l'application console de sorte que tout le code se trouve dans Main et est collé ci-dessous. Quelqu'un peut-il m'expliquer pourquoi le gestionnaire d'événement port_OnReceiveDatazz n'est pas appelé alors que je sais que des données sont envoyées au port par le matériel ?

Gracias

Merci à @Gabe , @Jason Down y @abatishchev pour toutes les suggestions. Je suis dans l'impasse et je n'arrive pas à faire fonctionner le gestionnaire d'événements. Peut-être que cela a quelque chose à voir avec l'appareil. Je peux me contenter de lire le port dans un thread et de transmettre les données directement au fichier.


Code


namespace serialPortCollection
{   class Program
    {
        static void Main(string[] args)
        {

            const int bufSize = 2048;
            Byte[] buf = new Byte[bufSize]; //To store the received data.

            SerialPort sp = new SerialPort("COM10", 115200);
            sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler

            sp.Open();
            sp.WriteLine("$"); //Command to start Data Stream

            // Wait for data or user input to continue.
            Console.ReadLine();

            sp.WriteLine("!"); //Stop Data Stream Command
            sp.Close();
        }

       // My Event Handler Method
        private static void port_OnReceiveDatazz(object sender, 
                                   SerialDataReceivedEventArgs e)
        {
            SerialPort spL = (SerialPort) sender;
            const int bufSize = 12;
            Byte[] buf = new Byte[bufSize];
            Console.WriteLine("DATA RECEIVED!");
            Console.WriteLine(spL.Read(buf, 0, bufSize));
        }
    }
}

15voto

Jason Down Points 13690

Je pense que votre problème est la ligne : **

sp.DataReceived += port_OnReceiveDatazz ;

Ça ne devrait pas l'être :

sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz) ;

**La syntaxe est correcte (je n'avais pas réalisé le raccourci au moment où j'ai répondu à cette question).

J'ai également vu des suggestions selon lesquelles vous devriez activer les options suivantes pour votre port série :

sp.DtrEnable = true;    // Data-terminal-ready
sp.RtsEnable = true;    // Request-to-send

Il se peut que vous deviez également définir le handshake sur RequestToSend (via l'énumération handshake).


UPDATE :

J'ai trouvé une suggestion qui dit que vous devez d'abord ouvrir votre port, puis assigner le gestionnaire d'événement. Peut-être que c'est un bug ?

Donc, au lieu de ça :

sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);
sp.Open();

Faites-le :

sp.Open();
sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);

Faites-moi savoir comment ça se passe.

8voto

Gabe Points 1664

Tout d'abord, je vous recommande d'utiliser le constructeur suivant au lieu de celui que vous utilisez actuellement :

new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);

Ensuite, vous devriez vraiment supprimer ce code :

// Wait 10 Seconds for data...
for (int i = 0; i < 1000; i++)
{
    Thread.Sleep(10);
    Console.WriteLine(sp.Read(buf,0,bufSize)); //prints data directly to the Console
}

Et au lieu de cela, il suffit de boucler jusqu'à ce que l'utilisateur appuie sur une touche ou quelque chose, comme ça :

namespace serialPortCollection
{   class Program
    {
        static void Main(string[] args)
        {
            SerialPort sp = new SerialPort("COM10", 115200);
            sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler

            sp.Open();
            sp.WriteLine("$"); //Command to start Data Stream

            Console.ReadLine();

            sp.WriteLine("!"); //Stop Data Stream Command
            sp.Close();
        }

       // My Event Handler Method
        private static void port_OnReceiveDatazz(object sender, 
                                   SerialDataReceivedEventArgs e)
        {
            SerialPort spL = (SerialPort) sender;
            byte[] buf = new byte[spL.BytesToRead];
            Console.WriteLine("DATA RECEIVED!");
            spL.Read(buf, 0, buf.Length);
            foreach (Byte b in buf)
            {
                Console.Write(b.ToString());
            }
            Console.WriteLine();
        }
    }
}

Notez également les révisions apportées au gestionnaire d'événement de réception de données, qui doit maintenant imprimer le tampon.

MISE À JOUR 1


Je viens d'exécuter le code suivant avec succès sur ma machine (en utilisant un câble null modem entre COM33 et COM34)

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread writeThread = new Thread(new ThreadStart(WriteThread));
            SerialPort sp = new SerialPort("COM33", 115200, Parity.None, 8, StopBits.One);
            sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler

            sp.Open();
            sp.WriteLine("$"); //Command to start Data Stream

            writeThread.Start();

            Console.ReadLine();

            sp.WriteLine("!"); //Stop Data Stream Command
            sp.Close();
        }

        private static void port_OnReceiveDatazz(object sender, 
                                   SerialDataReceivedEventArgs e)
        {
            SerialPort spL = (SerialPort) sender;
            byte[] buf = new byte[spL.BytesToRead];
            Console.WriteLine("DATA RECEIVED!");
            spL.Read(buf, 0, buf.Length);
            foreach (Byte b in buf)
            {
                Console.Write(b.ToString() + " ");
            }
            Console.WriteLine();
        }

        private static void WriteThread()
        {
            SerialPort sp2 = new SerialPort("COM34", 115200, Parity.None, 8, StopBits.One);
            sp2.Open();
            byte[] buf = new byte[100];
            for (byte i = 0; i < 100; i++)
            {
                buf[i] = i;
            }
            sp2.Write(buf, 0, buf.Length);
            sp2.Close();
        }
    }
}

MISE À JOUR 2


Compte tenu de tout le trafic sur cette question récemment. Je commence à soupçonner que votre port série n'est pas configuré correctement, ou que le périphérique ne répond pas.

Je vous recommande vivement d'essayer de communiquer avec l'appareil par d'autres moyens (j'utilise fréquemment hyperterminal). Vous pouvez ensuite jouer avec tous ces paramètres (débit binaire, parité, bits de données, bits d'arrêt, contrôle de flux) jusqu'à ce que vous trouviez le jeu qui fonctionne. La documentation de l'appareil devrait également préciser ces paramètres. Une fois que j'ai trouvé ces paramètres, je m'assure que mon SerialPort .NET est configuré correctement pour utiliser ces paramètres.

Quelques conseils pour configurer le port série :

Notez que lorsque j'ai dit que vous devriez utiliser le constructeur suivant, je voulais dire que vous devriez utiliser cette fonction, pas nécessairement ces paramètres ! Vous devez remplir les paramètres pour votre appareil, les paramètres ci-dessous sont communs, mais peuvent être différents pour votre appareil.

new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);

Il est également important que vous configuriez le SerialPort .NET pour utiliser le même contrôle de flux que votre périphérique (comme d'autres personnes l'ont indiqué précédemment). Vous pouvez trouver plus d'informations ici :

http://www.lammertbies.nl/comm/info/RS-232_flow_control.html

4voto

Justin Wignall Points 2040

J'ai eu le même problème avec un modem qui fonctionnait auparavant et qui, un jour, a cessé de déclencher l'événement DataReceived.

La solution dans mon cas, très aléatoire, a été d'activer le RTS par exemple.

sp.RtsEnable = true;

Je n'ai aucune idée de la raison pour laquelle cela a fonctionné sur cet appareil particulier (je ne suis pas du tout un spécialiste des communications), ni pourquoi cela a fonctionné puis s'est arrêté, mais cela pourrait aider quelqu'un d'autre un jour, alors je le poste juste au cas où...

3voto

abatishchev Points 42425

A propos, vous pouvez utiliser le code suivant dans votre gestionnaire d'événement :

switch(e.EventType)
{
  case SerialData.Chars:
  {
    // means you receives something
    break;
  }
  case SerialData.Eof:
  {
    // means receiving ended
    break;
  }
}

1voto

Matt Points 21

Je pense que cela ne fonctionnera pas parce que vous utilisez une application console et qu'il n'y a pas de boucle d'événement en cours d'exécution. Une boucle d'événement / pompe à messages utilisée pour la gestion des événements est configurée automatiquement lors de la création d'une application Winforms, mais pas pour une application console.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X