ModbusMaster  v2.0.1
Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol).
ModbusMaster Class Reference

Arduino class library for communicating with Modbus slaves over RS232/485 (via RTU protocol). More...

#include <ModbusMaster.h>

Public Member Functions

 ModbusMaster ()
 Constructor. More...
 
void begin (uint8_t, Stream &serial)
 Initialize class object. More...
 
void idle (void(*)())
 Set idle time callback function (cooperative multitasking). More...
 
void preTransmission (void(*)())
 Set pre-transmission callback function. More...
 
void postTransmission (void(*)())
 Set post-transmission callback function. More...
 
uint16_t getResponseBuffer (uint8_t)
 Retrieve data from response buffer. More...
 
void clearResponseBuffer ()
 Clear Modbus response buffer. More...
 
uint8_t setTransmitBuffer (uint8_t, uint16_t)
 Place data in transmit buffer. More...
 
void clearTransmitBuffer ()
 Clear Modbus transmit buffer. More...
 
void beginTransmission (uint16_t)
 
uint8_t requestFrom (uint16_t, uint16_t)
 
void sendBit (bool)
 
void send (uint8_t)
 
void send (uint16_t)
 
void send (uint32_t)
 
uint8_t available (void)
 
uint16_t receive (void)
 
uint8_t readCoils (uint16_t, uint16_t)
 Modbus function 0x01 Read Coils. More...
 
uint8_t readDiscreteInputs (uint16_t, uint16_t)
 Modbus function 0x02 Read Discrete Inputs. More...
 
uint8_t readHoldingRegisters (uint16_t, uint16_t)
 Modbus function 0x03 Read Holding Registers. More...
 
uint8_t readInputRegisters (uint16_t, uint8_t)
 Modbus function 0x04 Read Input Registers. More...
 
uint8_t writeSingleCoil (uint16_t, uint8_t)
 Modbus function 0x05 Write Single Coil. More...
 
uint8_t writeSingleRegister (uint16_t, uint16_t)
 Modbus function 0x06 Write Single Register. More...
 
uint8_t writeMultipleCoils (uint16_t, uint16_t)
 Modbus function 0x0F Write Multiple Coils. More...
 
uint8_t writeMultipleCoils ()
 
uint8_t writeMultipleRegisters (uint16_t, uint16_t)
 Modbus function 0x10 Write Multiple Registers. More...
 
uint8_t writeMultipleRegisters ()
 
uint8_t maskWriteRegister (uint16_t, uint16_t, uint16_t)
 Modbus function 0x16 Mask Write Register. More...
 
uint8_t readWriteMultipleRegisters (uint16_t, uint16_t, uint16_t, uint16_t)
 Modbus function 0x17 Read Write Multiple Registers. More...
 
uint8_t readWriteMultipleRegisters (uint16_t, uint16_t)
 

Static Public Attributes

static const uint8_t ku8MBIllegalFunction = 0x01
 Modbus protocol illegal function exception. More...
 
static const uint8_t ku8MBIllegalDataAddress = 0x02
 Modbus protocol illegal data address exception. More...
 
static const uint8_t ku8MBIllegalDataValue = 0x03
 Modbus protocol illegal data value exception. More...
 
static const uint8_t ku8MBSlaveDeviceFailure = 0x04
 Modbus protocol slave device failure exception. More...
 
static const uint8_t ku8MBSuccess = 0x00
 ModbusMaster success. More...
 
static const uint8_t ku8MBInvalidSlaveID = 0xE0
 ModbusMaster invalid response slave ID exception. More...
 
static const uint8_t ku8MBInvalidFunction = 0xE1
 ModbusMaster invalid response function exception. More...
 
static const uint8_t ku8MBResponseTimedOut = 0xE2
 ModbusMaster response timed out exception. More...
 
static const uint8_t ku8MBInvalidCRC = 0xE3
 ModbusMaster invalid response CRC exception. More...
 

Private Member Functions

