MODBUS / JBUS : Bien communiquer pour bien contrôler
PLAN du CHAPITRE
C'est quoi ce binz ??
Je suis informaticien et je pratique (le + possible) la communication avec des appareils divers et variés.(Centrales météo, Centrales de mesures, analyseurs, programmateurs de prom/eprom et automates...).
Cet aspect de l'informatique est passionnant mais dans certains domaines, on se sent étrangement seul face à l'autisme de l'appareil. J'ai ressenti dûrement ce problème avec le protocole MODBUS qui est très répandu dans le monde de la communication industrielle et notament sur les automates.
Il est maintenant rendu totalement transparent par des serveurs OPC du commerce qui sont vendus dans les 10KF et qui en rajoutent une couche par dessus les nombreuses couches du système d'exploitation.
Mais quand on ne veut pas débourser 10KF, qu'on veut faire simple et qu'on veut comprendre le mécanisme, la solution est ailleurs. Encore faut-il la trouver.
C'est pourquoi, j'ai voulu faire moi-même une page détaillée qui explique de long en large la pratique de ce protocole qui est simple comme l'étaient les Hiéroglyphes de la pierre de Rosette.
Bien expliqué, c'est mieux.
Tu trouveras sur cette page tous les renseignements nécessaires à l'utilisation de ce protocole.
Pour résumer brièvement ce qu'est MODBUS, on peut dire qu'il émane de la société GOULD MODICON, que c'est un protocole de communication basé sur un principe Maître/esclave. Un seul maître et plusieurs esclaves. 255 esclaves maxi sur RS485 et 2 maxi sur RS232. Ce standard a été implémenté sur de nombreux appareils, car il est indépendant du matériel et s'adapte parfaitement aux architectures ouvertes. On retrouve aussi ce protocole sous le nom JBUS.
MODBUS peut converser en ASCII 7 bits ou en binaire RTU 8bits
L'avantage du mode RTU est que les données à transmettre prennent moins de place donc moins de temps. En effet, on adresse plus de données en 8 qu'en 7 bits.
On développera uniquement le mode RTU.
MODBUS/RTU est un protocole sécurisé basé sur le calcul d'un CRC (cyclical Redundancy check) ou test de redondance cyclique. Ce CRC calculé sur 16 bits est partie intégrante du message et il est vérifié par le destinataire. Il est calculé sur tous les octets de la trame à part lui-même bien-entendu.
Cet entier de type WORD (2 octets) sera calculé dans la gamme 0 à 65535 mais sera ramené dans la gamme -32768 à 32767.
Le maître (PC) envoie des requêtes à l'esclave qui lui répondra si le message lui convient.
Pour que le message convienne il doit être rédigé selon des règles édictées plus bas.
En premier lieu, s'assurer que les 2 appareils sont configurés de la même façon : exemple :
Vérification des paramètres sur la carte de communication de l'esclave.
Le schéma de câblage est classique et sera imposé par l'esclave. Le PC quant à lui gèrera principaleùment les lignes RD (2) et TD (3), le contraire des interfaces à 25 broches
Il existe diverses fonctions MODBUS mais on ne s'intéressera qu'aux fonctions de lecture (03H) et écriture (06H)
La trame MODBUS est constituée d'une suite de caractères hexadécimaux. et contient les informations suivantes :
La nature des informations de la trame peut varier selon que l'on fera de la lecture, de l'écriture, de mots, de bits ....
On ne développera que les fonctions de lecture/écriture de mots. consécutifs. ON considèrera que l'on s'adresse uniquement à l'automate 1
La trame MODBUS est définie de la façon suivante :
PF/pf signifie 2 octets l'octet de poids Fort mis avant l'octet de poids faible
2.1 / Trame de lecture (ex : on veut connaître la valeur du mot 800)
Esclave | Fonction | Adresse du 1er mot | Nombre de mots | CRC16 |
01H | 03H | *PF/pf | 01H (PF/pf) | **PF/pf |
Trame de réponse de l'esclave :
Esclave | Fonction | Nombre octets | Valeur 1er mot | ............ | Valeur dernier mot | CRC16 |
01H | 03H | 1 octet | PF/pf | PF/pf | **PF/pf |
2.2 Trame d'écriture d'un mot (ex : on veut fixer la valeur 0 au mot dont l'adresse est 800)
Esclave | Fonction | Adresse du mot | Valeur du mot | CRC16 |
01H | 06H | *PF/pf | 00H (PF/pf) | **PF/pf |
Trame de réponse de l'esclave :
Esclave | Fonction | Adresse du mot | Valeur du mot | CRC16 |
01H | 06H | PF/pf | PF/pf | **PF/pf |
(*) Dans cet exemple, 800 décimal doit être converti en HEXA sur 2 octets Poids Fort puis poids faible. Il faut savoir qu'un PC parle intuitivement en HEXA. C'est à dire que si on prend le décimal 65 qui a pour équivalent caractère 'A', quand on va passer chr(65) sur la ligne, on transmettra 'A' qui est en fait 41H ,Eh oui !. De la même manière, quand on passera le décimal 0 qui a pour équivalent caractère NUL, on transmettra NUL qui est en fait 00H.
(**) Le CRC calculé subit le même type de conversion. Son calcul est développé ultérieurement.
2.3 / Exemple de lecture d'un mot sur l'esclave 1
La trame qui sera envoyée est la suivante :
01 03 0320 0001 8584 (voir trame de lecture précédemment, se munir d'une table de conversion ASCII/DEC/HEX)
Mais comme 01 fait 2 caractères on enverra chr(01) qui est le caractère SOH donc l'HEXA 01H et ainsi de suite...
Par conséquent, la trame définitive qui sera transmise est la suivante :
chr(01)+chr(03)+chr(03)+chr(20)+chr(00)+chr(01)+chr(85)+chr(84)
2.4 / Exemple de codage en Visual Basic au travers de l'ActiveX MSComm (composant comm série)
requete = chr(01)+chr(03)+chr(03)+chr(20)+chr(00)+chr(01)+chr(85)+chr(84)
mscomm1.Output = requete
2.5 / Exemple de codage en DELPHI au travers d'un ActiveX Comport Library (dispo gratuit sur internet)
requete := chr(01)+chr(03)+chr(03)+chr(20)+chr(00)+chr(01)+chr(85)+chr(84);
comport1.Writestr(requete);
2.6 / Exemple de codage avec les fonctions de l'API Windows
Parce-que l'entité de base sur un système d'exploitation est le fichier, le port série COM1 est aussi un fichier qu'il faut ouvrir pour écrire ou lire. Pour ce faire, on utilisera la fonction CreateFile de l'API
hCom: = CreateFile("COM1",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0, NULL );
Bien-sûr, on n'est pas dans le cadre de l'ActiveX et on devra remplir la structure de configuration COMMCONFIG et mettre à jour avec les fonctions SetCommConfig/GetCommConfig mais c'est bien documenté dans Win32.hlp
Ainsi ouvert, le fichier peut être lu, écrit. Et il sera refermé après usage (à cause des courants d'air)
Et maintenant qu'on a un fichier, on utilise tout simplement les fonctions de lecture (ReadFile) et d'écriture (WriteFile) de l'API.
attention aux déclarations soit en include(C) en uses(DELPHI) ou en declare(VB) selon le langage de programmation. Les déclarations de fonctions de l'API sont obligatoires en VB Il y a d'ailleurs un utilitaire livré avec VB qui fabrique automatiquement la syntaxe de déclaration des fonctions de l'API.
Le CRC est une technique utilisée pour assurer une fiabilité proche de 100%. Il est donc superflu d'utiliser les contrôles de flux et de parité.CRC signifie (cyclical Redundancy check) ou test de redondance cyclique. Ce CRC calculé sur 16 bits est partie intégrante du message et il est vérifié par le destinataire. Il est calculé sur tous les octets de la trame à part lui-même bien-entendu.
C'est à ce moment qu'il faut raisonner en HEXA et uniquement en HEXA. Car le CRC sera codé sur 2 octets et aboutira à 4 quartets. Chaque quartet vaudra entre 0 et F. Si le CRC calculé aboutit à -31356, sa séparation en 2 octets donne 85 PF et 84 pf. par conséquent : les quartets 8,5,8 et 4 autrement dit 08H 05H 08H et 04H. Laissons tomber cette considération pour le moment : Elle sera fort utile plus tard.
L'algorithme de calcul est le suivant :
3.2 / Exemple de calcul développé en binaire :
On pose au préalable :
Poly (polynôme arbitraire) = A001 HEXA
On envoie
la chaîne 02 07 c'est à dire chr(02)+chr(07)
Cela constitue le début d'une trame ou l'on demanderait la fonction 07 à l'esclave 02
Développement CRC FLAG (retenue) Init CRC 1111 1111 1111 1111 1er octet XOR 0000 0010 Résultat 1111 1111 1111 1101 Décalage 1 0111 1111 1111 1110 1 Flag=1, poly XOR 1010 0000 0000 0001 Résultat 1101 1111 1111 1111 Décalage 2 0110 1111 1111 1111 1 Flag=1, poly XOR 1010 0000 0000 0001 Résultat 1100 1111 1111 1110 Décalage 3 0110 0111 1111 1111 0 Décalage 4 0011 0011 1111 1111 1 Flag=1, poly XOR 1010 0000 0000 0001 Résultat 1001 0011 1111 1110 Décalage 5 0100 1001 1111 1111 0 Décalage 6 0010 0100 1111 1111 1 Flag=1, poly XOR 1010 0000 0000 0001 Résultat 1000 0100 1111 1110 Décalage 7 0100 0010 0111 1111 0 Décalage 8 0010 0001 0011 1111 1 Flag=1, poly XOR 1010 0000 0000 0001 Résultat 1000 0001 0011 1110 2nd octet XOR 0000 0111 Résultat 1000 0001 0011 1001 Décalage 1 0100 0000 1001 1100 1 Flag=1, poly XOR 1010 0000 0000 0001 Résultat 1110 0000 1010 1101 Décalage 2 0111 0000 0100 1110 1 Flag=1, poly XOR 1010 0000 0000 0001 résultat 1101 0000 0100 1111 Décalage 3 0110 1000 0010 0111 1 Flag=1, poly XOR 1010 0000 0000 0001 Résultat 1100 1000 0010 0110 Décalage 4 0110 0100 0001 0011 0 Décalage 5 0011 0010 0000 1001 1 Flag=1, poly XOR 1010 0000 0000 0001 Résultat 1001 0010 0000 1000 Décalage 6 0100 1001 0000 0100 0 Décalage 7 0010 0100 1000 0010 0 Décalage 8 0001 0010 0100 0001 0 quartets 1 2 4 1
Le résultat de ce calcul aboutit à CRC16 = 0001 0010 0100 0001 soit 1241. Eh non ! parce-que le CRC sera swappé pf puis PF. Par conséquent sa valeur est de 4112 qu'on transmettra PF/pf. C'est comme çà !
3.3 / Exemple concret en DELPHI
Voici l'extrait de fiche (form1) intéressant le code qui va suivre :
Et voici le CODE DELPHI que je vais commenter
et voici la routine poids
Attention à la vitesse de l'ordinateur. Si des rafales de requêtes arrivent trop vite, l'esclave n'a pas le temps de répondre. Il faut alors temporiser les requêtes.