Réception de trames en RS232

[Résolu]
Signaler
Messages postés
19
Date d'inscription
mercredi 18 janvier 2012
Statut
Membre
Dernière intervention
21 juillet 2012
-
Messages postés
14813
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
25 juillet 2021
-
Bonjour,

Dans le cadre d'un projet universitaire je dois créer une interface en VB.NET afin de visualiser en temps réel les productions d'énergie d'une éolienne et de panneaux solaires. Ceux-ci sont reliés à un compteur d'impulsions qui doit communiquer avec l'interface VB en RS232. J'ai commencé a éditer ce programme mais n'y connaissant pas grand chose en programmation je me suis heurté à plusieurs problèmes, en particulier l'envoi et la réception des trames de réponse de la part du compteur. En effet lorsqu'une trame est envoyée celle-ci est bien visible à l'oscilloscope mais le compteur ne réagit pas ; de plus je ne sais pas comment programmer l'interface pour qu'elle m'affiche les trames renvoyées par le compteur. Quelqu'un aurait-il quelques idées ? Voici le code en VB.NET :

 Public Function Stringvershexa(ByVal trame As String) As String
        'Convertit une string en char hexa pour en faire une trame hexa RTU

        Dim i, j As Integer

        i 1 : Stringvershexa ""
        While (i < Len(trame))
            j = CInt("&H" & Mid(trame, i, 2))
            Stringvershexa = Stringvershexa & Chr(j)
            i = i + 2
        End While
    End Function

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click

        Dim trame As String

        trame = "FE 10 00 0A 00 02 04 00 00 00 00 C1 4B"
        SerialPort1.Write(trame, 0, trame.Length)


    End Sub


    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        ReceivedText(SerialPort1.ReadExisting())    'Automatiquement activé dès que le port série reçoit une information
    End Sub
    Private Sub ReceivedText(ByVal [texte] As String)
        'Compare la chaîne envoyée à celle qui est reçue
        If Me.RtbReceived.InvokeRequired Then
            Dim x As New SetTextCallback(AddressOf ReceivedText)
            Me.Invoke(x, New String() {(texte)})
        Else
            Me.RtbReceived.Text &= [texte]
        End If
    End Sub

    Private Sub cmbPort_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbPort.SelectedIndexChanged
        If SerialPort1.IsOpen = False Then
            SerialPort1.PortName = cmbPort.Text         'Affiche un messagebox à l'utilisateur dès qu'il change de port
        Else                                            'sans s'être déconnecté au préalable.
            MsgBox("Port Ouvert", vbCritical)
        End If
    End Sub

    Private Sub cmbBaud_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbBaud.SelectedIndexChanged
        If SerialPort1.IsOpen = False Then
            SerialPort1.BaudRate = cmbBaud.Text         'Affiche un msgbox à l'utilisateur dès qu'il modifie la vitesse
        Else                                            'sans s'être déconnecté au préalable
            MsgBox("Port Ouvert", vbCritical)
        End If
    End Sub
   
    Private Sub BtnSend2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnSend2.Click
        Dim trame2, trame3 As String
        trame2 = "FE 10 01 5E 00 0B 16 00 0A 01 2C 57 6B 00 68 1C BA 68 5D 57 6B 68 00 00 00 00 00 00 00 D5 16"
        trame3 = "FE 10 01 72 00 01 02 99 13 D2 2B"
        SerialPort1.Write(trame2, 0, trame2.Length)
        Threading.Thread.Sleep(300)
        SerialPort1.Write(trame3, 0, trame3.Length)

    End Sub
End Class

34 réponses

Messages postés
19
Date d'inscription
mercredi 18 janvier 2012
Statut
Membre
Dernière intervention
21 juillet 2012

Bonjour,

Ah oui pardon le &h03 je pensais "lecture" mais j'ai écrit "écriture"^^. Merci beaucoup pour l'astuce, j'ai mis un peu de temps à comprendre mais j'ai réussi à afficher ma trame coupée sous forme de MessageBox pour le moment. J'ai également eu quelques erreurs concernant des exceptions de dépassement d'index mais j'ai réussi à les résoudre en effectuant un Try..Catch..End Try grâce à l'aide à ce sujet sur msdn.

En revanche je souhaiterais savoir ce que signifient le "*" et le "+" dans le code, enfin plutôt la raison pour laquelle il faut les mentionner, parce que j'ai essayé en les retirant et je n'ai pas remarqué de différence.