uint8_t ModbusMasterTransaction (uint8_t u8MBFunction)
 Modbus transaction engine. More...
 

Private Attributes

Stream * _serial
 reference to serial port object
 
uint8_t _u8MBSlave
 Modbus slave (1..255) initialized in begin()
 
uint16_t _u16ReadAddress
 slave register from which to read
 
uint16_t _u16ReadQty
 quantity of words to read
 
uint16_t _u16ResponseBuffer [ku8MaxBufferSize]
 buffer to store Modbus slave response; read via GetResponseBuffer()
 
uint16_t _u16WriteAddress
 slave register to which to write
 
uint16_t _u16WriteQty
 quantity of words to write
 
uint16_t _u16TransmitBuffer [ku8MaxBufferSize]
 buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer()
 
uint16_t * txBuffer
 
uint8_t _u8TransmitBufferIndex
 
uint16_t u16TransmitBufferLength
 
uint16_t * rxBuffer
 
uint8_t _u8ResponseBufferIndex
 
uint8_t _u8ResponseBufferLength
 
void(* _idle )()
 
void(* _preTransmission )()
 
void(* _postTransmission )()
 

Static Private Attributes

static const uint8_t ku8MaxBufferSize = 64
 size of response/transmit buffers
 
static const uint8_t ku8MBReadCoils = 0x01
 Modbus function 0x01 Read Coils.
 
static const uint8_t ku8MBReadDiscreteInputs = 0x02
 Modbus function 0x02 Read Discrete Inputs.
 
static const uint8_t ku8MBWriteSingleCoil = 0x05
 Modbus function 0x05 Write Single Coil.
 
static const uint8_t ku8MBWriteMultipleCoils = 0x0F
 Modbus function 0x0F Write Multiple Coils.
 
static const uint8_t ku8MBReadHoldingRegisters = 0x03
 Modbus function 0x03 Read Holding Registers.
 
static const uint8_t ku8MBReadInputRegisters = 0x04
 Modbus function 0x04 Read Input Registers.
 
static const uint8_t ku8MBWriteSingleRegister = 0x06
 Modbus function 0x06 Write Single Register.
 
static const uint8_t ku8MBWriteMultipleRegisters = 0x10
 Modbus function 0x10 Write Multiple Registers.
 
static const uint8_t ku8MBMaskWriteRegister = 0x16
 Modbus function 0x16 Mask Write Register.
 
static const uint8_t ku8MBReadWriteMultipleRegisters = 0x17
 Modbus function 0x17 Read Write Multiple Registers.
 
static const uint16_t ku16MBResponseTimeout = 2000
 Modbus timeout [milliseconds].
 

Detailed Description

Arduino class library for communicating with Modbus slaves over RS232/485 (via RTU protocol).

Examples:
examples/Basic/Basic.pde, examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde, and examples/RS485_HalfDuplex/RS485_HalfDuplex.ino.

Member Function Documentation

§ idle()

void ModbusMaster::idle ( void(*)()  idle)

Set idle time callback function (cooperative multitasking).

This function gets called in the idle time between transmission of data and response from slave. Do not call functions that read from the serial buffer that is used by ModbusMaster. Use of i2c/TWI, 1-Wire, other serial ports, etc. is permitted within callback function.

See also
ModbusMaster::ModbusMasterTransaction()
182 {
183  _idle = idle;
184 }
void idle(void(*)())
Set idle time callback function (cooperative multitasking).
Definition: ModbusMaster.cpp:181

§ preTransmission()

void ModbusMaster::preTransmission ( void(*)()  preTransmission)

Set pre-transmission callback function.

This function gets called just before a Modbus message is sent over serial. Typical usage of this callback is to enable an RS485 transceiver's Driver Enable pin, and optionally disable its Receiver Enable pin.

See also
ModbusMaster::ModbusMasterTransaction()
ModbusMaster::postTransmission()
Examples:
examples/RS485_HalfDuplex/RS485_HalfDuplex.ino.
197 {
198  _preTransmission = preTransmission;
199 }
void preTransmission(void(*)())
Set pre-transmission callback function.
Definition: ModbusMaster.cpp:196

