---
title: "Arduino Modbus TCP"
url: "https://maker.wiznet.io/teddy/projects/arduino-modbus-tcp/"
markdown_url: "https://maker.wiznet.io/teddy/projects/arduino-modbus-tcp/md"
type: "UCC: User Created Content"
author: "logo tutoduino"
author_url: "https://tutoduino.fr/tutoriels/arduino-modbus-tcp/"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "logo tutoduino"
original_url: "https://tutoduino.fr/tutoriels/arduino-modbus-tcp/"
published: "2022-10-31"
language: "en"
likes: 3
views: 874
comments: 1
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# Arduino Modbus TCP

> Arduino Modbus TCP

Original author: logo tutoduino (source: https://tutoduino.fr/tutoriels/arduino-modbus-tcp/)

## Article

## Arduino Modbus TCP

5

(6)

[Modbus](https://fr.wikipedia.org/wiki/Modbus) est un protocole de communication industriel très répandu. Ce protocole permet de lire et d’écrire des données sur un équipement (un [automate programmable industriel](https://fr.wikipedia.org/wiki/Automate_programmable_industriel) par exemple). Sa première version, nommée Modbus RTU, était basée sur une liaison série (RS232, RS485…). Devant l’adoption massive d’Ethernet dans l’industrie, une seconde version nommée Modbus TCP a été développée. Le format des trames Modbus RTU a été conservé, elles sont simplement encapsulées dans un paquet TCP et transmises sur [Ethernet](https://tutoduino.fr/ethernet/). Modbus TCP suit le principe du [client-serveur](https://fr.wikipedia.org/wiki/Client-serveur), c’est à dire qu’un serveur répond aux demandes d’un ou plusieurs clients.

Dans ce tuto nous allons configurer un serveur Modbus TCP sur un Arduino. Vous pourrez utiliser un client Modbus TCP sur votre PC pour lire et écrire les données du serveur Modbus TCP de l’Arduino.

![](https://tutoduino.fr/wp-content/uploads/2021/12/modbus-protocol-logo_w422.webp)

## Le protocole Modbus

Chaque message Modbus échangé entre un client et un serveur est composé principalement d’un « Code fonction » et d’un « Numéro de registre » suivi d’une valeur de ce registre.

### Les registres

Les données Modbus sont le plus souvent lues et écrites sous forme de « registres ». Les registres ont généralement une taille de 16 bits (1 mot), mais certains registres peuvent avoir une taille différente. Par exemple les « coil » qui sont des sorties binaires (0 ou 1) d’un serveur ont une taille de 1 bit.

Il existe 4 types de registres :

- Les ‘**coils’**, qui correspondent à des sorties binaires (0 ou 1)

- Les **‘input bits’**, qui correspondent à des entrées binaires en lecture seule

- Les **‘input registers’**, qui correspondent à des entrées analogiques en lecture seule

- Les **‘holding registers’**, qui correspondent à des paramètres analogiques modifiables

### Les code fonction

Le type de registre adressé par une requête Modbus est déterminé par le code de fonction.

Les codes les plus courants sont :

- 01 : lire un « **coil »**

- 02 : lire un « **input register »**

- 03 : lire un ou plusieurs « **holding registers »**

- 04 : lire un ou plusieurs « **input registers »**

- 05 : écrire un « **coil »**

- 06 : écrire un « **holding register »**

- 15 : écrire plusieurs « **coils »**

- 16 : écrire un ou plusieurs « holding registers »

## Shield Ethernet Arduino

J’ai utilisé un Arduino Uno pour ce tuto, et comme il n’ont pas de port Ethernet je l’ai équipé d’un [shield Ethernet](https://store.arduino.cc/collections/shields/products/arduino-ethernet-shield-2).

![Arduino Uno Ethernet Shield Modbus TCP](https://tutoduino.fr/wp-content/uploads/2021/12/20211222_094236-1024x693.jpg)

*Arduino Uno équipé du Shield Ethernet 2*

## Librairie Modbus

Il est nécessaire d’installer la librairie **ArduinoModbus** dans l’IDE Arduino. ArduinoModbus nécessite l’installation de la librairie ArduinoRS485.

![](https://tutoduino.fr/wp-content/uploads/2021/12/modbus-lib.png)

*Ajout de la librairie ArduinoModbus*

## Configuration de l’adresse MAC et IP

Chaque carte Ethernet possède sa propre [adresse MAC](https://tutoduino.fr/ethernet/#mac), celle du Shield Ethernet est inscrite sur le dos de la carte. L’adresse MAC de mon Shield Ethernet est ‘**A8:61:0A:AE:7A:08**‘.

![](https://tutoduino.fr/wp-content/uploads/2021/12/20211222_095209-1024x768.jpg)

*Adresse MAC du Shield Ethernet Arduino*

L’adresse IP doit être sélectionnée en fonction de votre réseau local. Ici je choisis par exemple l’adresse IP ‘**192.168.1.88**‘.

![](https://tutoduino.fr/wp-content/uploads/2021/12/Capture-decran-du-2021-12-22-10-13-17.png)

*Configuration de l’adresse MAC et IP du Shield Ethernet*

## Le programme Arduino du serveur Modbus TCP

Je me suis inspiré du programme d’exemple « EthernetModbusServerLED », qui permet de contrôler la LED de l’Arduino Uno via un client Modbus TCP. Mais j’ai utilisé des registres de type « holding register » et non « coil » car j’ai remarqué un problème dans mon client Modbus TCP Python qui ne positionne pas correctement les valeurs de ce type de registre… J’ai également ajouté un compteur qui s’incrémente continuellement et que l’on peut lire depuis le client Modbus TCP dans le « **holding register** » à l’adresse 0.

| `/*` `Modbus TCP server` `Created December 2021` `by Tutoduino` `*/` `#include` `<SPI.h>` `#include` `<Ethernet.h>` `#include` `<ArduinoModbus.h>` `// MAC address of the Ethernet Shield` `byte` `mac[] ``=` `{ ``0xA8``, ``0x61``, ``0x0A``, ``0xAE``, ``0x7A``, ``0x08` `};` `// IP address of the Ethernet Shield` `IPAddress ip(``192``, ``168``, ``1``, ``88``);` `// We use the default TCP port (502) of ModbusTcp` `EthernetServer ethServer(``502``);` `ModbusTCPServer modbusTCPServer;` `const` `int` `ledPin ``=` `7``;` `int` `counter ``=` `0``;` `void` `setup``() {` `Serial.begin``(``115200``);` `Serial.println``(``"Ethernet Modbus TCP Example"``);` `// start the Ethernet connection` `Ethernet.begin(mac, ip);` `// start the Ethernet server` `ethServer.begin();` `// start the Modbus TCP server` `if` `(``!``modbusTCPServer.begin()) {` `Serial.println``(``"Failed to start Modbus TCP Server!"``);` `while` `(``true``) {` `delay``(``1``); ``// do nothing, no point running without Modbus server` `}` `}` `// configure the LED as output` `pinMode``(ledPin, ``OUTPUT``);` `digitalWrite``(ledPin, ``LOW``);` `// configure 1 holding starting at address 0x00` `modbusTCPServer.configureHoldingRegisters(``0x00``, ``1``); ` `// configure 1 holding starting at address 0x00` `modbusTCPServer.configureHoldingRegisters(``0x01``, ``1``); ` `}` `void` `loop``() {` `// listen for incoming clients` `EthernetClient client ``=` `ethServer.available();` `if` `(client) {` `// a new client connected` `Serial.println``(``"new client"``);` `// let the Modbus TCP accept the connection` `modbusTCPServer.accept(client);` `// loop while the client is connected` `while` `(client.connected()) {` `// Increment internal counter, while client is connected` `counter``++``;` `// poll for Modbus TCP requests, while client connected` `modbusTCPServer.poll();` `// update registers` `updateRegisters();` `}` `Serial.println``(``"client disconnected"``);` `}` `}` `void` `updateRegisters() {` `// If holding register #0 is set, turn on the LED` `if` `(modbusTCPServer.holdingRegisterRead(``0x00``) ``==` `1``) {` `digitalWrite``(ledPin, ``HIGH``);` `} ``else` `{` `digitalWrite``(ledPin, ``LOW``);` `}` `// Write value of the counter into holding register #1` `if` `(modbusTCPServer.holdingRegisterWrite(``0x01``, counter) ``!=` `1``) {` `Serial.println``(``"Error while writing holding register"``);` `}` `}` |
| --- |

Une autre librairie Modbus semble intéressante également.Il s’agit de la librairie [**modbus-esp8266**](https://github.com/emelianov/modbus-esp8266). Cette librairie utilise bien moins de mémoire dynamique que la précédente. Voici le résultat de compilation du programme basé sur la librairie **modbus-esp8266** :

```
Le croquis utilise 21500 octets (66%) de l'espace de stockage de programmes. Le maximum est de 32256 octets.
Les variables globales utilisent 533 octets (26%) de mémoire dynamique, ce qui laisse 1515 octets pour les variables locales. Le maximum est de 2048 octets.
```

A comparer au résultat de compilation du programme basé sur la librairie **ArduinoModbus** :

```
Le croquis utilise 22246 octets (68%) de l'espace de stockage de programmes. Le maximum est de 32256 octets.
Les variables globales utilisent 1562 octets (76%) de mémoire dynamique, ce qui laisse 486 octets pour les variables locales. Le maximum est de 2048 octets.
```

Voici le programme adapté pour la librairie modbus-esp8266 :

| `/*` `Modbus TCP server` `Created December 2021` `by Tutoduino` `Based on the library from Alexander Emelianov (a.m.emelianov@gmail.com)` [`https://github.com/emelianov/modbus-esp8266`](https://github.com/emelianov/modbus-esp8266) `This code is licensed under the BSD New License. See LICENSE.txt for more info.` `*/` `#include` `<SPI.h>` `#include` `<Ethernet.h>` `#include` `<ModbusEthernet.h>` `// MAC address of the Ethernet Shield` `byte` `mac[] ``=` `{ ``0xA8``, ``0x61``, ``0x0A``, ``0xAE``, ``0x7A``, ``0x08` `};` `// IP address of the Ethernet Shield` `IPAddress ip(``192``, ``168``, ``1``, ``88``);` `// ModbusTCP instance` `ModbusEthernet modbusTCP; ` `// Internal counter` `int` `counter ``=` `0``;` `void` `setup``() {` `Serial.begin``(``115200``);` `// configure the PIN 7 as output` `pinMode``(``7``, ``OUTPUT``);` `// start the Ethernet connection` `Ethernet.begin(mac, ip); ` `Serial.println``(``"Modbus TCP server is starting"``);` `// configure as Modbus TCP server` `modbusTCP.server(); ` `// Add two holding registers` `modbusTCP.addReg(HREG(``0``));` `modbusTCP.addReg(HREG(``1``));` `}` `void` `loop``() {` `uint16_t value``=``0``;` `// Server Modbus TCP queries` `modbusTCP.task(); ` `value ``=` `modbusTCP.Reg(HREG(``0``));` `// If holding register #0 is 1, set the LED` `if` `(value ``==` `1``) {` `digitalWrite``(``7``, ``HIGH``);` `} ``else` `{` `digitalWrite``(``7``, ``LOW``);` `}` `// Increment counter and write it into holding register #1` `counter``++``;` `modbusTCP.Reg(HREG(``1``),counter);` `delay``(``50``);` `}` |
| --- |

## Le client Modbus TCP

Vous pouvez utiliser n’importe quel client Modbus TCP sur votre ordinateur. Il en existe de nombreux sous tous les systèmes (Linux, Windows, Mac…). Je vous laisse regarder sur [Qwant](https://www.qwant.com/?l=fr), le Google Français plus respectueux des données de ses utilisateurs ;).

Pour ma part, étant sur Linux et aimant bien utiliser le langage Python, j’utilise le projet [pyModbusTCP](https://pypi.org/project/pyModbusTCP/) Il permet d’utiliser très simplement un client Modbus TCP en Python.

Installation du module dans un terminal Linux :

| `$ ``sudo` `pip ``install` `pyModbusTCP` |
| --- |

On lance la console Python 3 dans le terminal Linux :

| `$ Python3` |
| --- |

Création d’un client avec l’adresse IP du serveur sur l’Arduino, dans l’interpréteur Python3 :

| `from` `pyModbusTCP.client ``import` `ModbusClient` `c ``=` `ModbusClient(host``=``"192.168.1.88"``, port``=``502``, unit_id``=``1``, auto_open``=``True``)` |
| --- |

Lecture de l’état du **« holding register »** #0 dans l’interpréteur Python3 :

| `value ``=` `c.read_holding_registers(``0``,``1``)` `print``(value)` |
| --- |

Positionne la valeur « 1 » dans le **« holding register »** #0 dans l’interpréteur Python3 :

| `c.write_single_register(``0``,``1``)` |
| --- |

La LED s’allume, la valeur du **« holding register »** #0 est bien passée à 1 sur l’Arduino !

Lecture du compteur interne dans le **« holding register »** #1 dans l’interpréteur Python3:

| `c.read_holding_registers(``1``,``1``)` |
| --- |

![](https://tutoduino.fr/wp-content/uploads/2021/12/Capture-decran-du-2021-12-22-19-41-00.png)

*Exécution des commandes du client Modbus TCP dans l’interpréteur Python 3*

---

Source: https://maker.wiznet.io/teddy/projects/arduino-modbus-tcp/