Aussi à propos du décalage, il faut le fixer en mettant des multiples de 256 ? Parce qu'en changeant ces valeurs, mes MessageBox ne m'affichent toujours que la valeur décimale d'un seul octet pris un à un. De plus, je ne parviens pas à commencer ma séparation à un point précis de la trame, les découpages s'effectuant dès le début de celle-ci.
Messages postés
14813
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
25 juillet 2021
156
Bonjour,

Dans le code, les += et *= permettent de raccourcir le code :
a*=b est équivalent à a=a*b
a+=b est équivalent à a=a+b

Le décalage (multiplication) par 256 permet de convertir les valeurs binaire 4 octets en Int 32 bits.
C'est une décomposition de :
Result=(((a*256+b)*256+c)*256+d)

Concernant le décalage, si X est l'index de la valeur (0 = valeur 9B 54 00 01 pour ton exemple) :

MonIndexDeBase=3+X*4
avec un tableau de base 0

Si tu as des erreurs avec les tableaux, postes ton code afin de voir où se situe l'erreur.

---------------------------------------------------------------------
[list=ordered][*]Pour poser correctement une question et optimiser vos chances d'obtenir des réponses, pensez à lire le règlement CS, ce lien ou encore celui-ci[*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]Si votre problème est résolu (et uniquement si c'est le cas), pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Messages postés
19
Date d'inscription
mercredi 18 janvier 2012
Statut
Membre
Dernière intervention
21 juillet 2012

Bonjour,

Merci de m'avoir éclairci à propos des "*=" et "+=" !

Par contre je n'ai pas très bien compris ce que tu veux dire à propos d'index de base.
Le nombre "4" dans ton calcul, il s'agit du nombre d'octets que je veux mettre dans mon tableau ?

Quand par exemple je prends mon code :

Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived


        Dim nb_octets As Integer = SerialPort1.BytesToRead 'on lit le nombre d'octets présents dans le tampon.

        Dim trame(nb_octets - 1) As Byte 'tableau accueillant les données au format byte.

        SerialPort1.Read(trame, 0, nb_octets) 'lecture du port.

        Dim lTrame As Long
        Try
            lTrame += trame(0)
            lTrame *= 256
           

        Catch ex As IndexOutOfRangeException

            Console.WriteLine("IndexOutOfRangeException caught")

        End Try


        Try

            MsgBox(trame(0))
          

        Catch ex As IndexOutOfRangeException

            Console.WriteLine("IndexOutofRangeException caught")

        End Try


lTrame+=trame(0), signifie bien que je m'intéresse à l'index 0 de mon tableau "trame" ?
Messages postés
19
Date d'inscription
mercredi 18 janvier 2012
Statut
Membre
Dernière intervention
21 juillet 2012

Bonjour,

J'ai bien compris ton explication concernant la formule 3+4X et je l'ai adaptée à mon code ; cependant je ne parviens pas à voir les valeurs décimales formées par les quatuors d'octets (affichage par MessageBox dans un premier temps). De plus j'ai toujours ce problème de dépassement d'index qui est compensé par le Try...Catch mais je ne comprends justement pas pourquoi les tableaux seraient vides alors que je reçois des octets... Par contre j'ai également pensé à une chose concernant la conversion : si le programme me convertit en décimal un groupe de quatre octets (par ex le premier 9B 54 00 01), il les lira comme ils sont écrits ou il les lira 19B54, en tenant compte des poids faible/fort ?

Voici le code de l'évènement DataReceived que j'ai modifié : peux-tu me dire où sont mes erreurs ? Merci.

 Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived



        Dim nb_octets As Integer = SerialPort1.BytesToRead 'lecture du nombre d'octets présents dans le tampon.

        Dim trame(nb_octets - 1) As Byte 'tableau accueillant les données au format byte.

        SerialPort1.Read(trame, 0, nb_octets) 'lecture du port.

        Dim Index, i As Integer

        Dim lTrame(Index) As Byte


        For i = 0 To 7 'itération pour l'index de la valeur du premier octet pour chaque compteur à enregistrer ( 3 à 31)


            Try
                Index = 3 + 4 * i 'Index de la valeur du premier octet pour chaque compteur enregistré

                ' MsgBox(Index)

                lTrame(Index) *= 256


                MsgBox(lTrame(Index))

            Catch ex As IndexOutOfRangeException

                Console.WriteLine("IndexOutofRangeException caught")

            End Try

        Next