§ postTransmission()

void ModbusMaster::postTransmission ( void(*)()  postTransmission)

Set post-transmission callback function.

This function gets called after a Modbus message has finished sending (i.e. after all data has been physically transmitted onto the serial bus).

Typical usage of this callback is to enable an RS485 transceiver's Receiver Enable pin, and disable its Driver Enable pin.

See also
ModbusMaster::ModbusMasterTransaction()
ModbusMaster::preTransmission()
Examples:
examples/RS485_HalfDuplex/RS485_HalfDuplex.ino.
215 {
216  _postTransmission = postTransmission;
217 }
void postTransmission(void(*)())
Set post-transmission callback function.
Definition: ModbusMaster.cpp:214

§ ModbusMasterTransaction()

uint8_t ModbusMaster::ModbusMasterTransaction ( uint8_t  u8MBFunction)
private

Modbus transaction engine.

Sequence:

  • assemble Modbus Request Application Data Unit (ADU), based on particular function called
  • transmit request over selected serial port
  • wait for/retrieve response
  • evaluate/disassemble response
  • return status (success/exception)
Parameters
u8MBFunctionModbus function (0x01..0xFF)
Returns
0 on success; exception number on failure
601 {
602  uint8_t u8ModbusADU[256];
603  uint8_t u8ModbusADUSize = 0;
604  uint8_t i, u8Qty;
605  uint16_t u16CRC;
606  uint32_t u32StartTime;
607  uint8_t u8BytesLeft = 8;
608  uint8_t u8MBStatus = ku8MBSuccess;
609 
610  // assemble Modbus Request Application Data Unit
611  u8ModbusADU[u8ModbusADUSize++] = _u8MBSlave;
612  u8ModbusADU[u8ModbusADUSize++] = u8MBFunction;
613 
614  switch(u8MBFunction)
615  {
616  case ku8MBReadCoils:
621  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadAddress);
622  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadAddress);
623  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadQty);
624  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadQty);
625  break;
626  }
627 
628  switch(u8MBFunction)
629  {
636  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteAddress);
637  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteAddress);
638  break;
639  }
640 
641  switch(u8MBFunction)
642  {
644  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty);
645  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty);
646  break;
647 
649  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]);
650  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]);
651  break;
652 
654  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty);
655  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty);
656  u8Qty = (_u16WriteQty % 8) ? ((_u16WriteQty >> 3) + 1) : (_u16WriteQty >> 3);
657  u8ModbusADU[u8ModbusADUSize++] = u8Qty;
658  for (i = 0; i < u8Qty; i++)
659  {
660  switch(i % 2)
661  {
662  case 0: // i is even
663  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i >> 1]);
664  break;
665 
666  case 1: // i is odd
667  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i >> 1]);
668  break;
669  }
670  }
671  break;
672 
675  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty);
676  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty);
677  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty << 1);
678 
679  for (i = 0; i < lowByte(_u16WriteQty); i++)
680  {
681  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i]);
682  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i]);
683  }
684  break;
685 
687  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]);
688  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]);
689  u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[1]);
690  u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[1]);
691  break;
692  }
693 
694  // append CRC
695  u16CRC = 0xFFFF;
696  for (i = 0; i < u8ModbusADUSize; i++)
697  {
698  u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
699  }
700  u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC);
701  u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC);
702  u8ModbusADU[u8ModbusADUSize] = 0;
703 
704  // flush receive buffer before transmitting request
705  while (_serial->read() != -1);
706 
707  // transmit request
708  if (_preTransmission)
709  {
710  _preTransmission();
711  }
712  for (i = 0; i < u8ModbusADUSize; i++)
713  {
714  _serial->write(u8ModbusADU[i]);
715  }
716 
717  u8ModbusADUSize = 0;
718  _serial->flush(); // flush transmit buffer
719  if (_postTransmission)
720  {
721  _postTransmission();
722  }
723 
724  // loop until we run out of time or bytes, or an error occurs
725  u32StartTime = millis();
726  while (u8BytesLeft && !u8MBStatus)
727  {
728  if (_serial->available())
729  {
730 #if __MODBUSMASTER_DEBUG__
731  digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true);
732 #endif
733  u8ModbusADU[u8ModbusADUSize++] = _serial->read();
734  u8BytesLeft--;
735 #if __MODBUSMASTER_DEBUG__
736  digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false);
737 #endif
738  }
739  else
740  {
741 #if __MODBUSMASTER_DEBUG__
742  digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, true);
743 #endif
744  if (_idle)
745  {
746  _idle();
747  }
748 #if __MODBUSMASTER_DEBUG__
749  digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, false);
750 #endif
751  }
752 
753  // evaluate slave ID, function code once enough bytes have been read
754  if (u8ModbusADUSize == 5)
755  {
756  // verify response is for correct Modbus slave
757  if (u8ModbusADU[0] != _u8MBSlave)
758  {
759  u8MBStatus = ku8MBInvalidSlaveID;
760  break;
761  }
762 
763  // verify response is for correct Modbus function code (mask exception bit 7)
764  if ((u8ModbusADU[1] & 0x7F) != u8MBFunction)
765  {
766  u8MBStatus = ku8MBInvalidFunction;
767  break;
768  }
769 
770  // check whether Modbus exception occurred; return Modbus Exception Code
771  if (bitRead(u8ModbusADU[1], 7))
772  {
773  u8MBStatus = u8ModbusADU[2];
774  break;
775  }
776 
777  // evaluate returned Modbus function code
778  switch(u8ModbusADU[1])
779  {
780  case ku8MBReadCoils:
785  u8BytesLeft = u8ModbusADU[2];
786  break;
787 
792  u8BytesLeft = 3;
793  break;
794 
796  u8BytesLeft = 5;
797  break;
798  }
799  }
800  if ((millis() - u32StartTime) > ku16MBResponseTimeout)
801  {
802  u8MBStatus = ku8MBResponseTimedOut;
803  }
804  }
805 
806  // verify response is large enough to inspect further
807  if (!u8MBStatus && u8ModbusADUSize >= 5)
808  {
809  // calculate CRC
810  u16CRC = 0xFFFF;
811  for (i = 0; i < (u8ModbusADUSize - 2); i++)
812  {
813  u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
814  }
815 
816  // verify CRC
817  if (!u8MBStatus && (lowByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 2] ||
818  highByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 1]))
819  {
820  u8MBStatus = ku8MBInvalidCRC;
821  }
822  }
823 
824  // disassemble ADU into words
825  if (!u8MBStatus)
826  {
827  // evaluate returned Modbus function code
828  switch(u8ModbusADU[1])
829  {
830  case ku8MBReadCoils:
832  // load bytes into word; response bytes are ordered L, H, L, H, ...
833  for (i = 0; i < (u8ModbusADU[2] >> 1); i++)
834  {
835  if (i < ku8MaxBufferSize)
836  {
837  _u16ResponseBuffer[i] = word(u8ModbusADU[2 * i + 4], u8ModbusADU[2 * i + 3]);
838  }
839 
840  _u8ResponseBufferLength = i;
841  }
842 
843  // in the event of an odd number of bytes, load last byte into zero-padded word
844  if (u8ModbusADU[2] % 2)
845  {
846  if (i < ku8MaxBufferSize)
847  {
848  _u16ResponseBuffer[i] = word(0, u8ModbusADU[2 * i + 3]);
849  }
850 
851  _u8ResponseBufferLength = i + 1;
852  }
853  break;
854 
858  // load bytes into word; response bytes are ordered H, L, H, L, ...
859  for (i = 0; i < (u8ModbusADU[2] >> 1); i++)
860  {
861  if (i < ku8MaxBufferSize)
862  {
863  _u16ResponseBuffer[i] = word(u8ModbusADU[2 * i + 3], u8ModbusADU[2 * i + 4]);
864  }
865 
866  _u8ResponseBufferLength = i;
867  }
868  break;
869  }
870  }
871 
872  _u8TransmitBufferIndex = 0;
873  u16TransmitBufferLength = 0;
874  _u8ResponseBufferIndex = 0;
875  return u8MBStatus;
876 }
uint16_t _u16WriteAddress
slave register to which to write
Definition: ModbusMaster.h:227
static const uint8_t ku8MBInvalidFunction
ModbusMaster invalid response function exception.
Definition: ModbusMaster.h:170
static const uint8_t ku8MBWriteSingleRegister
Modbus function 0x06 Write Single Register.
Definition: ModbusMaster.h:246
static const uint8_t ku8MBWriteMultipleRegisters
Modbus function 0x10 Write Multiple Registers.
Definition: ModbusMaster.h:247
static const uint8_t ku8MBResponseTimedOut
ModbusMaster response timed out exception.
Definition: ModbusMaster.h:180
static const uint8_t ku8MBReadHoldingRegisters
Modbus function 0x03 Read Holding Registers.
Definition: ModbusMaster.h:244
static const uint8_t ku8MBWriteSingleCoil
Modbus function 0x05 Write Single Coil.
Definition: ModbusMaster.h:240
static const uint8_t ku8MBInvalidSlaveID
ModbusMaster invalid response slave ID exception.
Definition: ModbusMaster.h:161
uint16_t _u16ReadQty
quantity of words to read
Definition: ModbusMaster.h:225
static const uint8_t ku8MaxBufferSize
size of response/transmit buffers
Definition: ModbusMaster.h:223
Stream * _serial
reference to serial port object
Definition: ModbusMaster.h:221
static const uint8_t ku8MBReadInputRegisters
Modbus function 0x04 Read Input Registers.
Definition: ModbusMaster.h:245
uint16_t _u16ResponseBuffer[ku8MaxBufferSize]
buffer to store Modbus slave response; read via GetResponseBuffer()
Definition: ModbusMaster.h:226
static const uint16_t ku16MBResponseTimeout
Modbus timeout [milliseconds].
Definition: ModbusMaster.h:252
uint16_t _u16WriteQty
quantity of words to write
Definition: ModbusMaster.h:228
uint16_t _u16ReadAddress
slave register from which to read
Definition: ModbusMaster.h:224
static const uint8_t ku8MBWriteMultipleCoils
Modbus function 0x0F Write Multiple Coils.
Definition: ModbusMaster.h:241
static const uint8_t ku8MBMaskWriteRegister
Modbus function 0x16 Mask Write Register.
Definition: ModbusMaster.h:248
static const uint8_t ku8MBSuccess
ModbusMaster success.
Definition: ModbusMaster.h:152
static const uint8_t ku8MBReadDiscreteInputs
Modbus function 0x02 Read Discrete Inputs.
Definition: ModbusMaster.h:239
uint16_t _u16TransmitBuffer[ku8MaxBufferSize]
buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer()
Definition: ModbusMaster.h:229
static const uint8_t ku8MBInvalidCRC
ModbusMaster invalid response CRC exception.
Definition: ModbusMaster.h:189
uint8_t _u8MBSlave
Modbus slave (1..255) initialized in begin()
Definition: ModbusMaster.h:222
static uint16_t crc16_update(uint16_t crc, uint8_t a)
Processor-independent CRC-16 calculation.
Definition: crc16.h:71
static const uint8_t ku8MBReadWriteMultipleRegisters
Modbus function 0x17 Read Write Multiple Registers.
Definition: ModbusMaster.h:249
static const uint8_t ku8MBReadCoils
Modbus function 0x01 Read Coils.
Definition: ModbusMaster.h:238

The documentation for this class was generated from the following files: