2009-03-23 6 views
2

J'essaye d'écrire une application de test pour la série I/O (RS-232) avec plusieurs unités en C# et je rencontre un problème avec mon manque d'expérience de threading. m solliciter des commentaires pour une méthode plus connue.E/S asynchrones à plusieurs ports sur port série en C#

J'ai un pool de ports COM COM1-16 dont chacun peut lire/écrire à tout moment et j'ai besoin de pouvoir les gérer simultanément. Est-ce une situation pour un pool de threads? Qu'est-ce qui guide la structuration de cette applet? Après examen, je me demandais si j'avais vraiment besoin de faire des threads asynchrones ici, je pouvais simplement gérer les états pour chaque port COM et faire la logique de flux (c'est-à-dire, statemachine) pour chaque port COM individuellement.

Répondre

2

Une grande partie de la difficulté entourant le port série est centrée autour d'une hypothèse. L'hypothèse est que le port série reçoit des données en morceaux qui sont pratiques, et ce qui est attendu.

Voici un exemple. Je sais que mon récepteur GPS envoie des lignes (se termine avec CRLF). Ceci est un exemple de l'une des phrases NMEA:

$ GPGSV, 3,1,11,10,75,053,29,29,52,311,32,24,50,298,30,02,39,073,30 * 77

Cependant, le gestionnaire d'événements DataReceived des ports série peut (à plusieurs reprises sur mon PC) déclencher plusieurs fois avec des segments de ces données.

feu événement

- Données

1 $ 
2 GPGSV,3,1,11,10 
3 ,75,053,29,29,52,311,32,24,50,298,30,02,39,073,30*77 

Au lieu de combattre cela, je créé des routines qui reçoivent des données à chaque fois que l'événement se déclenche, et la file d'attente vers le haut. Quand j'ai besoin des données, j'appelle d'autres routines qui rassemblent les données en tailles de blocs Je veux. Donc, en utilisant mon exemple la première et la deuxième fois que j'appelle la ligne de lecture (ma ligne de lecture), je reçois une réponse vide. La troisième fois, je récupère toute la phrase NMEA.

La mauvaise nouvelle est que je ne fais pas de C#. Le code est ici SerialPort

Selon la vitesse des ports, les délégués peuvent ne pas être un bon choix. J'ai testé mes routines à près de 1Mbps en utilisant des délégués, et n'utilisant pas de délégués. À ces vitesses, ne pas utiliser les délégués était un meilleur choix.

Voici quelques conseils de ceux qui savent

Kim Hamilton

+1

@dbasnett - si vous avez une chaîne de terminaison connue, une autre approche est de définir la propriété SerialPort.NewLine (http://msdn.microsoft.com/en-us/library /system.io.ports.serialport.newline.aspx) à CRLF, puis utilisez SerialPort.ReadLine() (http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.readline. aspx). Cela vous assure d'obtenir des paquets complets. – mtrw

0

La façon dont .NET pour gérer est d'utiliser des événements et délégués. Cela finira par créer plusieurs threads, mais cela le fera d'une manière qui signifie que vous ne les créez pas explicitement. Si vous créez un gestionnaire d'événements et l'ajoutez à l'événement DataReceived de chaque port, lorsqu'un port reçoit des données, le gestionnaire d'événements est appelé sur un thread distinct. Naturellement, cela signifie que la méthode doit être réentrante et que l'accès à toutes les structures de données partagées doit être protégé contre les accès simultanés.

Votre routine de gestionnaire va faire quelque chose comme ce qui suit:

  1. Appel ReadExisting pour obtenir les données disponibles.
  2. Gérer les données.
  3. Terminé.
-1

Vous devez savoir à quelle vitesse le récepteur crache des données. Est-ce une fois par seconde, deux fois par seconde, 5 fois ...

J'ai eu ce même problème en lisant les données GPS. Vous devez utiliser le backgroundworker en C# pour mettre à jour vos variables, écran.

1

Si vous utilisez l'arrière-plan, vous ne saisirez pas les petites données , vous obtiendrez la chaîne entière. Vous avez besoin quelque chose comme:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    try 
    { 
     serialPort1.Open(); 
     if (serialPort1.IsOpen) 
     { 
      while (keepReading) 
      { 
       backgroundWorker1.ReportProgress(0, serialPort1.ReadLine()); 
       //backgroundWorker1.ReportProgress(0, sentence.Split(',')); 
       // split_gps_data(); 
      } 
     } 
    } 
} 
Questions connexes