Messages postés
14813
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
25 juillet 2021
156
Bonjour,

lTrame(Index) *= 256
Avec :
Dim lTrame(Index) As Byte

Je pense que tu ne comprends pas le but du code que je t'ai montré pour faire le conversion.

Car, 2*256=512 et ça ne tient pas sur un Byte.

---------------------------------------------------------------------
[list=ordered][*]Pour poser correctement une question et optimiser vos chances d'obtenir des réponses, pensez à lire le règlement CS, ce lien ou encore celui-ci[*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]Si votre problème est résolu (et uniquement si c'est le cas), pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Messages postés
19
Date d'inscription
mercredi 18 janvier 2012
Statut
Membre
Dernière intervention
21 juillet 2012

Bonjour,

J'ai compris la multiplication par 256 dans la décomposition, seulement quand je code mon programme je me rends compte qu'il effectue le produit par 256 de la valeur décimale de mon octet de l'index du tableau concerné et non de la valeur lue en binaire... Pour définir la lecture binaire il faut bien passer par le paramètre IO.BinaryReader ? Je n'ai pas trouvé comment présenter ça dans le code.
Messages postés
19
Date d'inscription
mercredi 18 janvier 2012
Statut
Membre
Dernière intervention
21 juillet 2012

Ah non ça n'a rien à voir ! A la main je trouve le bon résultat en effectuant la décomposition mais en l'adaptant au programme, suivant ce que tu m'as dit, je n'ai rien qui s'affiche et toujours cette erreur récurrente de dépassement d'index, pourtant le tableau ne devrait pas être vide !
Messages postés
14813
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
25 juillet 2021
156
Bonjour,

A l'occasion, lis le point 1 de ma signature.

Et si dans ton Try/Catch tu mets :
Dim lValue as Integer=0
Index = 3 + 4 * i 'Index de la valeur du premier octet pour chaque compteur enregistré
lValue+=lTrame(Index) * 256
Index+=1
lValue+=lTrame(Index) * 256
Index+=1
lValue+=lTrame(Index) * 256
Index+=1
lValue+=lTrame(Index) * 256

MessageBox.Show(lValue.Tostring)


C'est mieux ?

Concernant l'exception, tu as 8 valeurs à lire ?

---------------------------------------------------------------------
[list=ordered][*]Pour poser correctement une question et optimiser vos chances d'obtenir des réponses, pensez à lire le règlement CS, celui-ci pour bien poser votre question ou encore celui-ci pour les PFE et autres exercices[*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]En VB.NET pensez à activer Option Explicit et Option Strict (propriété du projet) et à retirer l'import automatique de l'espace de nom Microsoft.VisualVasic (onglet Références dans les propriétés du projet).
[*]Si votre problème est résolu (et uniquement si c'est le cas), pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Messages postés
19
Date d'inscription
mercredi 18 janvier 2012
Statut
Membre
Dernière intervention
21 juillet 2012

Bonjour,

J'ai essayé et j'ai toujours des problèmes de dépassement d'index... C'est lassant. Je vais revoir les cours de vb sur le net un peu plus profondément, quelque chose a dû m'échapper. Je me laisse un mois pour trouver la solution ça devrait suffire. Sinon oui j'ai huit valeurs à lire. Par contre je ne vois pas le rapport avec le point 1 de ta signature.
Messages postés
14813
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
25 juillet 2021
156
Bonjour,

Désolé pour le temps de réponse.
As-tu regardé en pas à pas, car comme ça, je ne comprend pas vpourquoi ça pose pb..

---------------------------------------------------------------------
[list=ordered][*]Pour poser correctement une question et optimiser vos chances d'obtenir des réponses, pensez à lire le règlement CS, celui-ci pour bien poser votre question ou encore celui-ci pour les PFE et autres exercices[*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]En VB.NET pensez à activer Option Explicit et Option Strict (propriété du projet) et à retirer l'import automatique de l'espace de nom Microsoft.VisualVasic (onglet Références dans les propriétés du projet).
[*]Si votre problème est résolu (et uniquement si c'est le cas), pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Messages postés
19
Date d'inscription
mercredi 18 janvier 2012
Statut
Membre
Dernière intervention
21 juillet 2012

Bonsoir,

Pas de problème pour le temps de réponse, je n'ai plus mis le nez dans le programme depuis la dernière fois(en effet les projets étant officiellement terminés depuis deux mois, je le poursuis pour mon compte et de mon propre chef alors je prends un peu mon temps^^). Alors j'ai effectué quelques modifications dans mon code et je me suis débarrassé des messages de dépassement d'index (sans trop savoir comment d'ailleurs), et j'obtiens également les valeurs que je souhaite avoir, en reprenant et changeant quelques paramètres dans le code que tu m'as proposé. Je n'ai pas encore essayé pour tous les compteurs, mais à ce niveau je pense que ça devrait aller. Voici le code que j'ai écrit pour le premier compteur, en l'occurrence le mot correspondant à la valeur de sa production dans les exemples précédents étant 9B 54 00 01, (respectivement aux index 3, 4,5 et 6 de la trame complète) j'ai fait faire au programme le calcul en prenant l'ordre des index 5, 6 , 3 et 4 et en ajoutant les parenthèses où il faut j'obtiens la bonne valeur =). Reste à l'afficher dans un label au lieu d'une MsgBox. :
 Try

            Dim longtrame As Integer = 0


            Index = 5 'Index de la valeur du premier octet pour chaque compteur enregistré
            longtrame = (longtrame + trame(Index)) * 256
            Index += 1
            longtrame = (longtrame + trame(Index)) * 256
            Index -= 3
            longtrame = (longtrame + trame(Index)) * 256
            Index += 1
            longtrame = (longtrame + trame(Index))

            MessageBox.Show(longtrame.ToString)

        Catch ex As IndexOutOfRangeException

            Console.WriteLine("IndexOutofRangeException caught")

        End Try


