In this tutorial, you will program ESP32 processor to be Modbus TCP Master. We will use two devices, which contain this processor: Moduino ESP32 and Pycom. Both devices are running in MicroPython environment. Our Modbus Slave will be PC computer with Modbus simulator software running on it. You will need:
- Moduino ESP32 or Moduino Pycom device (check this website to find out more about Moduino ESP32 device and this to check Pycom device)
- PC with Linux operating system
- RS-232/RS-485 port in your computer or USB to RS-232/RS-485 converter
Download Modbus Slave simulator from http://www.modbusdriver.com/diagslave.html. Then open downloaded archive and unpack version for Linux operating system.
Run the program from console with -p <port> argument:
./diagslave -p <port>
<port> is a port where the Modbus Slave server will work. For Modbus protocol it is by default 502, but you can use another one.
In Linux ports below 1024 cannot be used by programs run from regular user (not root privileges).
Remember what port you are using. This value will be necessary later.
Step 2: Prepare Your Computer to Connect to the DeviceYou will need some programs to make connection to the device and send files to it.
Install Python environment and pip (if you don't have it):
apt-get install python3
apt-get install python3-dev
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"python3
get-pip.py
Install picocom:
apt-get install picocom
This program is needed to connect to the device and execute commands on it.Install mpfshell:
pip install mpfshell
This program allows you to send files to the device.
You can also install it form sources. Refer this page: https://github.com/wendlers/mpfshellStep 3: Prepare Device and Connect to It
To connect Moduino or Pycom device to PC you need RS-232/RS-485 port or converter. Check version of your device (which port type it uses) and find appropriate port or converter.
- Connect device to PC
- Then connect power supply to it
Connect device to PC and then connect power supply to it. You can also connect ethernet cable to Moduino ESP32 (if it has that port).
Connection should be like in these photos:
If you don't have RS port in your computer, you can use USB-RS converter, such like this:
Find path for port, which is used for device connection.It can be for example: /dev/ttyS1, /dev/ttyUSB0. For usb converters, path will contain USB word.
You can connect to device with picocom program:
picocom /dev/ttyUSB0 -b 115200
Command prompt of device looks similar to one of these images below:
To communicate with Modbus Slave you need appropriate library. Libraries for Pycom aren't compatible with Moduino. Check instructions which comply to your device.Close picocom before sending files: press Ctrl+A and then Ctrl+X keys.uModBus library for Moduino ESP32 bases on pycom-modbus library for Moduino Pycom. It is modified to work on regular ESP32 device. It also has additional close() methods for connector classes.
1) Moduino ESP32
Download library from https://github.com/techbase123/micropython-modbus. Unpack archive and send all 4 files to Moduino device.
Use mpfshell to upload them. Run this program in directory with that files.Connect to device by executing:
ttyUSB0 is a name of serial port where device is connected.Change directory to /flash/lib with command:
cd /flash/lib
Put all files with commands:
put uModBusConst.py
put uModBusFunctions.py
put uModBusTCP.py
put uModBusSerial.py
Then exit console with exit command and restart the device with Reset button.
2) Moduino Pycom
Download library from https://github.com/pycom/pycom-modbus/. Unpack archive and send content of uModbus directory to the device.Use mpfshell to upload them. Run this program in directory with that files.Connect to device by executing:
open ttyUSB0
ttyUSB0 is a name of serial port where device is connected.Change directory to /flash/lib, create uModbus directory and enter it with commands:
cd /flash/lib<br>md uModbus <br>cd uModbus
Put all files with commands:
put const.py
put functions.py
put tcp.py
put serial.py
Then exit console with exit command and restart the device with Reset button.
Commands to establish connection differ between Moduino and Pycom.Connect to device with picocom to execute appropriate commands. You can connect Moduino device to network by wire or wireless. Following examples assumes that your network has working DHCP server.In other case, device won't get IP address.WiFi support is available in every Moduino. Ethernet port is an option and not all devices have it.
1) Moduino ESP32Connecting to WiFi
Execute following commands on the device:
from netWiFi import netWiFi
wifi = netWiFi(netWiFi.WIFI_STA, 'ESSID', 'PASS')
wifi.start()
Replace ESSID with name of your WiFi network, and PASS with password of it.After some time after executing start() you should get an IP address which was assigned to your device.
Connecting to Ethernet network
Connect device to wired network with ethernet cable.Then execute following commands:
from netETH import netETH
eth = netETH()
eth.start()
After some time after executing start() you should get IP address which was assigned to your device.
2) Moduino PycomConnect to WiFi
Execute following commands on the device:
from network import WLAN
wlan = WLAN(mode=WLAN.STA)
nets = wlan.scan()
for net in nets:
if net.ssid == 'ESSID':
print('Network found!')
wlan.connect(net.ssid, auth=(net.sec, 'PASS'), timeout=5000)
while not wlan.isconnected():
machine.idle()
print('WLAN connection succeeded!')
break
Replace ESSID with name of your WiFi network, and PASS with password of it.
Step 6: Initialize Communication With Modbus SlaveModbus Master libraries are similar for both devicesThey vary in initialization.
1) Initialize uModBus on Moduino ESP32
Execute:
from uModBusTCP import uModBusTCP as TCP
2) Initialize uModBus on Pycom
Execute:
from uModbus.tcp import TCP
Open connectionThen open connection with:
modbus=TCP('IP', PORT, 60)
where:
- IP - ip address of your PC with Modbus Slave simulator
- PORT - port of Modbus Slave
- 60 is a timeout
If following error occurs during executing reading/writing commands:
execute:
- for Moduino ESP32:
modbus.close()
- for Moduino Pycom:
modbus._sock.close()
and then recreate connection:
modbus=TCP('IP', PORT, 60)
This is important to close socket before recreating connection.Device has constrainted amount of available socket connection.
Step 7: Read and Write RegistersModbus support several functions to read and write registers.uModBus library has method for each function:
- 1: read_coils
- 2: read_discrete_inputs
- 3: read_holding_registers
- 4: read_input_registers
- 5: write_single_coil
- 6: write_single_register
Firstly, lets write some values.
1) Write coils (func: 5)
Write 1 value to 200 register from slave 1:
modbus.write_single_coil(1, 200, 0xFF00)
First argument is for slave id, in our case 1.Second is register number and thirs is a value. For 1 you have to put 0xFF00 here. Write 0 to 201 register from slave 1:
modbus.write_single_coil(1, 201, 0)
This method allows writting only boolean values: 0 or 1.
2) Write registers (func: 6)
Now write some integer values to several registers.
Write signed 111 value to register 100 from slave 1:
modbus.write_single_register(1, 100, 111, True)
First argument is slave id, second register number and third is new value.Last argument defines if value should be set as signed number. Default value for it is True. You don't need to set it.
Write signed -457 value to 101 register from slave 1:
modbus.write_single_register(1, 101, -457)
Write not signed 50 value to 100 register from slave 3:
modbus.write_single_register(3, 100, 50, False)
This method allows writting integer values to single register.Single register can contain 16 bit values.Method returns True is input value is valid and False if not. Value is written even if is invalid (too big for register)
3) Read coils/discrete inputs
Now lets read written boolean values. To read register with function 1 read coil, execute:
modbus.read_coils(slaveId, register, count)[0:count]
To read register with function 2 read discrete input, execute:
modbus.read_discrete_inputs(slaveId, register, count)[0:count]
where:
- slave-id - id of virtual slave (Slave simulator accepts all valid ids)
- register - register number for reading
- count - amount of registers to be read (put desired amount in both places)
These methods return array with boolean values. Each value correspond to each register.
The fragment: [0:count] is needed, because this method returns more values, than count. It returns always amount of values which is divisible by 8. Additional values are False and don't corresponds to any register.
Read our boolean values with both methods:
modbus.read_coils(1,200,2)[0:2]modbus.read_discrete_inputs(1,200,2)[0:2]
Result will be like these:
True refers to 1 value, False to 0.
4) Read registers
Now read values from registers written with 6 function.
To read registers with function 3 read holding registers, execute:
modbus.read_holding_registers(slaveId, register, count, signed=True)
To read registers with function 4 read input registers, execute:
modbus.read_input_registers(slaveId, register, count, signed=True)
where:
- slave-id - id of virtual slave
- register - register number for reading
- count - amount of registers to be read
- signed - indicates if read values should be treated as signed numbers or not. Default state: True
Return value is a tuple with desired amount of registers.
Read registers set in previous point:
modbus.read_holding_registers(1,100,2,True)
modbus.read_input_registers(1,100,2,True)
modbus.read_holding_registers(3,100,1,False)
modbus.read_input_registers(3,100,1,False)
Results should look like in this screenshot:
In the next lesson you will learn how to create Modbus RTU Master on ESP32-enabled device.
Thank you for your participation. :)
Comments