Modbus RTU
modbus
library implements Modbus RTU communication for ENP-RS232 and ENP-RS485 modules.
Initialize communication interface with rs232.init
or rs485.init
function before using modbus
.
modbus.read_coils
-- @param address number Address of Modbus device
-- @param start_register number Number of the first register to read
-- @param registers_count number Number of registers to read
-- @param timeout number Time to wait for the response in milliseconds
-- @return table|nil, number
function modbus.read_coils(address, start_register, registers_count, timeout)
end
Reads coil registers, Modbus function 0x01
.
Returns Lua table with register contents or nil
in case of error. Error code is returned as a second return value (use modbus.err_to_str
to convert it to string representation).
Example
-- Read two coil registers (numbers 215 and 216), timeout 1 second
registers, result = modbus.read_coils(1, 215, 2, 1000)
if registers then
enapter.log("Coils: "..tostring(registers[1]).." "..tostring(registers[2]))
else
enapter.log("Error reading Modbus: "..tostring(result).." "..modbus.err_to_str(result), "error", true)
end
modbus.read_discrete_inputs
-- @param address number Address of Modbus device
-- @param start_register number Number of the first register to read
-- @param registers_count number Number of registers to read
-- @param timeout number Time to wait for the response in milliseconds
-- @return table|nil, number
function modbus.read_discrete_inputs(address, start_register, registers_count, timeout)
end
Reads discrete input registers, Modbus function 0x02
.
Returns Lua table with register contents or nil
in case of error. Error code is returned as a second return value (use modbus.err_to_str
to convert it to string representation).
Example
-- Read two discrete input registers (numbers 220 and 221), timeout 1 second
registers, result = modbus.read_discrete_inputs(1, 220, 2, 1000)
if registers then
enapter.log("Discrete input: "..tostring(registers[1]).." "..tostring(registers[2]))
else
enapter.log("Error reading Modbus: "..tostring(result).." "..modbus.err_to_str(result), "error", true)
end
modbus.read_holdings
-- @param address number Address of Modbus device
-- @param start_register number Number of the first register to read
-- @param registers_count number Number of registers to read
-- @param timeout number Time to wait for the response in milliseconds
-- @return table|nil, number
function modbus.read_holdings(address, start_register, registers_count, timeout)
end
Reads holding registers, Modbus function 0x03
.
Returns Lua table with register contents or nil
in case of error. Error code is returned as a second return value (use modbus.err_to_str
to convert it to string representation).
Example
-- Read two holding registers (numbers 230 and 231), timeout 1 second
registers, result = modbus.read_holdings(1, 230, 2, 1000)
if registers then
enapter.log("Holding: "..tostring(registers[1]).." "..tostring(registers[2]))
else
enapter.log("Error reading Modbus: "..tostring(result).." "..modbus.err_to_str(result), "error", true)
end
modbus.read_inputs
-- @param address number Address of Modbus device
-- @param start_register number Number of the first register to read
-- @param registers_count number Number of registers to read
-- @param timeout number Time to wait for the response in milliseconds
-- @return table|nil, number
function modbus.read_inputs(address, start_register, registers_count, timeout)
end
Reads input registers, Modbus function 0x04
.
Returns Lua table with register contents or nil
in case of error. Error code is returned as a second return value (use modbus.err_to_str
to convert it to string representation).
Example
-- Read two input registers (numbers 240 and 241), timeout 1 second
registers, result = modbus.read_inputs(1, 240, 2, 1000)
if registers then
enapter.log("Input: "..tostring(registers[1]).." "..tostring(registers[2]))
else
enapter.log("Error reading Modbus: "..tostring(result).." "..modbus.err_to_str(result), "error", true)
end
modbus.write_coil
-- @param address number Address of Modbus device
-- @param register number Register number to write to
-- @param value number Value to write
-- @param timeout number Time to wait for the response in milliseconds
-- @return number
function modbus.write_coil(address, register, value, timeout)
end
Writes coil register, Modbus function 0x05
.
Returns 0
if the value is written successfully, otherwise returns error code (use modbus.err_to_str
to convert it to string representation).
Example
-- Write 0 to coil register number 503, timeout 1 second
result = modbus.write_coil(1, 503, 0, 1000)
if result ~= 0 then
enapter.log("Error writing Modbus: "..tostring(result).." "..modbus.err_to_str(result), "error", true)
end
modbus.write_holding
-- @param address number Address of Modbus device
-- @param register number Register number to write to
-- @param value number Value to write
-- @param timeout number Time to wait for the response in milliseconds
-- @return number
function modbus.write_holding(address, register, value, timeout)
end
Writes holding register, Modbus function 0x06
.
Returns 0
if the value is written successfully, otherwise returns error code (use modbus.err_to_str
to convert it to string representation).
Example
-- Write 12 to holding register number 610, timeout 1 second
result = modbus.write_holding(1, 610, 12, 1000)
if result ~= 0 then
enapter.log("Error writing Modbus: "..tostring(result).." "..modbus.err_to_str(result), "error", true)
end
modbus.write_multiple_coils
-- @param address number Address of Modbus device
-- @param start_register number Number of the first register to write to
-- @param values table Array of values to write to registers
-- @param timeout number Time to wait for the response in milliseconds
-- @return number
function modbus.write_multiple_coils(address, start_register, values, timeout)
end
Writes the sequence of coil registers, Modbus function 0x0F
. The values
table must contain integer values to be written to the registers.
Returns 0
if values are written successfully, otherwise returns error code (use modbus.err_to_str
to convert it to string representation).
Example
-- Write zeroes to coil registers 700 and 701, timeout 1 second
values = {0, 0}
result = modbus.write_multiple_coils(1, 700, values, 1000)
if result ~= 0 then
enapter.log("Error writing Modbus: "..tostring(result).." "..modbus.err_to_str(result), "error", true)
end
modbus.write_multiple_holdings
-- @param address number Address of Modbus device
-- @param start_register number Number of the first register to write to
-- @param values table Array of values to write to registers
-- @param timeout number Time to wait for the response in milliseconds
-- @return number
function modbus.write_multiple_holdings(address, start_register, values, timeout)
end
Writes the sequence of holding registers, Modbus function 0x10
. The values
table must contain integer values to be written to the registers.
Returns 0
if values are written successfully, otherwise returns error code (use modbus.err_to_str
to convert it to string representation).
Example
-- Write values to holding registers 800 and 801, timeout 1 second
values = {14, 15}
result = modbus.write_multiple_coils(1, 800, values, 1000)
if result ~= 0 then
enapter.log("Error writing Modbus: "..tostring(result).." "..modbus.err_to_str(result), "error", true)
end
modbus.err_to_str
-- @param error number
-- @return string
function modbus.err_to_str(error)
end
Returns string representation of modbus
function return code.
Byte Order
A Modbus register is composed of two bytes. Typically, the register value is transferred in Big-Endian byte order. However, the most modern CPUs, including the one in Enapter UCM, use Little-Endian byte order. Given this, the UCM automatically performs endianness conversion, under the assumption that the Modbus server transfers values in Big-Endian order. Consequently, there is no need for you to manually perform this conversion.
Let's take an example. Imagine you have the register number 112
which holds unsigned integer value 4660
(it may be 46.6
℃), which is equal to 0x1234
hexadecimal (two bytes – 0x12
and 0x34
). The value is transferred as 0x3412
(13330
decimal), but when you read it:
-- Read the value of the register 112
registers, result = modbus.read_holdings(1, 112, 1, 1000)
if registers then
value = register[1]
enapter.log("Register value: "..tostring(value))
end
You'll get this logged as expected without any conversions:
Register value: 4660