Je reprends tantôt la programmation de mon interface, il faut que je modifie un peu mon code pour le tester directement avec le compteur. A ce stade il me reste à savoir créer une temporisation pour actualiser périodiquement les valeurs et à m'intéresser à la création de courbes en temps réel pour les différentes productions énergétiques... Je vais voir tout ça et je te tiens au courant si j'ai d'autres difficultés^^ En tout cas, merci d'avoir considéré mon problème jusqu'à maintenant ; ton aide m'est providentielle si je puis ainsi dire !
Messages postés
14813
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
25 juillet 2021
156
Bonjour,

D'accord, bon courage, je reste attentif à tes demandes :)

---------------------------------------------------------------------
[list=ordered][*]Pour poser correctement une question et optimiser vos chances d'obtenir des réponses, pensez à lire le règlement CS, celui-ci pour bien poser votre question ou encore celui-ci pour les PFE et autres exercices[*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]En VB.NET pensez à activer Option Explicit et Option Strict (propriété du projet) et à retirer l'import automatique de l'espace de nom Microsoft.VisualVasic (onglet Références dans les propriétés du projet).
[*]Si votre problème est résolu (et uniquement si c'est le cas), pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Messages postés
19
Date d'inscription
mercredi 18 janvier 2012
Statut
Membre
Dernière intervention
21 juillet 2012

Bonsoir,

Alors je sollicite encore ton aide car j'ai un un nouveau problème ; je pense que ça n'est pas grand chose mais je n'ai pas encore trouvé de moyen pour le résoudre. Donc, je récupère bien les trames qui me sont envoyées par le compteur et elles sont parfaitement bien converties grâce à l'algorithme. J'ai fait afficher les valeurs sous TextBox au lieu de MessageBox pour pouvoir lire tout en même temps sans avoir à cliquer à chaque fois sur le boîte de dialogue. Le hic est que le programme ne me fait pas apparaître exactement les bonnes valeurs. En effet, la valeur exacte apparaît dans le TextBox mais elle est sitôt remplacée par une valeur qui n'a strictement rien à voir avec la précédente (en général elle est beaucoup plus grande, de l'ordre du million). J'avais déjà remarqué ce phénomène en lisant les valeurs par boîtes de dialogue : je reçois ma trame, la boîte de dialogue s'ouvre avec la valeur que je souhaite, je clique sur "ok" et une autre boîte de dialogue s'ouvre avec une autre valeur n'ayant rien à voir. Au début je n'y avais pas prêté attention puisque la valeur désirée apparaissait en premier mais il se trouve qu'avec l'affichage en TextBox, celle-ci ne retient que la seconde valeur. Pour l'affichage sur TextBox, j'ai créé des fonctions faisant un appel avec Invoke pour l'exécution sur un thread séparé, pour chaque compteur. La valeur obtenue est du type "Double" et je l'ai convertie en "string" pour qu'elle soit utilisée dans chaque fonction. Je pense qu'à ce niveau là mon code est bon, mais je ne vois pas comment passer outre les secondes valeurs, erronées, qui sont retenues à l'affichage. Je ne sais pas si tu as compris ce que je veux dire ? Voici un extrait de mon code (syntaxe pour les deux premiers compteurs, le reste étant la même chose), si tu veux je peux mettre des captures d'écran de ce que je reçois comme valeurs :
    Private Sub SetText1(ByVal [text] As Object)
        'Procédure permettant l'appel de la TextBox sur un autre Thread, compteur 1
        If Me.TxtCompteur1.InvokeRequired Then
            Dim x As New SetTextCallback(AddressOf SetText1)
            Me.Invoke(x, New Object() {(text)})
        Else
            Me.TxtCompteur1.Text = [text]
        End If
    End Sub
 Private Sub SetText2(ByVal [text] As String)
        'Procédure permettant l'appel de la TextBox sur un autre Thread, compteur 2
        If Me.TxtCompteur2.InvokeRequired Then
            Dim y As New SetTextCallback(AddressOf SetText2)
            Me.Invoke(y, New Object() {(text)})
        Else
            Me.TxtCompteur2.Text = [text]
        End If
    End Sub

Public Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived

        Dim nb_octets As Double = SerialPort1.BytesToRead 'lecture du nombre d'octets présents dans le tampon.


        Dim trame(nb_octets) As Byte  'tableau accueillant les données au format byte.


        SerialPort1.Read(trame, 0, nb_octets) 'lecture du port.

        Dim Index, Index1, Index2, Index3, Index4, Index5, Index6, Index7 As Integer

        Try
            'Compteur 1
            Dim longtrame As Double = 0

            Index = 5 'Index de la valeur du premier octet pour chaque compteur enregistré
            longtrame = (longtrame + trame(Index)) * 256
            Index += 1
            longtrame = (longtrame + trame(Index)) * 256
            Index -= 3
            longtrame = (longtrame + trame(Index)) * 256
            Index += 1
            longtrame = (longtrame + trame(Index))
            longtrame = longtrame * 0.1

            Dim longtrame_chaine As String = CStr(longtrame)


            SetText1(longtrame_chaine)

            'MessageBox.Show(longtrame_chaine)

        Catch ex As IndexOutOfRangeException

            Console.WriteLine("IndexOutofRangeException caught")

        End Try

        Try
            'Compteur 2
            Dim longtrame1 As Double = 0

            Index1 = 9 'Index de la valeur du premier octet pour chaque compteur enregistré
            longtrame1 = (longtrame1 + trame(Index1)) * 256
            Index1 += 1
            longtrame1 = (longtrame1 + trame(Index1)) * 256
            Index1 -= 3
            longtrame1 = (longtrame1 + trame(Index1)) * 256
            Index1 += 1
            longtrame1 = (longtrame1 + trame(Index1))
            longtrame1 = longtrame1 * 0.1

            Dim longtrame_chaine1 As String = CStr(longtrame1)


            SetText2(longtrame_chaine1)

            'MessageBox.Show(longtrame_chaine)

        Catch ex As IndexOutOfRangeException

            Console.WriteLine("IndexOutofRangeException caught")

        End Try
Messages postés
14813
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
25 juillet 2021
156
Bonjour,

Cet effet peut se produire, si tu décales ta réception d'un octet par exemple.

E, .NET, évites CStr, préfères plutôt Utiliser MaVar.ToString().

A la place de déclarer tes varialbes de travail en Double, essyes plutot UInt32, Int64 ou encore UItn64.

Essayes de mettre un test de ce genre dans ta réception :
If MaVar>1000000 Then
#IF DEBUG Then
    Stop
#EndIf
End If


---------------------------------------------------------------------
[list=ordered][*]Pour poser correctement une question et optimiser vos chances d'obtenir des réponses, pensez à lire le règlement CS, celui-ci pour bien poser votre question ou encore celui-ci pour les PFE et autres exercices[*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]En VB.NET pensez à activer Option Explicit et Option Strict (propriété du projet) et à retirer l'import automatique de l'espace de nom Microsoft.VisualVasic (onglet Références dans les propriétés du projet).
[*]Si votre problème est résolu (et uniquement si c'est le cas), pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---