Le CRC16 en ModBus

Quand on parle de communication entre une machine et un PC (ou un automate), c’est un dialogue en question/réponse. Mais si on peut envoyer n’importe quoi, il faut quand même que la machine comprenne en quelle langue on parle et comment décoder la trame. Pour ce faire, on utilise le CRC (Contrôle de redondance cyclique) et il en existe plusieurs en fonction du type de codage utilisé (8, 16 ou 32 bits) pour la communication.

Le plus souvent, on utilise un CRC16, c’est le système le plus courant, l’autre étant le 32 bits (CRC32).

Le calcul du CRC fait appel à des notions de programmation logique avec des OR, XOR, AND et XAND… autant dire que si on ne connait pas c’est le bordel, et même moi qui connait le principe je n’arrive pas à le traduire en code. Ci dessous vous trouverez deux fonctions, CRC16 et AddCRC16 :

  • CRC16 : renvoie un tableau contenant le bit de poids fort et le bit de poids faible en fonction d’une trame sans CRC en Byte().
  • AddCRC16 : corrige la trame envoyé sans CRC en Byte() en rajoutant le CRC à la fin.

Quand on souhaite envoyer une trame, on a souvent besoin d’ajouter le CRC après calcul quand le trame est variable, d’où la modification de la fonction CRC16 (qui n’est pas de moi) en AddCRC16 (que j’ai adapté) qui permet de restituer une trame exploitable immédiatement.

Function CRC16(ByVal data() As Byte) As Array
        Dim CRC16Lo As Byte, CRC16Hi As Byte 'CRC register
        Dim CL As Byte, CH As Byte 'Polynomial codes & HA001
        Dim SaveHi As Byte, SaveLo As Byte
        Dim i As Integer
        Dim Flag As Integer
        Dim ReturnData(2) As Byte

        CRC16Lo = &HFF
        CRC16Hi = &HFF
        CL = &H1
        CH = &HA0

        For i = 0 To UBound(data)
            CRC16Lo = CRC16Lo Xor data(i) 'for each data and CRC register XOR

            For Flag = 0 To 7
                SaveHi = CRC16Hi
                SaveLo = CRC16Lo
                CRC16Hi = CRC16Hi  2 'peak shift to the right one
                CRC16Lo = CRC16Lo  2 'shift to the right a low

                If ((SaveHi And &H1) = &H1) Then 'If the high byte last one for a
                    CRC16Lo = CRC16Lo Or &H80 'then the low byte shifted to the right after the meeting in front of a
                End If 'Otherwise, auto-fill 0

                If ((SaveLo And &H1) = &H1) Then 'If the LSB is 1, then XOR with the polynomial codes
                    CRC16Hi = CRC16Hi Xor CH
                    CRC16Lo = CRC16Lo Xor CL
                End If
            Next Flag
        Next i

        ReturnData(0) = CRC16Hi 'CRC high
        ReturnData(1) = CRC16Lo 'CRC low
        Return ReturnData
    End Function

Fonction suivante…

Function AddCRC16(ByVal data() As Byte) As Byte()
        Dim CRC16Lo As Byte, CRC16Hi As Byte 'CRC register
        Dim CL As Byte, CH As Byte 'Polynomial codes & HA001
        Dim SaveHi As Byte, SaveLo As Byte
        Dim i As Integer
        Dim Flag As Integer
        'Dim ReturnData(2) As Byte

        CRC16Lo = &HFF
        CRC16Hi = &HFF
        CL = &H1
        CH = &HA0

        For i = 0 To UBound(data)
            CRC16Lo = CRC16Lo Xor data(i) 'for each data and CRC register XOR

            For Flag = 0 To 7
                SaveHi = CRC16Hi
                SaveLo = CRC16Lo
                CRC16Hi = CRC16Hi  2 'peak shift to the right one
                CRC16Lo = CRC16Lo  2 'shift to the right a low

                If ((SaveHi And &H1) = &H1) Then 'If the high byte last one for a
                    CRC16Lo = CRC16Lo Or &H80 'then the low byte shifted to the right after the meeting in front of a
                End If 'Otherwise, auto-fill 0

                If ((SaveLo And &H1) = &H1) Then 'If the LSB is 1, then XOR with the polynomial codes
                    CRC16Hi = CRC16Hi Xor CH
                    CRC16Lo = CRC16Lo Xor CL
                End If
            Next Flag
        Next i

        'Agrandissement du data pour mettre 2 paramètres supplémentaires
        ReDim Preserve data(UBound(data) + 2)

        'Stock le CRC
        data(UBound(data) - 1) = Convert.ToByte(CRC16Lo)
        data(UBound(data)) = Convert.ToByte(CRC16Hi)

        Return data
    End Function

Bien sur il faut quand même créer la trame pour lui ajouter le CRC. Dans le prochain chapitre, je donnerais deux fonctions pour créer des trames de lecture et d’écriture qui font justement appellent à la fonction AddCRC16.

Series Navigation<< Recevoir une trame en ModBusConstructeurs de trame ModBus >>

Laisser un commentaire