2017-09-07 6 views
1

J'ai un joli programme C#, mais le traitement des octets reçus en série est beaucoup trop lent. Et je pense que je peux peut-être résoudre cela en utilisant un travailleur de fond, mais je n'ai aucune expérience avec elle et toutes mes tentatives antérieures ont échoué.C# Comment implémenter un arrière-plan dans cette configuration?

private void serial_DataReceived(object sender, SerialDataReceivedEventArgs e) 
     { 
      rxBuffer += serial.ReadExisting(); // add new bytes to the string 'rxBuffer' 

      this.Invoke(new EventHandler(serialReceived)); 
     } 

     private void serialReceived(object s, EventArgs e) 
     { 
      while (rxBuffer.Length > 0) // keep processing bytes until the string is empty 
      { 
       // textBox1.Text += rxBuffer[0]; 
       byte b = Convert.ToByte(rxBuffer[0]); 
       string hexValue = b.ToString("X"); 

       rxBuffer = rxBuffer.Remove(0, 1); // removes the 'captured' byte from the string 
       ..... 
       lots of code 

Cette boucle while représente essentiellement 75% de mon programme entier. Les octets incomming
contoll Les éléments d'interface utilisateur, ils peuvent stocker ou lire des fichiers texte et envoyer des octets sur le port série, il peut tout simplement faire à peu près tout.

Ce système fonctionne mais il est beaucoup trop lent. Donc, je pense que déplacer la boucle while dans un fond d'écran pourrait le résoudre. Comment est-ce que je peux implémenter un ouvrier d'arrière-plan dans la configuration de code actuelle?

Toutes mes tentatives ont jusqu'ici échoué.

EDIT: Je veux ajouter quelque chose que je viens de commenter ci-dessous. Je pensais que serial_DataReceived serait appelé avec chaque octet unique. Il se passe un délai de 2 ms entre 2 octets reçus suivant dans mon application. ReadExisting() retourne parfois plus de 1 octet. Il y a donc un certain retard dans l'événement en série. Je l'ai eu aussi en Qt mais cela n'a jamais été un problème, je pense que c'est une caractéristique de recevoir des cordes entières à la fois.

Personnellement, je pense que le invoke() rend tout lent, mais je n'ai aucune expérience antérieure avec C# donc je devine juste, de toute façon je suis ouvert à toutes les solutions.

+0

Voici un lien qui indique comment utiliser l'arrière-plan; https://stackoverflow.com/questions/6481304/how-to-use-a-backgroundworker –

+1

Quelle est la raison derrière l'utilisation de 'ReadExisting'? surtout si vous êtes réellement intéressé par les octets? =! [SerialPort.Read] (https://msdn.microsoft.com/fr-fr/library/ms143549 (v = vs.110) .aspx) lit les octets directement dans un tampon. Il semble que tout le traitement de chaîne est en fait le processus lent, si vous le mettez en arrière-plan, il ne sera pas plus rapide. Puisque vous avez déjà implémenté l'événement 'serial_DataReceived', votre processus est déjà sur un thread d'arrière-plan. –

+0

Que faites-vous dans 'beaucoup de code' de sorte qu'il nécessite un appel' Invoke'? L'appel le rend probablement si lent (et mon ancienne supposition sur le traitement des chaînes est fausse) –

Répondre

0

ce code semble être la solution. Je remarque que mon interface graphique fonctionne signicantly lisse

private void serial_DataReceived(object sender, SerialDataReceivedEventArgs e) 
    { 
     rxBuffer += serial.ReadExisting(); 

     try { backgroundWorker1.RunWorkerAsync(); } catch { } 
    } 


    private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) 
    { 
     //private void serialReceived(object s, EventArgs e) 
     //{ 
     while (rxBuffer.Length > 0) 
     { 
      // textBox1.Text += rxBuffer[0]; 
      byte b = Convert.ToByte(rxBuffer[0]); 
      string hexValue = b.ToString("X"); 

      rxBuffer = rxBuffer.Remove(0, 1); 

J'ai essayé d'utiliser le IsBusy() drapeau, mais ça n'a pas donc j'utiliser les blocs try et catch à la place. Le serial_Datar réceptionnant bien ajoute de nouveaux octets à la chaîne rxBuffer et l'arrière-plan s'assure que chaque octet de la chaîne rxString est traité.

EDIT: J'ai un problème, je ne peux pas contrôler mes éléments d'interface utilisateur à l'exception d'un panneau. Je viens de découvrir. J'essaie d'accéder aux éléments de l'interface utilisateur quand je suis encore dans un fil différent.

0

Je vois beaucoup cette question, où les gens envoient et reçoivent des commandes via le port série. J'ai un bon exemple ici https://stackoverflow.com/a/38536373/2009197 qui parle de l'utilisation d'un travailleur de fond et une machine d'état pour réaliser une communication asynchrone entre les ordinateurs/périphériques en série. Vous devrez invoquer la mise à jour de votre thread d'interface utilisateur car vous recevrez des données sur un thread distinct.