class ModbusRTUSlave – Modbus RTU slave

ModbusRTUSlave implements the Modbus RTU slave. ModbusRTUSlave support function codes 1 (Read Coils), 2 (Read Discrete Inputs), 3 (Read Holding Registers), 4 (Read Input Registers), 5 (Write Single Coil), 6 (Write Single Holding Register), 15 (Write Multiple Coils), and 16 (Write Multiple Holding Registers).

Micropython Example:

  1# SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4
  5import os, sys, io
  6import M5
  7from M5 import *
  8import modbus
  9from unit import ISO485Unit
 10
 11
 12label0 = None
 13label1 = None
 14label2 = None
 15modbusrtuslave_0 = None
 16iso485_0 = None
 17
 18
 19register1 = None
 20slave_value1 = None
 21starting_register1 = None
 22slave_list1 = None
 23starting_register4 = None
 24slave_list4 = None
 25register2 = None
 26slave_value2 = None
 27starting_register2 = None
 28slave_list2 = None
 29starting_register6 = None
 30slave_list6 = None
 31starting_register5 = None
 32slave_list5 = None
 33starting_register3 = None
 34slave_list3 = None
 35
 36
 37def modbus_write_single_coil_cb(args):
 38    global \
 39        label0, \
 40        label1, \
 41        label2, \
 42        modbusrtuslave_0, \
 43        iso485_0, \
 44        register1, \
 45        slave_value1, \
 46        starting_register1, \
 47        slave_list1, \
 48        starting_register4, \
 49        slave_list4, \
 50        register2, \
 51        slave_value2, \
 52        starting_register2, \
 53        slave_list2, \
 54        starting_register6, \
 55        slave_list6, \
 56        starting_register5, \
 57        slave_list5, \
 58        starting_register3, \
 59        slave_list3
 60    _, register1, slave_value1 = args
 61    label0.setText(str("write single coil"))
 62    label1.setText(str(register1))
 63    label2.setText(str(slave_value1))
 64
 65
 66def modbus_read_coils_cb(args):
 67    global \
 68        label0, \
 69        label1, \
 70        label2, \
 71        modbusrtuslave_0, \
 72        iso485_0, \
 73        register1, \
 74        slave_value1, \
 75        starting_register1, \
 76        slave_list1, \
 77        starting_register4, \
 78        slave_list4, \
 79        register2, \
 80        slave_value2, \
 81        starting_register2, \
 82        slave_list2, \
 83        starting_register6, \
 84        slave_list6, \
 85        starting_register5, \
 86        slave_list5, \
 87        starting_register3, \
 88        slave_list3
 89    _, starting_register1, slave_list1 = args
 90    label0.setText(str("read coils"))
 91    label1.setText(str(starting_register1))
 92    label2.setText(str(slave_list1))
 93
 94
 95def modbus_read_input_registers_cb(args):
 96    global \
 97        label0, \
 98        label1, \
 99        label2, \
