Modbus

Protocol overview

Modbus Protocol is a messaging structure developed by Modicon in 1979.

Modbus is a "request response" protocol type

MODBUS Application Protocol

Key features:

MODBUS over serial line protocol

Key features:

MODBUS data model

The MODBUS data model is based on a series of tables having distinguishing characteristics.

The four primary tables are:

Primary tables Object type Type of Comments
Discrete Input Single bit Read-Only can be provided by an I/O system
Coils Single bit Read-Write can be altered by an apllication program
Input Registers 16-bit word Read-Only can be provided by an I/O system
Holding Registers 16-bit word Read-Write can be altered by an application program

The distinction between inputs and outputs, and between bit-addressable and word-adressable data items is conceptual. The tables may be overlaying one another.
For each of the primary tables, the protocol allow individual selection of 65536 data items.
All data handled via modbus (bits or registers) must be allocated in device application memory but physical adress in memory should not be confused with data reference.
Modbus logical reference are unsigned integer starting at 0.

Protocol implementations

Supported code functions:

Lua implementation

This implementation is synchronous and thread safe.
It requires the 'pack' to manipulate string buffers.

Serial ASCII and RTU mode

The stack can be initialized with default parametres:

To start a GPIO to signal the transmission and reception phases use "_,err = m:enable_hardware_switch(12,'high')" and "_,err = m:disable_hardware_switch()".

Once initialized you have access to the 8 main MODBUS functions:

  1. ,err=m:request('ReadCoils',,,)
  2. ,err=m:request('ReadDiscreteInputs',,,)
  3. ,err=m:request('ReadHoldingRegisters',,,)
  4. ,err=m:request('ReadInputRegisters',,,)
  5. _,err=m:request('WriteSingleCoil',,,)
  6. _,err=m:request('WriteSingleRegister',,,)
  7. _,err=m:request('WriteMultipleCoils',,,,)
  8. _,err=m:request('WriteMultipleRegisters',,,)

coil and register values are specified as string buffers.

The stack is explicitely closed by calling "m:close()".

require 'modbus'
m,err=modbus.new('/dev/ttyS0',{baudrate=9600,parity='even',timeout=3},'RTU')
data,err=m:request('ReadHoldingRegisters',1,0,40)
if err then print(err) end
if data then
  res={string.unpack(data,"<H40")}
  table.remove(res,1)
  p(res)
end

TCP mode or ASCII and RTU over TCP mode

The stack can be initialized with default parametres:

Once initialized you have access to the 8 main MODBUS functions:

  1. ,err=m:request('ReadCoils',,,,,)
  2. ,err=m:request('ReadDiscreteInputs',,,,,)
  3. ,err=m:request('ReadHoldingRegisters',,,,,)
  4. ,err=m:request('ReadInputRegisters',,,,,)
  5. _,err=m:request('WriteSingleCoil',,,,,)
  6. _,err=m:request('WriteSingleRegister',,,,,)
  7. _,err=m:request('WriteMultipleCoils',,,,,,)
  8. _,err=m:request('WriteMultipleRegisters',,,,,)

is either an ip address or a resolvable hostname.
can be set to nil, in this case the default value is 502.
coil and register values are specified as string buffers.

The stack is explicitely closed by calling "m:close()".

require 'modbustcp'
m,err=modbustcp.new('/dev/ttyS0', {timeout=1,maxsocket=2})

data,err=m:request('ReadHoldingRegisters','10.41.51.164',502,1,0,40)
if err then print(err) end
if data then
  res={string.unpack(data,"<H40")}
  table.remove(res,1)
  p(res)
end