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

Python Discussion :

Calcul CRC 16


Sujet :

Python

  1. #1
    Membre confirmé
    Femme Profil pro
    Etudiante
    Inscrit en
    Mai 2016
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : Mai 2016
    Messages : 87
    Par défaut Calcul CRC 16
    Bonjour,

    Je souhaite communiquer avec un régulateur de température (eurotherm S2000) via une RS232. Le protocole de communication utilisé est un protocole Modbus. Le message transmit se compose d'un certain nombre de caractères pour que mon ordinateur puisse comprendre. Ainsi, la syntaxe de la trame d'un message est début de la trame (3 octets), adresse du pérephirique (1 octets), code fonction (1 octets), données (n octets), CRC (2 octets) , EOT (3 octets).

    Donc cette communication repose sur le calcul du contrôle de redondance cyclique (CRC 16bits), un calcul permettant la détection d'erreur.


    Mon probléme est que je ne sais pas comment mettre en place cette communication via python. Donc si vous pouviez m'éclairer sur mon probléme, cela me serait d'une grande aide.


    Voici la doc de l'instrument que j'utilise: http://www.eurotherm.tm.fr/index.php...wnload_id=1915

    En vous remerciant par avance.

    Cordialement.

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 676
    Par défaut
    Salut,

    Citation Envoyé par Cerise22 Voir le message
    Mon probléme est que je ne sais pas comment mettre en place cette communication via python. Donc si vous pouviez m'éclairer sur mon probléme, cela me serait d'une grande aide.
    Il suffit de coder
    S'il faut tout coder, c'est un travail conséquent qu'il faut structurer, réaliser, tester,...

    Une autre solution est de rechercher sur le ouèbe si une implémentation utilisable par Python de ce type de protocole n'est pas utilisable tout ou partie.
    Il faut lire la documentation et le code pour voir si çà le fait... tester avec votre engin pour voir si çà fonctionne adapter ou écrire des bouts.

    Dans tous les cas, c'est un boulot de plusieurs jours (voire semaines) pour un programmeur expérimenté (même pour récupérer une bibliothèque prête à l'emploi, il faut de l'expérience pour savoir si elle a des chances de fonctionner, la tester, l'adapter).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2013
    Messages
    156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2013
    Messages : 156
    Par défaut
    Bonjour,

    Pour la partie communication, vous pouvez déjà pour renseigner sur les modules, pyserial, ftd2xx ou pylibftdi (choisissez en une ou plusieurs suivant vos besoin).
    Ensuite, pour les calculs de CRC, il y à plein d'implémentation sur le net, personnellement j'en utilise une que j'ai trouver il y a un petit moment sur le web, mais pycrc devrai faire ton bonheur.
    Il propose entre autre :
    crc-16-modbus
    Width 16
    Poly 0x8005
    Reflect In True
    XOR In 0xffff
    Reflect Out True
    XOR Out 0x0000
    Short command pycrc.py --model crc-16-modbus
    Extended command pycrc.py --width 16 --poly 0x8005 --reflect-in True --xor-in 0xffff --reflect-out True --xor-out 0x0000
    Check 0x4b37

  4. #4
    Membre confirmé
    Femme Profil pro
    Etudiante
    Inscrit en
    Mai 2016
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : Mai 2016
    Messages : 87
    Par défaut
    Bonjour,

    Pour la communication avec le régulateur de température, je vais utiliser le module pyserial pour la communication avec la liaison RS232.
    Pour le calcul du CRC 16 , le code de redondance cyclique, j'utilise le module PyCRC.

    Le protocole pour lire une température via le régulateur est d'envoyer ces paramétres via le port série: "1 3 0 28 0 1" ensuite on calcul le CRC de ces données. Dans la documentation, on m'indique que l'on doit ajouter à la chaine précedente le CRC lo byte et le CRC HIGH byte.

    Mais concretement à quoi correspond le CRC lo byte et le CRC High byte?


    En vous remerciant.

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 676
    Par défaut
    Citation Envoyé par Cerise22 Voir le message
    Mais concretement à quoi correspond le CRC lo byte et le CRC High byte?
    Votre documentation donne un exemple en C:

    Code C : 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
    uint16 calculate_crc(octet *z_p, uint16 z_message_length)
    /* CRC fait tourner l'algorithme de contrôle de redondance cyclique sur l'entrée z_p
    */
    /* Renvoie une valeur de 16 bits CRC après achèvement et ajoute */
    /* toujours 2 octets CRC au message */
    /* renvoie 0 si le CRC du message qui arrive est correct */
    {
        uint16 CRC= 0xffff;
        uint16 next;
        uint16 report;
        uint16 n;
        uint8 crch, crcl;
        while (z_message_length--) {
            next = (uint16)*z_p;
            CRC ^= next;
            for (n = 0; n < 8; n++) {
                report = CRC & 1;
                CRC >>= 1;
                if (report) {
                    CRC ^= 0xA001;
                }
            }
            z_p++;
        }
        crch = CRC / 256;
        crcl = CRC % 256
        z_p[z_message_length++] = crcl;
        z_p[z_message_length] = crch;
        return CRC;
    }

    Une autre façon de voir est qu'un CRC16 se calcule sur 2 octets/bytes et comme vous transférez des bytes sur le port série, il faut savoir dans quel ordre transférer ces 2 bytes... et là on vous dit: "low-byte first".
    note: même si vous ne connaissez pas C, ces constructions sont suffisamment proches de Python pour être à priori "lisibles".

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre confirmé
    Femme Profil pro
    Etudiante
    Inscrit en
    Mai 2016
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : Mai 2016
    Messages : 87
    Par défaut
    Merci pour votre retour.

    Comme dit précedemment, j'utilise le module PyCRC:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    from PyCRC.CRC16 import CRC16
     
    input = '1302801'
    print(CRC16().calculate(input))
     # Cela m'affiche comme valeur 42303
    Donc en ayant cette valeur comment je peux différencier le bit de poids faible et le bit de poids fort?

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 676
    Par défaut
    Citation Envoyé par Cerise22 Voir le message
    Donc en ayant cette valeur comment je peux différencier le bit de poids faible et le bit de poids fort?
    Vous lisez le code C et vous le traduisez en Python:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> CRC = 42303
    >>> crch = CRC // 256;
    >>> crcl = CRC % 256
    >>> crcl, crch
    (63, 165)
    >>>
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  8. #8
    Membre confirmé
    Femme Profil pro
    Etudiante
    Inscrit en
    Mai 2016
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : Mai 2016
    Messages : 87
    Par défaut
    Merci pour votre aide

  9. #9
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 676
    Par défaut
    Citation Envoyé par Cerise22 Voir le message
    Merci pour votre aide
    Vous avez vu que pyCRC propose plusieurs CRC-16. Ca serait bien de vérifier que vous calculez bien le même CRC que le code en C, sinon çà ne marchera pas.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  10. #10
    Membre confirmé
    Femme Profil pro
    Etudiante
    Inscrit en
    Mai 2016
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : Mai 2016
    Messages : 87
    Par défaut
    Merci pour votre remarque.

    En effet, il existe 4 type de calcul de CRC16. J'ai utilisé le CRC 16 simple, d'ailleurs dans l'écrito il est indiqué "# CRC16 MODULE
    ## includes CRC16 and CRC16 MODBUS" , cela signifie donc que c'est bien le calcul du crc16 pour le protocole Modbus.

    Voici son code:
    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
     
    from ctypes import c_ushort
     
     
    class CRC16(object):
        crc16_tab = []
     
        # The CRC's are computed using polynomials. Here is the most used
        # coefficient for CRC16
        crc16_constant = 0xA001  # 40961
     
        def __init__(self, modbus_flag=False):
            # initialize the precalculated tables
            if not len(self.crc16_tab):
                self.init_crc16()
            self.mdflag = bool(modbus_flag)
     
        def calculate(self, input_data=None):
            try:
                is_string = isinstance(input_data, str)
                is_bytes = isinstance(input_data, bytes)
     
                if not is_string and not is_bytes:
                    raise Exception("Please provide a string or a byte sequence "
                                    "as argument for calculation.")
     
                crcValue = 0x0000 if not self.mdflag else 0xffff
     
                for c in input_data:
                    d = ord(c) if is_string else c
                    tmp = crcValue ^ d
                    rotated = c_ushort(crcValue >> 8).value
                    crcValue = rotated ^ int(self.crc16_tab[(tmp & 0x00ff)], 0)
     
                return crcValue
            except Exception as e:
                print("EXCEPTION(calculate): {}".format(e))
     
        def init_crc16(self):
            '''The algorithm uses tables with precalculated values'''
            for i in range(0, 256):
                crc = c_ushort(i).value
                for j in range(0, 8):
                    if (crc & 0x0001):
                        crc = c_ushort(crc >> 1).value ^ self.crc16_constant
                    else:
                        crc = c_ushort(crc >> 1).value
                self.crc16_tab.append(hex(crc))
    Finalement dans mon projet, j'utilise le régualteur de température cal9500P, il fonctionne sur le même principe que l'eurotherm.

    J'ai une question, concernant l'envoi du protocole d'écriture sur le port série.

    Dans mon programme je fais:
    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
     
    se = serial.Serial(
     
        port='/dev/ttyUSB0', 
        baudrate = 9600,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS,
        timeout=1,
        xonxoff=1,
        rtscts=0,
        dsrdtr=0
    )
     
     
    se.write("1302801 "+ crcl +crch .encode("UTF-8"))
    i=True
    x=""
    while i:
            if(se.inWaiting()>0):
                x=se.readline()
                se.readline()
                i=False
                print (x)
                se.close()

    Pour lire une température via le port série, je dois envoyer comme commande: 1 3 0 28 0 1 et le crc low puis le crc high.

    Est ce que la maniére dont j'ai écrit cela dans mon programme est correct?

    En vous remerciant.

  11. #11
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 676
    Par défaut
    Citation Envoyé par Cerise22 Voir le message
    Est ce que la manière dont j'ai écrit cela dans mon programme est correct?
    C'est correct si l'automate comprend ce que vous lui avez envoyé. Mais quand je lis une chose comme se.write("1302801 "+ crcl +crch .encode("UTF-8")), je ne pense pas que ce soit correct. Essentiellement parce que .encode("UTF-8") montre que vous pensez "chaîne de caractères". Lorsqu'on fait de la communication à bas niveau, on pense octets/bytes et on écrit de l'hexadécimal: "1" n'est pas b'\x01'...

    Pour le CRC(*), c'est pareil, si vous ne testez pas, vous prenez le risque de vous poser des tas de questions si çà ne fonctionne pas: votre trame étant construite avec des bouts de code non testés, comment vous allez faire pour déterminer la cause d'un problème? D'autant que pas grand monde pourra vous aider.
    (*)écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    from PyCRC.CRC16 import CRC16
     
    input = '1302801'
    print(CRC16().calculate(input))
    est déjà faux car, par défaut, "modbus_flag=False"...
    Après il faut lire le code pour savoir si c'est a peu près pareil, et dans tous les cas, "tester" pour s'assurer que le code fait bien ce qu'on en attend.


    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  12. #12
    Membre confirmé
    Femme Profil pro
    Etudiante
    Inscrit en
    Mai 2016
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Etudiante

    Informations forums :
    Inscription : Mai 2016
    Messages : 87
    Par défaut
    Donc si je comprends, vous me conseillez d'écrire la commande en hexadecimale?


    Pour le CRC(*), c'est pareil, si vous ne testez pas
    Comment pourrais je le tester autrement qu'en "situation réelle"?


    En vous remerciant.

  13. #13
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 676
    Par défaut
    Citation Envoyé par Cerise22 Voir le message
    Donc si je comprends, vous me conseillez d'écrire la commande en hexadecimale?
    Vous demandez "Est ce que la manière dont j'ai écrit cela dans mon programme est correct?", je dis "probablement pas, car..." mais j'aurais pu simplement vous faire remarquer qu'écrire "1302801 "+ crcl +crch .encode("UTF-8"), avec crcl, crch entiers ou pas, est déjà incorrect côté Python.

    Citation Envoyé par Cerise22 Voir le message
    Comment pourrais je le tester autrement qu'en "situation réelle"?
    Vous pourriez déjà écrire un programme en C qui reprenne le calcul de checksum donné dans la documentation et comparer les résultats d'un jeu de test.

    note: comme je l'ai déjà écrit dans une réponse précédente, vous avez des code python qui réalisent déjà des protocoles modbus. Si vous n'avez pas de bonnes raisons pour ne pas les utiliser, c'est que vous avez pris le temps de lire ces codes et de les tester... et vous savez aussi que vous avez des "timers" à respecter qui font qu'écrire serial.write... et espérer que çà fonctionne, c'est ballot.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. [WD12E] Calcul CRC-CCITT erroné
    Par bouillant dans le forum WinDev
    Réponses: 9
    Dernier message: 17/03/2022, 11h54
  2. Choix et calcul CRC, checksum,md5
    Par mercure07 dans le forum C++
    Réponses: 1
    Dernier message: 22/04/2008, 14h27
  3. Calcul CRC 16
    Par G_angel dans le forum C#
    Réponses: 1
    Dernier message: 16/04/2007, 09h46
  4. Calcul CRC d'une trame
    Par Dimitri_87 dans le forum Réseau
    Réponses: 6
    Dernier message: 10/02/2007, 17h56
  5. Calcul CRC ISO3309
    Par zodd dans le forum Algorithmes et structures de données
    Réponses: 1
    Dernier message: 29/05/2006, 13h35

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