100        modbusrtuslave_0, \
101        iso485_0, \
102        register1, \
103        slave_value1, \
104        starting_register1, \
105        slave_list1, \
106        starting_register4, \
107        slave_list4, \
108        register2, \
109        slave_value2, \
110        starting_register2, \
111        slave_list2, \
112        starting_register6, \
113        slave_list6, \
114        starting_register5, \
115        slave_list5, \
116        starting_register3, \
117        slave_list3
118    _, starting_register4, slave_list4 = args
119    label0.setText(str("read input register"))
120    label1.setText(str(starting_register4))
121    label2.setText(str(slave_list4))
122
123
124def modbus_write_single_registers_cb(args):
125    global \
126        label0, \
127        label1, \
128        label2, \
129        modbusrtuslave_0, \
130        iso485_0, \
131        register1, \
132        slave_value1, \
133        starting_register1, \
134        slave_list1, \
135        starting_register4, \
136        slave_list4, \
137        register2, \
138        slave_value2, \
139        starting_register2, \
140        slave_list2, \
141        starting_register6, \
142        slave_list6, \
143        starting_register5, \
144        slave_list5, \
145        starting_register3, \
146        slave_list3
147    _, register2, slave_value2 = args
148    label0.setText(str("write single registers"))
149    label1.setText(str(register2))
150    label2.setText(str(slave_value2))
151
152
153def modbus_read_discrete_inputs_cb(args):
154    global \
155        label0, \
156        label1, \
157        label2, \
158        modbusrtuslave_0, \
159        iso485_0, \
160        register1, \
161        slave_value1, \
162        starting_register1, \
163        slave_list1, \
164        starting_register4, \
165        slave_list4, \
166        register2, \
167        slave_value2, \
168        starting_register2, \
169        slave_list2, \
170        starting_register6, \
171        slave_list6, \
172        starting_register5, \
173        slave_list5, \
174        starting_register3, \
175        slave_list3
176    _, starting_register2, slave_list2 = args
177    label0.setText(str("read  discrete input"))
178    label1.setText(str(starting_register2))
179    label2.setText(str(slave_list2))
180
181
182def modbus_write_multiple_registers_cb(args):
183    global \
184        label0, \
185        label1, \
186        label2, \
187        modbusrtuslave_0, \
188        iso485_0, \
189        register1, \
190        slave_value1, \
191        starting_register1, \
192        slave_list1, \
193        starting_register4, \
194        slave_list4, \
195        register2, \
196        slave_value2, \
197        starting_register2, \
198        slave_list2, \
199        starting_register6, \
200        slave_list6, \
201        starting_register5, \
202        slave_list5, \
203        starting_register3, \
204        slave_list3
205    _, starting_register6, slave_list6 = args
206    label0.setText(str("write multiple registers"))
207    label1.setText(str(slave_list6))
208    label2.setText(str(slave_list6))
209
210
211def modbus_write_multiple_coils_cb(args):
212    global \
213        label0, \
214        label1, \
215        label2, \
216        modbusrtuslave_0, \
217        iso485_0, \
218        register1, \
219        slave_value1, \
220        starting_register1, \
221        slave_list1, \
222        starting_register4, \
223        slave_list4, \
224        register2, \
225        slave_value2, \
226        starting_register2, \
227        slave_list2, \
228        starting_register6, \
229        slave_list6, \
230        starting_register5, \
231        slave_list5, \
232        starting_register3, \
233        slave_list3
234    _, starting_register5, slave_list5 = args
235    label0.setText(str("write multiple coils"))
236    label1.setText(str(slave_list5))
237    label2.setText(str(slave_list5))
238
239
240def modbus_read_holding_registers_cb(args):
241    global \
242        label0, \
243        label1, \
244        label2, \
245        modbusrtuslave_0, \
246        iso485_0, \
247        register1, \
248        slave_value1, \
249        starting_register1, \
250        slave_list1, \
251        starting_register4, \
252        slave_list4, \
253        register2, \
254        slave_value2, \
255        starting_register2, \
256        slave_list2, \
257        starting_register6, \
258        slave_list6, \
259        starting_register5, \
260        slave_list5, \
261        starting_register3, \
262        slave_list3
263    _, starting_register3, slave_list3 = args
264    label0.setText(str("read holding register"))
265    label1.setText(str(starting_register3))
266    label2.setText(str(slave_list3))
267
268
269def setup():
270    global \
271        label0, \
272        label1, \
273        label2, \
274        modbusrtuslave_0, \
275        iso485_0, \
276        register1, \
277        slave_value1, \
278        starting_register1, \
279        slave_list1, \
280        starting_register4, \
281        slave_list4, \
282        register2, \
283        slave_value2, \
284        starting_register2, \
285        slave_list2, \
286        starting_register6, \
287        slave_list6, \
288        starting_register5, \
289        slave_list5, \
290        starting_register3, \
291        slave_list3
292
293    M5.begin()
294    Widgets.fillScreen(0x222222)
295    label0 = Widgets.Label("label0", 79, 60, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
296    label1 = Widgets.Label("label1", 73, 100, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
297    label2 = Widgets.Label("label2", 67, 135, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
298
299    iso485_0 = ISO485Unit(2, port=(18, 17))
300    iso485_0.init(
301        tx_pin=None,
302        rx_pin=None,
303        baudrate=115200,
304        data_bits=None,
305        stop_bits=None,
306        parity=None,
307        ctrl_pin=None,
308    )
309    modbusrtuslave_0 = modbus.ModbusRTUSlave(iso485_0, device_address=1, verbose=False)
310    modbusrtuslave_0.set_callback(
311        modbusrtuslave_0.WRITE_SINGLE_COIL_EVENT, modbus_write_single_coil_cb
312    )
313    modbusrtuslave_0.set_callback(modbusrtuslave_0.READ_COILS_EVENT, modbus_read_coils_cb)
314    modbusrtuslave_0.set_callback(
315        modbusrtuslave_0.READ_INPUT_REGISTERS_EVENT, modbus_read_input_registers_cb
316    )
317    modbusrtuslave_0.set_callback(
318        modbusrtuslave_0.WRITE_SINGLE_REGISTER_EVENT, modbus_write_single_registers_cb
319    )
320    modbusrtuslave_0.set_callback(
321        modbusrtuslave_0.READ_DISCRETE_INPUTS_EVENT, modbus_read_discrete_inputs_cb
322    )
323    modbusrtuslave_0.set_callback(
324        modbusrtuslave_0.WRITE_MULTIPLE_REGISTERS_EVENT, modbus_write_multiple_registers_cb
325    )
326    modbusrtuslave_0.set_callback(
327        modbusrtuslave_0.WRITE_MULTIPLE_COILS_EVENT, modbus_write_multiple_coils_cb
328    )
329    modbusrtuslave_0.set_callback(
330        modbusrtuslave_0.READ_HOLDING_REGISTERS_EVENT, modbus_read_holding_registers_cb
331    )
332    modbusrtuslave_0.add_coil(0, True)
333    modbusrtuslave_0.add_coil(1, False)
334    modbusrtuslave_0.add_discrete_input(0, True)
335    modbusrtuslave_0.add_discrete_input(1, False)
336    modbusrtuslave_0.add_holding_register(0, 0x0102)
337    modbusrtuslave_0.add_holding_register(1, 0x0304)
338    modbusrtuslave_0.add_input_register(0, 0x0102)
339    modbusrtuslave_0.add_input_register(1, 0x0304)
340
341
342def loop():
343    global \
344        label0, \
345        label1, \
346        label2, \
347        modbusrtuslave_0, \
348        iso485_0, \
349        register1, \
350        slave_value1, \
351        starting_register1, \
352        slave_list1, \
353        starting_register4, \
354        slave_list4, \
355        register2, \
356        slave_value2, \
357        starting_register2, \
358        slave_list2, \
359        starting_register6, \
360        slave_list6, \
361        starting_register5, \
362        slave_list5, \
363        starting_register3, \
364        slave_list3
365    M5.update()
366    modbusrtuslave_0.tick()
367
368
369if __name__ == "__main__":
370    try:
371        setup()
372        while True:
373            loop()
374    except (Exception, KeyboardInterrupt) as e:
375        try:
376            from utility import print_error_msg
377
378            print_error_msg(e)
379        except ImportError:
380            print("please update to latest firmware")

UIFLOW2 Example:

example.png

cores3_rtu_slave_example.m5f2

Constructors

class modbus.ModbusRTUSlave(uart, device_address: int = 1, context=None, ignore_unit_id: bool = False, verbose: bool = False)

Create a ModbusRTUSlave object.

参数:
  • uart (UART) – UART object or RS485 object.

  • device_address (int) – Device address. The address is 0 to 247.

  • context (dict) – Modbus server context.

  • ignore_unit_id (bool) – Ignore unit ID(or Device address).

  • verbose (bool) – Verbose mode.

context is a dictionary that contains the Modbus server context. the format is as follows:

{
    "discrete_inputs": [
        {
            "register": 0,  # Start address of the discrete inputs.
            "value": [False, True, False, True]  # Values of the discrete inputs. quantity is the length of the list.
        }
    ],
    "coils": [
        {
            "register": 0,  # Start address of the coils.
            "value": [False, True, False, True]  # Values of the coils. quantity is the length of the list. quantity is the length of the list.
        }
    ],
    "input_registers": [
        {
            "register": 0,  # Start address of the input registers.
            "value": [0x0000, 0x0001, 0x0002, 0x0003]  # Values of the input registers. quantity is the length of the list. quantity is the length of the list.
        }
    ],
    "holding_registers": [
        {
            "register": 0,  # Start address of the holding registers.
            "value": [0x0000, 0x0001, 0x0002, 0x0003]  # Values of the holding registers. quantity is the length of the list. quantity is the length of the list.
        }
    ],
}

UIFLOW2:

init.png

Methods

ModbusRTUSlave.start() None

Start the Modbus RTU slave.

UIFLOW2:

start.png

ModbusRTUSlave.stop() None

Stop the Modbus RTU slave.

UIFLOW2:

stop.png

ModbusRTUSlave.add_coil(register: int, value: bool) None

Add a coil to the modbus register dictionary.

参数:
  • register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to add. The value is True or False.

UIFLOW2:

add_coil.png

ModbusRTUSlave.add_discrete_input(register: int, value: bool) None

Add a discrete input to the modbus register dictionary.

参数:
  • register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to add. The value is True or False.

UIFLOW2:

add_discrete_input.png

ModbusRTUSlave.add_holding_register(register: int, value: int) None

Add a holding register to the modbus register dictionary.

参数:
  • register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to add. The value is 0x0000 to 0xFFFF.

UIFLOW2:

add_holding_register.png

ModbusRTUSlave.add_input_register(register: int, value: int) None

Add an input register to the modbus register dictionary.

参数:
  • register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to add. The value is 0x0000 to 0xFFFF.

UIFLOW2:

add_input_register.png

ModbusRTUSlave.remove_coil(register: int) None

Remove a coil from the modbus register dictionary.

参数:

register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

UIFLOW2:

remove_coil.png

ModbusRTUSlave.remove_discrete_input(register: int) None

Remove a discrete input from the modbus register dictionary.

参数:

register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

UIFLOW2:

remove_discrete_input.png

ModbusRTUSlave.remove_holding_register(register: int) None

Remove a holding register from the modbus register dictionary.

参数:

register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

UIFLOW2:

remove_holding_register.png

ModbusRTUSlave.remove_input_register(register: int) None

Remove an input register from the modbus register dictionary.

参数:

register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

UIFLOW2:

remove_input_register.png

ModbusRTUSlave.get_coil(register: int) bool

Get the coil value.

参数:

register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

返回:

The value of the coil.

UIFLOW2:

get_coil.png

ModbusRTUSlave.get_discrete_input(register: int) bool

Get the discrete input value.

参数:

register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

返回:

The value of the discrete input.

UIFLOW2:

get_discrete_input.png

ModbusRTUSlave.get_holding_register(register: int) int

Get the holding register value.

参数:

register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

返回:

The value of the holding register.

UIFLOW2:

get_holding_register.png

ModbusRTUSlave.get_input_register(register: int) int

Get the input register value.

参数:

register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

返回:

The value of the input register.

UIFLOW2:

get_input_register.png

ModbusRTUSlave.set_coil(register: int, value: bool) None

Set the coil value.

参数:
  • register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to set. The value is True or False.

UIFLOW2:

set_coil.png

ModbusRTUSlave.set_multi_coils(register: int, value: list) None

Set the multi coils value.

参数:
  • register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

  • value (list) – Values to set. The value is a list of True or False.

UIFLOW2:

set_multi_coils.png

ModbusRTUSlave.set_discrete_input(register: int, value: bool) None

Set the discrete input value.

参数:
  • register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to set. The value is True or False.

UIFLOW2:

set_discrete_input.png

ModbusRTUSlave.set_multi_discrete_input(register: int, value: list) None

Set the multi discrete inputs value.

参数:
  • register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

  • value (list) – Values to set. The value is a list of True or False.

UIFLOW2:

set_multi_discrete_input.png

ModbusRTUSlave.set_holding_register(register: int, value: int) None

Set the holding register value.

参数:
  • register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to set. The value is 0x0000 to 0xFFFF.

UIFLOW2:

set_holding_register.png

ModbusRTUSlave.set_multi_holding_register(register: int, value: list) None

Set the multi holding registers value.

参数:
  • register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

  • value (list) – Values to set. The value is a list of 0x0000 to 0xFFFF.

UIFLOW2:

set_multi_holding_register.png

ModbusRTUSlave.set_input_register(register: int, value: int) None

Set the input register value.

参数:
  • register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to set. The value is 0x0000 to 0xFFFF.

UIFLOW2:

set_input_register.png

ModbusRTUSlave.set_multi_input_register(register: int, value: list) None

Set the multi input registers value.

参数:
  • register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

  • value (list) – Values to set. The value is a list of 0x0000 to 0xFFFF.

UIFLOW2:

set_multi_input_register.png

ModbusRTUSlave.tick() None

Modbus RTU slave tick function. This function should be called in the main loop.

UIFLOW2:

tick.png

ModbusRTUSlave.set_callback(func_code: int, handler) None

Set the callback function for the function code.

参数:
  • func_code (int) – Function code. The function code is 1 to 6, 15, 16. the symbol is defined in the modbus.ModbusRTUSlave (*_EVENT etc.).

  • handler – Callback function.

UIFLOW2:

read_coils_callback.png

read_discrete_inputs_callback.png

read_holding_registers_callback.png

read_input_registers_callback.png

write_multiple_coils_callback.png

write_multiple_registers_callback.png

write_single_coil_callback.png

write_single_register_callback.png

Constants

ModbusRTUSlave.READ_COILS_EVENT

Function code 1 (Read Coils).

ModbusRTUSlave.READ_DISCRETE_INPUTS_EVENT

Function code 2 (Read Discrete Inputs).

ModbusRTUSlave.READ_HOLDING_REGISTERS_EVENT

Function code 3 (Read Holding Registers).

ModbusRTUSlave.READ_INPUT_REGISTERS_EVENT

Function code 4 (Read Input Registers).

ModbusRTUSlave.WRITE_SINGLE_COIL_EVENT

Function code 5 (Write Single Coil).

ModbusRTUSlave.WRITE_SINGLE_HOLDING_REGISTER_EVENT

Function code 6 (Write Single Holding Register).

ModbusRTUSlave.WRITE_MULTIPLE_COILS_EVENT

Function code 15 (Write Multiple Coils).

ModbusRTUSlave.WRITE_MULTIPLE_HOLDING_REGISTERS_EVENT

Function code 16 (Write Multiple Holding Registers).