Modbus TCP

Des registres et des bobines Modbus sur TCP/IP, avec un adressage typé, la maîtrise de l'ordre des octets et un balayage réseau borné.

Afficher en Markdown

Le pilote Modbus TCP lit et écrit des registres et des bobines Modbus sur TCP/IP : automates, compteurs, passerelles et tout serveur qui parle Modbus/TCP. L'adressage est entièrement typé : vous choisissez une classe de registre et un numéro de registre à partir de 0, et l'application assemble la requête ; il n'y a aucune adresse en texte libre à rater.

Équipement

Champ Sens Défaut
Hôte Le nom DNS, l'adresse IPv4 ou IPv6 du serveur ou de la passerelle Modbus. vide : l'équipement n'est pas connecté tant qu'aucun n'est saisi
Port Le port TCP, de 1 à 65535. Un champ vide affiche 502 en gris et l'équipement est appelé sur ce port ; un équipement enregistré avec 0 se lit de la même façon. 502
ID d'unité L'ID d'unité (esclave) Modbus porté par chaque requête : ce qu'une passerelle emploie pour router vers l'équipement derrière elle. De 0 à 255. 1
Format de trame Comment chaque requête circule sur la connexion : MBAP, l'en-tête Modbus TCP devant chaque requête, ou RTU, la trame RTU avec son CRC envoyée telle quelle, pour un convertisseur série-Ethernet en mode transparent (voir RTU sur TCP). L'hôte, le port, l'ID d'unité et les tags sont les mêmes dans les deux cas. MBAP
Intervalle minimal entre transactions (ms) Un cadencement de compatibilité : le silence minimal après la fin d'une transaction avant que la suivante ne commence, de 0 à 1000. Zéro n'ajoute aucun délai artificiel. 0
Intervalle de scrutation (ms) La cadence de scrutation par défaut des tags qui ne la remplacent pas. 1000

L'URI de base affichée dans l'en-tête du volet est modbus+tcp://host:port/unitID, plus ?minimumTransactionIntervalMs=n quand l'intervalle est réglé.

Les équipements qui partagent un hôte et un port partagent aussi une seule barrière de transaction : les requêtes vers le même endpoint ne se chevauchent jamais, et le plus grand intervalle minimal configuré parmi les équipements activés de cet endpoint les cadence tous. Le volet le dit quand un autre équipement élève l'intervalle effectif au-dessus de celui configuré ici. L'intervalle ne gouverne que le trafic que cette application émet : c'est une aide à la compatibilité pour un serveur ou une passerelle lents, pas une réparation des défauts de réseau.

La connexion attend 5 secondes au plus ; une réponse est attendue 10 secondes au plus ; il n'y a aucune reprise au niveau du protocole. La boucle de reprise en arrière-plan possède la reconnexion, si bien qu'un équipement éteint ne coûte rien de plus qu'une lecture de mauvaise qualité.

RTU sur TCP

Un convertisseur série-Ethernet en mode transparent ne parle pas Modbus TCP de lui-même : ce qui arrive sur son socket repart tel quel sur son bus série, et ce que le bus répond revient. Un équipement derrière lui est un équipement Modbus TCP dont le Format de trame est RTU : la station envoie la trame RTU (l'ID d'unité, la requête et son CRC) sans en-tête MBAP, et ne croit une réponse que si son CRC est juste. Le Base URI porte alors framing=rtu dans sa requête, par exemple modbus+tcp://192.168.0.20:502/1?framing=rtu ; un équipement en MBAP garde l'adresse qu'il a toujours eue. Tout le reste de cette page vaut sans changement : les classes de registre, les codes de fonction, la file des écritures, les délais et l'intervalle entre transactions.

  • L'ID d'unité est l'adresse de l'équipement sur le bus série derrière le convertisseur, de 1 à 247.
  • Les équipements derrière un convertisseur partagent son hôte et son port, et avec eux sa barrière de transactions : une requête à la fois, ce qui est aussi tout ce que porte un bus série. Si le convertisseur a besoin d'une pause entre les trames, augmentez l'Intervalle minimal entre transactions (ms).
  • Les réglages série du convertisseur lui-même (débit en bauds, format) se font sur le convertisseur ; la station ne les voit jamais.
  • Une trame RTU ne porte pas de numéro de transaction : avant chaque requête, la station écarte donc tout ce que le convertisseur a déjà envoyé, et une réponse arrivée après l'expiration de sa requête n'est jamais prise pour celle de la suivante.

Adressage des tags

Champ Sens Défaut
Classe de registre Quelle entité Modbus le tag adresse : Bobine (0xxxx), Entrée discrète (1xxxx), Registre d'entrée (3xxxx) ou Registre de maintien (4xxxx). Chacune porte le premier chiffre que l'adresse du manuel a pour elle, si bien qu'un manuel qui n'imprime que 30001 désigne les registres d'entrée. Déduite du type et de l'accès : les tags booléens reçoivent une entrée discrète (lecture seule) ou une bobine (inscriptible) ; tous les autres types reçoivent un registre d'entrée (lecture seule) ou un registre de maintien (inscriptible).
Numéro de registre (base 0) L'adresse brute du protocole. C'est l'adresse à partir de 0 sur le bus, pas la notation du manuel : le registre de maintien 40001 est le numéro de registre 0. Saisir 30001 ici ne choisit pas la classe, car certains équipements ont réellement des registres au-delà de 30000 : la classe se choisit au-dessus. Le registre voyage sur le bus en nombre de 16 bits, si bien que le champ prend de 0 à 65535 et refuse tout ce qui est plus large là où il est saisi. 0
Quantité (registres, vide = automatique) Combien de registres de 16 bits la valeur occupe. La zone n'est dessinée que sur les tags String : tous les autres types ont une largeur fixe, il n'y a donc rien à remplacer. Par type : Boolean, Int16 et UInt16 1, Int32 et Float 2, String 4
Octet de poids fort en premier (MSB first, gros-boutiste) Quel octet de chaque registre de 16 bits passe en premier sur le bus ; les mots entre parenthèses sont ceux que les manuels impriment. Tags numériques, et un booléen tenu dans un registre de maintien ou d'entrée ; un booléen dans une bobine ou une entrée discrète est un seul bit, sans octet à ordonner, si bien que la case n'y est pas dessinée. coché (ce que demande la spécification Modbus)
Mot de poids fort en premier (mot haut en premier) Quel registre d'une valeur sur deux registres porte la moitié haute. Tags Int32 et Float seulement : une valeur sur un seul registre (Boolean, Int16, UInt16) n'a pas de second registre, la case n'y est donc pas dessinée. Sous les deux cases, Ordre des octets de la valeur nomme la disposition qu'elles forment avec les lettres d'un manuel (Ordre des octets et des mots). coché

La carte Source de la valeur se termine par Adresse dans le manuel, l'endroit où se trouve le tag dans la notation que le manuel de l'équipement imprime : le premier chiffre de la classe puis le registre compté à partir de 1. Le registre d'entrée 0 se lit 30001, un Float au registre de maintien 100 se lit de 40101 à 40102, et un registre au-delà de 9998 passe à six chiffres (le registre de maintien 9999 se lit 410000), si bien que le volet se lit ligne à ligne contre le manuel.

Types de valeur et quantités

Six types de valeur sont proposés, et la largeur de protocole de chacun est fixée :

Type de donnée Registres Forme sur le bus
Boolean 1 Sur une classe de registre : tout registre non nul se lit vrai, et une écriture envoie 1 ou 0. Sur Coil/DiscreteInput : le bit lui-même.
Int16 1 Un entier signé de 16 bits dans un seul registre, de -32768 à 32767.
UInt16 1 Un entier non signé de 16 bits dans un seul registre, de 0 à 65535. Le même registre se lit 65535 en UInt16 et -1 en Int16 : le signe vient du type de donnée choisi, pas du registre.
Int32 2 Un entier signé de 32 bits sur une paire de registres.
Float 2 Une simple précision IEEE 754 sur une paire de registres.
String 1 ou plus (4 par défaut) Des octets UTF-8 empaquetés deux par registre. Une lecture s'arrête au premier octet NUL ; une écriture doit tenir dans la quantité déclarée (2 octets par registre) et est complétée par des zéros.

Un tag String est lu et écrit dans l'ordre où l'équipement porte les octets, et une écriture envoie toujours de l'UTF-8. Des octets qui ne sont pas de l'UTF-8 valide, ce à quoi ressemblent une plage que l'équipement n'a jamais initialisée ou du texte écrit dans un autre encodage, se lisent en caractère de remplacement Unicode plutôt que d'échouer : le tag montre quelque chose de visiblement faux, et tous les autres tags de cet équipement continuent de se lire.

La Quantité (registres, vide = automatique) n'est demandée que sur les tags String. Les largeurs Boolean, Int16, UInt16, Int32 et Float sont fixes, si bien que la zone n'est dessinée sur aucun de ces points, ni dans le volet du tag ni dans la grille des tags ; le remplacement existe pour dimensionner les tags String.

Ordre des octets et des mots

La case de l'ordre des octets est dessinée sur les tags numériques et sur un booléen tenu dans un registre, celle de l'ordre des mots sur ceux à deux registres seulement (Int32, Float). Ce sont deux questions indépendantes : quel octet mène à l'intérieur de chaque registre, et quel registre mène sur une paire. Modbus n'en définit aucun pour le texte, si bien qu'un tag String ne se les voit pas proposer : ses octets voyagent dans l'ordre où l'équipement les porte. Pour la valeur 0x01020304, avec A pour l'octet de poids fort, les quatre dispositions sont :

Octet de poids fort en premier Mot de poids fort en premier Octets sur le bus
coché coché AB CD (le défaut de la spécification)
coché décoché CD AB (l'échange de mots classique)
décoché coché BA DC
décoché décoché DC BA

Les lectures et les écritures appliquent les deux mêmes réponses dans le même ordre, si bien qu'une écriture pose exactement les octets qu'une lecture aurait repris. Ordre des octets de la valeur, sous les cases, dit la disposition en un mot (ABCD, CDAB, BADC ou DCBA), comme un manuel la nomme.

Une valeur Int16 ou UInt16 tient dans un seul registre, si bien que seul l'ordre des octets s'y applique : pour 0x1234, l'octet de poids fort en premier envoie 12 34 et la case décochée envoie 34 12. Il n'y a pas de second registre à placer : la case de l'ordre des mots n'y est donc pas dessinée.

Codes de fonction

Classe de registre Lecture Écriture
Registre de maintien (4xxxx) 3 (Read Holding Registers) 6 (registre unique) ou 16 (registres multiples)
Registre d'entrée (3xxxx) 4 (Read Input Registers) lecture seule ; une écriture est refusée
Bobine (0xxxx) 1 (Read Coils) 5 (Force Single Coil, une seule bobine)
Entrée discrète (1xxxx) 2 (Read Discrete Inputs) lecture seule ; une écriture est refusée

Une écriture ne rapporte un succès que lorsque la réponse de protocole du serveur confirme l'acceptation ; la valeur en cache n'avance qu'à ce moment-là.

Découverte

Le balayage est explicite et borné : l'application ne déduit ni ne parcourt jamais votre sous-réseau local. Le formulaire de portée prend :

Champ Sens Défaut
Hôte IPv4 ou CIDR Une adresse (192.168.1.10) ou un sous-réseau pas plus large que /24 (192.168.1.0/24). Les adresses de réseau et de diffusion sont sautées. obligatoire
Port Le port à sonder. 502
ID d'unité Des valeurs, des listes séparées par des virgules ou des plages croissantes : 1, 1,5,9, 1, 3, 8-16 (de 0 à 255). 1
Format de trame La trame dans laquelle chaque sondage est envoyé. Un convertisseur en mode transparent ne répond qu'aux trames RTU : balayez-le en RTU. MBAP
Intervalle minimal entre transactions (ms) Le cadencement entre deux sondages terminés sur le même hôte, de 0 à 1000. 0

La découverte envoie chaque sondage dans le Format de trame choisi. En RTU, chaque sondage est la trame RTU nue, et une réponse ne compte que si son ID d'unité correspond et que son CRC est juste ; les unités derrière un convertisseur en mode transparent sont ainsi trouvées comme les autres. Une unité trouvée garde le format de trame du balayage quand elle est ajoutée.

Un seul balayage envoie 256 sondages au plus (hôtes × ID d'unité) ; un plan plus grand est refusé avant l'ouverture de la moindre prise. La seule requête envoyée est Read Basic Device Identification (fonction 43/14) : la découverte ne lit jamais de registres et ne devine jamais de plan de registres. Une réponse d'exception Modbus entièrement valide prouve qu'une unité est présente sans prétendre à son identité ; la joignabilité TCP, les délais dépassés et les trames malformées, non. Quatre hôtes au plus sont balayés en parallèle, séquentiellement à l'intérieur de chaque hôte, avec des délais de connexion et de sondage de 750 ms.

Les résultats portent l'endpoint complet et un nom proposé, construit depuis le fabricant et le code produit quand l'équipement les rapporte. Les candidats ont zéro tag : les registres se configurent après Ajouter. Une unité déjà configurée est marquée comme telle et propose Ouvrir au lieu de créer un doublon.

Des limites à connaître

  • Les autres largeurs d'entier (SByte, Byte, UInt32, Int64, UInt64) et Double ne sont pas proposés : le codec de bus fait l'aller-retour exact sur les six types ci-dessus.
  • Une seule requête est en cours par endpoint à la fois ; les nombreux équipements derrière une passerelle partagent cette sérialisation par construction.
  • Les écritures adressent une bobine ou une suite de registres à la fois ; il n'y a pas d'écriture multibobine.