Le code fonction est le premier octet de la PDU. Il indique au serveur quelle opération effectuer. La spécification en définit une vingtaine, mais six suffisent pour presque tout le travail de terrain.
Cette page est une référence. Le tableau complet d’abord, le détail des trames ensuite.
Tableau de référence
| Déc | Hex | Nom | Table visée | Quantité max | Série uniquement |
|---|---|---|---|---|---|
| 1 | 0x01 | Read Coils | Coils | 2000 bits | — |
| 2 | 0x02 | Read Discrete Inputs | Discrete inputs | 2000 bits | — |
| 3 | 0x03 | Read Holding Registers | Holding registers | 125 registres | — |
| 4 | 0x04 | Read Input Registers | Input registers | 125 registres | — |
| 5 | 0x05 | Write Single Coil | Coils | 1 bit | — |
| 6 | 0x06 | Write Single Register | Holding registers | 1 registre | — |
| 7 | 0x07 | Read Exception Status | — | — | Oui |
| 8 | 0x08 | Diagnostics | — | — | Oui |
| 11 | 0x0B | Get Comm Event Counter | — | — | Oui |
| 12 | 0x0C | Get Comm Event Log | — | — | Oui |
| 15 | 0x0F | Write Multiple Coils | Coils | 1968 bits | — |
| 16 | 0x10 | Write Multiple Registers | Holding registers | 123 registres | — |
| 17 | 0x11 | Report Server ID | — | — | Oui |
| 20 | 0x14 | Read File Record | Fichiers | — | — |
| 21 | 0x15 | Write File Record | Fichiers | — | — |
| 22 | 0x16 | Mask Write Register | Holding registers | 1 registre | — |
| 23 | 0x17 | Read/Write Multiple Registers | Holding registers | 125 lus / 121 écrits | — |
| 24 | 0x18 | Read FIFO Queue | Registres | 31 registres | — |
| 43 | 0x2B | Encapsulated Interface Transport | — | — | — |
Les plages 65 à 72 et 100 à 110 sont réservées aux codes fonction propriétaires. Un constructeur peut y placer ce qu’il veut. Aucune interopérabilité n’est garantie sur ces codes.
Sommaire
Les six codes que vous utiliserez vraiment
0x03 — Read Holding Registers
Le code le plus utilisé de tout le protocole. Lit une plage contiguë de registres 16 bits en lecture/écriture.
Requête — lire 2 registres à partir de l’adresse 0, esclave 1 : 01 03 00 00 00 02 C4 0B
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | Esclave interrogé |
| Code fonction | 03 | 3 | Read Holding Registers |
| Adresse de départ | 00 00 | 0 | Premier registre lu, plage 0 à 65535 |
| Quantité | 00 02 | 2 | Nombre de registres, 1 à 125 |
| CRC | C4 0B | — | Poids faible transmis en premier |
Réponse : 01 03 04 00 6E 00 05 5B ED
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | Esclave qui répond |
| Code fonction | 03 | 3 | Écho du code demandé |
| Nombre d’octets | 04 | 4 | 2 × quantité |
| Registre 0 | 00 6E | 110 | Première valeur |
| Registre 1 | 00 05 | 5 | Seconde valeur |
| CRC | 5B ED | — | — |
Le champ « nombre d’octets » vaut toujours le double de la quantité demandée. S’il ne correspond pas, l’équipement a un défaut d’implémentation.
0x04 — Read Input Registers
Structure de trame strictement identique à 0x03, seul le code fonction change. La différence est la table visée : registres en lecture seule.
Beaucoup d’équipements exposent les mêmes données sur 0x03 et 0x04. D’autres n’implémentent que 0x03. Si une lecture 0x04 renvoie l’exception 01, essayez 0x03 avec la même adresse.
0x01 — Read Coils
Lit des bits. La réponse les emballe huit par octet, bit de poids faible en premier.
Requête — lire 19 bits à partir de l’adresse 0 : 01 01 00 00 00 13 7D C7
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | — |
| Code fonction | 01 | 1 | Read Coils |
| Adresse de départ | 00 00 | 0 | Premier bit lu |
| Quantité | 00 13 | 19 | Nombre de bits, 1 à 2000 |
| CRC | 7D C7 | — | — |
Réponse : 01 01 03 CD 6B 05 42 82
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | — |
| Code fonction | 01 | 1 | — |
| Nombre d’octets | 03 | 3 | ⌈19 / 8⌉ arrondi au supérieur |
| Octet 1 | CD | — | Bits 0 à 7 |
| Octet 2 | 6B | — | Bits 8 à 15 |
| Octet 3 | 05 | — | Bits 16 à 18, plus 5 bits de bourrage à 0 |
| CRC | 42 82 | — | — |
L’octet CD vaut 1100 1101 en binaire. En lecture de poids faible vers poids fort, cela donne les bits 0 à 7 : 1, 0, 1, 1, 0, 0, 1, 1. L’ordre est contre-intuitif la première fois. Le bit 0 est celui le plus à droite.
Les bits de bourrage du dernier octet sont toujours à zéro. Ne les interprétez pas.
0x02 — Read Discrete Inputs
Identique à 0x01 dans la structure. Vise les discrete inputs en lecture seule.
0x06 — Write Single Register
Écrit une valeur dans un holding register. La réponse est un écho exact de la requête.
Requête et réponse sont identiques : 01 06 00 01 00 03 98 0B
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | — |
| Code fonction | 06 | 6 | Write Single Register |
| Adresse | 00 01 | 1 | Registre visé |
| Valeur | 00 03 | 3 | Valeur écrite |
| CRC | 98 0B | — | — |
L’écho est la confirmation. Si vous recevez un écho, l’écriture est acceptée — mais cela ne garantit pas que l’équipement a agi sur le procédé, seulement qu’il a accepté la valeur.
0x10 — Write Multiple Registers
Écrit une plage contiguë. Jusqu’à 123 registres.
Requête — écrire 10 puis 258 aux adresses 1 et 2 : 01 10 00 01 00 02 04 00 0A 01 02 92 30
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | — |
| Code fonction | 10 | 16 | Write Multiple Registers |
| Adresse de départ | 00 01 | 1 | Premier registre écrit |
| Quantité | 00 02 | 2 | Nombre de registres, 1 à 123 |
| Nombre d’octets | 04 | 4 | 2 × quantité |
| Registre 1 | 00 0A | 10 | Première valeur |
| Registre 2 | 01 02 | 258 | Seconde valeur |
| CRC | 92 30 | — | — |
Réponse — courte, elle ne renvoie pas les données : 01 10 00 01 00 02 10 08
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | — |
| Code fonction | 10 | 16 | — |
| Adresse de départ | 00 01 | 1 | Confirme la plage écrite |
| Quantité | 00 02 | 2 | Confirme le nombre écrit |
| CRC | 10 08 | — | — |
C’est le code à privilégier pour écrire une valeur 32 bits ou un flottant : les deux registres sont écrits dans la même transaction, l’équipement ne voit jamais un état intermédiaire incohérent. Deux écritures 0x06 successives, elles, laissent une fenêtre où la valeur lue est fausse.
Les codes utiles mais moins connus
0x05 — Write Single Coil
La valeur n’est pas 0 ou 1. C’est 0xFF00 pour activer et 0x0000 pour désactiver. Toute autre valeur doit produire l’exception 03.
Requête et réponse sont identiques : 01 05 00 AC FF 00 4C 1B
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | — |
| Code fonction | 05 | 5 | Write Single Coil |
| Adresse du bit | 00 AC | 172 | Bit visé |
| Valeur | FF 00 | ON | FF 00 = ON, 00 00 = OFF, rien d’autre |
| CRC | 4C 1B | — | — |
Comme pour 0x06, la réponse est un écho.
0x0F — Write Multiple Coils
Écrit jusqu’à 1968 bits. Même emballage que pour la lecture : huit bits par octet, poids faible en premier.
Requête : 01 0F 00 00 00 0A 02 CD 01 70 68
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | — |
| Code fonction | 0F | 15 | Write Multiple Coils |
| Adresse de départ | 00 00 | 0 | Premier bit écrit |
| Quantité | 00 0A | 10 | Nombre de bits, 1 à 1968 |
| Nombre d’octets | 02 | 2 | ⌈10 / 8⌉ |
| Octet 1 | CD | — | Bits 0 à 7 |
| Octet 2 | 01 | — | Bits 8 et 9, plus 6 bits de bourrage à 0 |
| CRC | 70 68 | — | — |
0x16 — Mask Write Register
Le code que trop peu d’ingénieurs connaissent, et qui résout un vrai problème.
Pour changer un seul bit dans un mot de commande, le réflexe est de lire le registre, modifier le bit, réécrire le tout. Entre la lecture et l’écriture, un autre client peut avoir modifié un bit voisin. Vous l’écrasez.
Le code 0x16 fait l’opération dans l’équipement, de façon atomique :
Résultat = (Valeur_actuelle ET Masque_ET) OU (Masque_OU ET NON Masque_ET)Requête et réponse sont identiques : 01 16 00 04 00 F2 00 25 67 EE
| Champ | Hex | Valeur | Rôle |
|---|---|---|---|
| Adresse esclave | 01 | 1 | — |
| Code fonction | 16 | 22 | Mask Write Register |
| Adresse | 00 04 | 4 | Registre visé |
| Masque ET | 00 F2 | — | Bits conservés |
| Masque OU | 00 25 | — | Bits forcés à 1 |
| CRC | 67 EE | — | — |
Avec une valeur courante de 0x12, le résultat vaut 0x17. La réponse est un écho de la requête.
Tous les équipements ne l’implémentent pas. Testez avant de bâtir votre logique dessus.
0x17 — Read/Write Multiple Registers
Lecture et écriture dans une seule transaction. L’écriture est effectuée avant la lecture.
Intéressant sur un bus série chargé : vous divisez par deux le nombre d’échanges pour un schéma commande/retour d’état. Peu implémenté en pratique.
0x2B / 0x0E — Read Device Identification
Sous-fonction du transport encapsulé. Retourne des chaînes de caractères : nom du constructeur, code produit, version du micrologiciel, et parfois le nom du modèle et l’URL du constructeur.
Très utile en recensement de parc. Une passe de 0x2B/0x0E sur toutes les adresses vous donne un inventaire sans ouvrir une armoire. Support inégal selon les gammes.
Les codes de diagnostic série
Ces codes ne fonctionnent que sur liaison série. Sur Modbus TCP, ils retournent l’exception 01.
0x08 — Diagnostics porte des sous-fonctions sur 2 octets. Les plus utilisées :
| Sous-code | Fonction |
|---|---|
| 0x0000 | Renvoie les données de la requête, test de boucle |
| 0x0001 | Redémarre l’option de communication |
| 0x0004 | Force le mode écoute seule |
| 0x000B | Compteur de messages sur le bus |
| 0x000C | Compteur d’erreurs de communication |
| 0x000D | Compteur d’erreurs d’exception |
| 0x000E | Compteur de messages destinés à ce serveur |
| 0x000F | Compteur de non-réponses |
| 0x0012 | Compteur de dépassements de caractères |
Le sous-code 0x0000 est un excellent test de liaison. Si l’écho revient correct, la couche physique et la temporisation sont bonnes. Le problème est alors ailleurs.
Le compteur 0x0012 est un indicateur direct de problème de câblage ou de temporisation.
0x11 — Report Server ID renvoie une identification propre au constructeur, plus un octet d’état marche/arrêt. Le format n’est pas normalisé.
Ce que la spécification ne garantit pas
Trois écarts à connaître avant de déclarer un équipement défectueux.
Le support des codes n’est pas obligatoire. Un équipement peut n’implémenter que 0x03 et 0x10. C’est conforme. L’exception 01 en réponse à 0x04 n’est pas un défaut.
Les limites de quantité sont des maximums théoriques. Beaucoup d’équipements plafonnent bien en dessous. Un compteur qui refuse une lecture de 125 registres mais accepte 30 est courant. Réduisez la taille du groupe avant de conclure.
Les plages contiguës ne le sont pas toujours. Une lecture couvrant un trou dans la cartographie renvoie l’exception 02, même si toutes les adresses demandées existent individuellement. Découpez vos groupes de poll selon les blocs réellement définis dans la documentation.
Questions fréquentes
Quelle est la différence entre le code fonction 03 et le code 04 ?
La table visée. Le 03 lit les holding registers, en lecture/écriture. Le 04 lit les input registers, en lecture seule. La trame est identique par ailleurs.
Pourquoi ma requête renvoie-t-elle le code fonction 0x83 ?
C’est une réponse d’exception. Le serveur ajoute 0x80 au code fonction pour signaler une erreur. L’octet suivant donne le code d’exception.
Combien de registres peut-on lire en une seule requête ?
125 au maximum avec les codes 03 et 04, à cause de la limite de 253 octets pour la PDU. En écriture avec le code 16, la limite descend à 123.
Le code fonction 05 accepte-t-il la valeur 0x0001 ?
Non. Seules les valeurs 0xFF00 et 0x0000 sont valides. Toute autre valeur doit produire l’exception 03.
Comment écrire un flottant en Modbus ?
Avec le code 16 sur deux registres consécutifs, en une seule transaction. Vérifiez l’ordre des mots attendu par l’équipement avant d’écrire.
Les codes fonction sont-ils les mêmes en RTU et en TCP ?
Oui, à l’exception des codes de diagnostic série (07, 08, 11, 12, 17) qui ne sont pas disponibles sur Modbus TCP.
