IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Graphique temps réél de données liaison série


Sujet :

VB.NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Novembre 2016
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 40
    Par défaut Graphique temps réél de données liaison série
    Bonjour,

    Je suis Newbie en VBnet et j'ai un soucis sur la mise en place d'un graphique en temps réel de données provenant de la liaison série. J'ai une carte électronique qui envoie une trame de données à 100Hz. L'envoi périodique démarre quand mon application envoie un "Start".

    Pour faire ça j'ai ajouté un chart et un bouton start à mon interface. Quand j'envoie la trame de démarrage, les données à 100Hz arrivent, c'est fluide pendant 5s puis ça lag énormément voir même de gros blocage, là est mon problème.

    A niveau de la liaison série, je crée une interruption dès que j'ouvre mon port COM et le sub "COM_RXHandler" stocke les données dans un buffer.

    Je lance un thread qui traite la trame et l'affichage des données dans le "chart". J'ai créé un delegate pour que mon thread puisse modifier le "chart". Le code géré dans le thread est une boucle infinie qui check un flag et ajoute les datas au "chart" si besoin (donc tout les 100Hz). J'ai aussi mis un DoEvents dans le thread.

    Je suis vraiment novice en VB (je ne fais que C pour microcontrôleur niveau programmation).

    Si quelqu'un à une idée de ce qui pourrait causer ce ralentissement.

  2. #2
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 198
    Par défaut
    fait voir le code ca sera plus simple

    déjà y a le doevents à éviter (c'est comme la Comic Sans ca fait partie des choses interdites ^^)
    le délégué il faudrait le begininvoke peut etre au lieu de l'invoke

    à un moment si tu te retrouves avec 20000 points alors que tu n'as que 2000 pixels de large sur ton écran il y a moyen d'en retirer pour gagner en perf sans perdre en précision

    après j'ai plus l'habitude de draw moi même que d'utiliser le chart d'ms, mais ca doit pouvoir fonctionner avec le char d'ms ^^
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre averti
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Novembre 2016
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 40
    Par défaut
    Hello,

    OK voici le code, je mets le principal sinon ce serait trop lourd. Si besoin d'explications pas de soucis, par contre il y a certainement de mauvaises choses que j'ai faites donc je suis preneur s'il y a des remarques. Comme je disais je suis Newbie en VB, je ne connais que le C, j'ai certainement des habitudes non adéquats pour du VB...

    Alors dans la classe générée par mon interface graphique on a :

    Création du thread d'analyse des trames du port série
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Dim ManageSerialPortThread As New Thread(AddressOf APP_ManageReceivedFrame)
    Delegate pour modifier le chart
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Delegate Sub SetChartCallback(ByVal Value1_U32 As Long, ByVal Value2_U32 As Long)
    Démarrage de l'application :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
        Private Sub MonApplication_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            ' Update the available port COM
            PortCOMNumber_CB.Items.Clear()
            For Each sp As String In My.Computer.Ports.SerialPortNames
                PortCOMNumber_CB.Items.Add(sp)
            Next
     
            'Start Serial port thread
            ManageSerialPortThread.Start()
     
            ' Start Timers
            Timer1.Start()
            Timer2.Start()
     
            ' Initialize chart
           MyChart.Series.Clear()
           MyChart.Titles.Add("MyChart")
     
            Serie1.Name = "MySerie"
            Serie1.ChartType = SeriesChartType.Line
            MyChart.Series.Add(Serie1)
        End Sub
    Fonction de gestion du port série gérée par un autre thread. Je ne l'ai pas mis mais il y a un "Handler" qui gère la réception des données du port série et lève le flag "COM_FrameReceived" pour que ce thread analyse la trame reçue.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    Sub APP_ManageReceivedFrame()
     
            While True
                If (COM_FrameReceived_B = False) And (COM_WaitForResponse_B = True) And (COM_TimeOutElapsed_B = True) Then
                    Me.SetInformationBox(Color.Red, "No response timeout")
                ElseIf COM_FrameReceived_B = True Then
                    COM_WaitForResponse_B = False
                    ' Control Frame
                    COM_ErrorReceived_U8 = COM_ControlReceivedFrame()
     
                    Select Case COM_ErrorReceived_U8
                        Case cCOM_LengthError_U8
                            Me.SetInformationBox(Color.Red, "Length error")
                        Case cCOM_CRCError_U8
                            Me.SetInformationBox(Color.Red, "CRC error")
                        Case cCOM_CommandError_U8
                            Me.SetInformationBox(Color.Red, "Command error")
                        Case cCOM_TreatmentOK_U8
                                Case &HA
                                        If BitConverter.IsLittleEndian Then
                                            TempBuffer_U8A(0) = COM_RxBuffer_U8A(7)
                                            TempBuffer_U8A(1) = COM_RxBuffer_U8A(6)
                                            TempBuffer_U8A(2) = COM_RxBuffer_U8A(5)
                                            TempBuffer_U8A(3) = COM_RxBuffer_U8A(4)
                                            Value1_U32 = BitConverter.ToUInt32(TempBuffer_U8A, 0)
                                            TempBuffer_U8A(0) = COM_RxBuffer_U8A(11)
                                            TempBuffer_U8A(1) = COM_RxBuffer_U8A(10)
                                            TempBuffer_U8A(2) = COM_RxBuffer_U8A(9)
                                            TempBuffer_U8A(3) = COM_RxBuffer_U8A(8)
                                            Value2_U32 = BitConverter.ToUInt32(TempBuffer_U8A, 0)
                                        Else
                                            TempBuffer_U8A(0) = COM_RxBuffer_U8A(4)
                                            TempBuffer_U8A(1) = COM_RxBuffer_U8A(5)
                                            TempBuffer_U8A(2) = COM_RxBuffer_U8A(6)
                                            TempBuffer_U8A(3) = COM_RxBuffer_U8A(7)
                                            Value1_U32 = BitConverter.ToUInt32(TempBuffer_U8A, 0)
                                            TempBuffer_U8A(0) = COM_RxBuffer_U8A(8)
                                            TempBuffer_U8A(1) = COM_RxBuffer_U8A(9)
                                            TempBuffer_U8A(2) = COM_RxBuffer_U8A(10)
                                            TempBuffer_U8A(3) = COM_RxBuffer_U8A(11)
                                            Value2_U32 = BitConverter.ToUInt32(TempBuffer_U8A, 0)
                                        End If
     
                                        Me.SetChart(Value1_U32, Value2_U32) 
                             End Select
                    COM_FrameReceived_B = False
                End If
            End While
        End Sub

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    Sub SetChart(ByVal Value1_U32 As Long, ByVal Value2_U32 As Long)
            If MyChart.InvokeRequired Then
                Dim d As New SetChartCallback(AddressOf SetChart)
                Me.Invoke(d, New Object() {Value1_U32, Value2_U32})
            Else
                Me.Serie1.Points.AddXY(Value1_U32 / 100, Value2_U32)
     
                Me.MyChart.ChartAreas(0).AxisX.Interval = 1
                If ((Value1_U32 / 100) >= 10) And ((Value1_U32 Mod 100) = 0) Then
                    Me.MyChart.ChartAreas(0).AxisX.Maximum = Value1_U32 / 100
                    Me.MyChart.ChartAreas(0).AxisX.Minimum = (Value1_U32 / 100) - 10
                    Me.MyChart.ChartAreas(0).AxisY.Maximum = Value2_U32 + 25000
                    Me.MyChart.ChartAreas(0).AxisY.Minimum = Value2_U32 - 25000
                    Me.MyChart.ChartAreas(0).RecalculateAxesScale()
                End If
            End If
        End Sub
    Sur ce dernier "sub" c'est là que j'update mon graphique. Value1 est un compteur multiple de 100ms. Le but d'updater le min et max des 2 axes et d'avoir un axe X glissant sur 10s (idem en Y).

    Accessoirement j'ai une autre question :

    - J'ai créé un module COMPort qui contient quelques "sub" qui gère l'envoie de trame sur le port série. J'aimerais y regrouper tout ce qui a trait au port série, par exemple, le sub ManageReceivedFrame du thread qui gère le port série et qui est actuellement défini dans la classe principale. Or dans ce thread j'ai des "delegate" appelé par des "Me.xxxxx" pour gérer de l'affichage graphique et on remonte une erreur parce qu'on ne peut employer un "Me" dans un autre module. Comment peut-on contourner ce problème ?

  4. #4
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 198
    Par défaut
    1ère chose, on ne met jamais (même s'il ne faut jamais dire jamais) un while true sans pause, sinon on prend facilement 100% des ressources d'un coeur processeur sans raison
    donc en début ou fin de boucle ajoute
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    system.threading.thread.sleep(x) ' avec x entre 1 et quelques milliers de millisecondes selon le degré d'urgence
    ' pour quelque chose à 100hz je serais tenté de dire entre 5 et 10

    sur l'optimisation du chart je n'ai pas trop d'idée pour l'instant, faudrait que je prenne le temps de le tester dans ce genre de conditions
    mais bon déjà en soulageant le processeur ca va ptete gagner un peu


    concernant le déplacement du code dans un module, Me correspond à l'instance de classe actuellement utilisée par l'exécution du code
    un module n'est pas une classe, donc pas d'instance, donc pas de Me
    le reste du code n'est pas génial, normalement on fait des classes et on évite le code linéaire et spaghetti
    après si c'est juste une petite appli tu peux laisser comme ca
    par contre dans ton module tu peux quand même repartir sur l'interface, y a plein de moyens moches de le faire facilement, mais mes doigts refusent d'écrire ces solutions
    idéalement faudrait transformer le module en classe, demander dans le constructeur un pointeur vers une méthode à appeler pour l'ajout d'un point
    du coup cette classe ne connaitra pas plus l'instance de form, mais tu pourras appeler la méthode pointée, ce qui aura le même effet
    ce paragraphe doit te paraitre obscur si tu n'es pas familier avec la POO (surement le cas), donc si tu veux aller dans ce sens idéalement lire un tuto là dessus ...
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 252
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 252
    Par défaut
    Salut,
    Je me permets d'intervenir même si je n'ai que très peu de connaissances en VB.NET car j'avais déjà fait une application C++ (il y a bien longtemps) pour loguer des données issues d'une carte à puce, via le port série, et c'est du même tonneau ici.

    Il faudrait savoir comment fonctionne l'objet "Chart" que tu fais gonfler au fur et a mesure des données qui arrivent par le port série. Moi j'avais rencontré un sacré problème en C++ car mon objet dont j'ai perdu le nom, gérait ça en dessin comme un bitmap et que je faisais gonfler au rythme des logues avec ma carte à puce et en moins de deux le dessin que l'objet me gérait était tellement énorme en mémoire que le PC était a la ramasse.

    J'ai donc opté pour du fenêtrage avec l'objet Chart.

    J'envoyais les données de la carte à puce directement dans un simple tableau en C++ et un thread venait lire et mettre dans un Chart (de manière fenêtrée/bornée) les données du tableau. Ce qui était complétement différent que de faire gonfler l'objet lui même et d'avoir en mémoire un dessin énorme. Pour donnée l'impression de temps réel, je mettais à jour les scrollbar uniquement. Si l'utilisateur voulait un zoom alors l'objet Chart ajustait le fenêtrage/borne avant de lire plus de données dans le tableau. Si il voulait faire défiler les données chronologiquement, idem c'est le fenêtrage qui avançait etc...

    Je ne sais pas si je suis clair ?
    Ou peut être que je n'ai rien compris a ton code et que c'est déjà ce que tu fais. Au quel cas inutile de t'attarder sur ce que j'ai écrit.

    A+

  6. #6
    Membre Expert
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2013
    Messages
    1 563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2013
    Messages : 1 563
    Par défaut
    Citation Envoyé par SamPirate62 Voir le message
    Quand j'envoie la trame de démarrage, les données à 100Hz arrivent, c'est fluide pendant 5s puis ça lag énormément voir même de gros blocage, là est mon problème.
    Tu reçois combien de points par seconde en moyenne? J'ai pas lu l'entièreté de la discussion, mais il est possible que le Chart encaisse mal le gros volume de données à l'affichage.

  7. #7
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 198
    Par défaut
    Citation Envoyé par SamPirate62 Voir le message
    (donc tout les 100Hz)
    même si c'est pas très français vu que "tous les" = fréquence et Hz = fréquence ^^
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  8. #8
    Membre averti
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Novembre 2016
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 40
    Par défaut
    Tu as tout à fait raison : "à 100Hz" ou "tout les 10ms" est plus français.

  9. #9
    Membre Expert
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2013
    Messages
    1 563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2013
    Messages : 1 563
    Par défaut
    Citation Envoyé par SamPirate62 Voir le message
    Tu as tout à fait raison : "à 100Hz" ou "tout les 10ms" est plus français.
    Tu reçois donc un point toutes les 10ms? Peux-tu vérifier si, au bout des 5 secondes tu as bien 500 points?

  10. #10
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    bonjour


    Vincent PETIT
    Il faudrait savoir comment fonctionne l'objet "Chart" que tu fais gonfler au fur et a mesure des données qui arrivent par le port série
    Perfectly la DataPointCollection de ChartControl.Points n'est pas elastique et ca finit par "hang" ...
    Ce code doit être revu possiblement comme suit (cela dépend de la "fenêtre de DataPoint" ou nombre de DataPoint à afficher ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
     
    Sub SetChart(ByVal Value1_U32 As Long, ByVal Value2_U32 As Long)
            If MyChart.InvokeRequired Then
                Dim d As New SetChartCallback(AddressOf SetChart)
                Me.Invoke(d, New Object() {Value1_U32, Value2_U32})
            Else
                  '****************
                  'nouveau code
                If Me.Serie1.Points.Count > 500 Then  'plus de 500 points à voir
                    Me.Serie1.Points.Remove(Me.Serie1.Points.Last)
                    Me.Serie1.Points.InsertXY(0, Value1_U32 / 100, Value2_U32)
                Else
                    Me.Serie1.Points.AddXY(Value1_U32 / 100, Value2_U32)
                End If 
     
                '****************
                Me.MyChart.ChartAreas(0).AxisX.Interval = 1
                If ((Value1_U32 / 100) >= 10) And ((Value1_U32 Mod 100) = 0) Then
                    Me.MyChart.ChartAreas(0).AxisX.Maximum = Value1_U32 / 100
                    Me.MyChart.ChartAreas(0).AxisX.Minimum = (Value1_U32 / 100) - 10
                    Me.MyChart.ChartAreas(0).AxisY.Maximum = Value2_U32 + 25000
                    Me.MyChart.ChartAreas(0).AxisY.Minimum = Value2_U32 - 25000
                    Me.MyChart.ChartAreas(0).RecalculateAxesScale()
                End If
            End If
        End Sub
    Cela a pour effet de maintenir un Serie.Points constant de 500 points ...
    bon code...

  11. #11
    Membre averti
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Novembre 2016
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 40
    Par défaut
    Bonjour,

    Désole de revenir si tardivement.

    Merci à tous pour vos réponses.

    J'ai bien 500 points au bout de 5s.
    J'ai testé le code de MABROUKI, ça me paraît être la bonne solution pour borner le graphe, par contre il faut retirer le "first" et non le "last" point. Le "insert XY" ne sert, il faut utiliser le "AddXY". Quand on supprime le premier point le tableau se décale automatiquement.

    Par contre mon graphe ne glisse pas au niveau de l'axe X.

    EDIT: j'arrive à avoir un graphe glissant, par contre j'ai toujours de gros problème de ralentissement même en bornant à 100 points au lieu de 500.

Discussions similaires

  1. Réponses: 2
    Dernier message: 15/04/2012, 01h13
  2. traitement temp réel de données port série
    Par lezebulon dans le forum Langages de programmation
    Réponses: 1
    Dernier message: 29/07/2010, 12h13
  3. problème récupération de données en liaison série
    Par prison_break dans le forum C++Builder
    Réponses: 4
    Dernier message: 27/06/2007, 08h51
  4. Comment capturer les données sur une liaison série RS232
    Par jef Orome dans le forum Windows Serveur
    Réponses: 3
    Dernier message: 02/04/2007, 18h14
  5. Réponses: 4
    Dernier message: 30/03/2007, 16h27

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo