Browsed by
Tag: #RTU

MODBUS RTU M-Duino Ardbox

MODBUS RTU M-Duino Ardbox

In this post it is shown how to implement Modbus RTU (RS485/RS232) in M-Duinos and Ardbox PLCs. The library used is a modification of the SimpleModbus, which has been adapted to the internal configuration of Industrial Shields PLCs (SimpleModbus library for Industrial Shields PLCs).  Adapted libraries to Industrial Shields PLCs  are available here

 First the code for the Master is showed below.

#include <SoftwareSerial.h>
#include <SimpleModbusMasterSoftwareSerial.h>

#define ARDBOX
//#define MDUINO

#ifdef ARDBOX
#define SSerialRX 11 // RO //RS485 Receive pin
#define SSerialTX 10 // DI //RS485 Transmit pin
#define SSerialTxControl 7 // DE //RS485 Direction pin
#define GroundRE 4 // RE
#elif MDUINO
#define SSerialRX 11 // RO //RS485 Receive pin
#define SSerialTX 10 // DI //RS485 Transmit pin
#define SSerialTxControl 14 // DE //RS485 Direction pin
#define GroundRE 13 // RE
#endif

#define baud 9600
#define timeout 1000
#define polling 200 // the scan rate 
#define retry_count 10


int SSerialRX =11 ;// RO  //RS485 Receive pin
int SSerialTX=10; // DI  //RS485 Transmit pin
int  SSerialTxControl=7;  // DE  //RS485 Direction pin
int GroundRE=4 ; // RE
SoftwareSerial RS485Serial(SSerialRX, SSerialTX);

enum
{
PACKET1,
PACKET2,
PACKET3,
PACKET4,
TOTAL_NO_OF_PACKETS // leave this last entry
};

// Create an array of Packets to be configured
Packet packets[TOTAL_NO_OF_PACKETS];

// Masters register array
#define TOTAL_NO_OF_REGISTERS 4
unsigned int regs[TOTAL_NO_OF_REGISTERS];


void setup()
{
  Serial.begin(9600);
  pinMode(SSerialTxControl, OUTPUT);  
  pinMode(GroundRE, OUTPUT);
  digitalWrite(GroundRE,LOW);

  modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 100, 1, 0); 
  // parameters: packet/ID Slave/ function/ Modbus address/Total numbr of registers/position in the  'regs' array.
 modbus_construct(&packets[PACKET2], 1, PRESET_SINGLE_REGISTER, 110, 1, 1);
  modbus_construct(&packets[PACKET3], 1, READ_COIL_STATUS, 0, 1, 2);
   modbus_construct(&packets[PACKET4], 1, FORCE_MULTIPLE_COILS, 16, 1,3);
  modbus_configure(&RS485Serial, baud, SERIAL_8N1, timeout, polling, retry_count, SSerialTxControl, packets, TOTAL_NO_OF_PACKETS, regs);
}

void loop()
{
  modbus_update();

regs[1]=200; //(PACKET 2) The value 200 will be written to Holdin register 110.
regs[3]=1; //  (PACKET 4)The value 1 will be written to COIL 16.
Serial.print(regs[0]); //(PACKET 1) It is printed in Serial Monitor the value contained in Holding Register 100 of the slave.
Serial.print(regs[2]);  //(PACKET 3) It is printed in Serial Monitor the value contained in the Coil 0 of the slave.
delay(1000);

}

The code for a Modbus RTU Slave is the following.


#include <SoftwareSerial.h>
#include <SimpleModbusSlaveSoftwareSerial.h>

#define ARDBOX
//#define MDUINO

#ifdef ARDBOX
#define SSerialRX 11 // RO //RS485 Receive pin
#define SSerialTX 10 // DI //RS485 Transmit pin
#define SSerialTxControl 7 // DE //RS485 Direction pin
#define GroundRE 4 // RE
#elif MDUINO
#define SSerialRX 11 // RO //RS485 Receive pin
#define SSerialTX 10 // DI //RS485 Transmit pin
#define SSerialTxControl 14 // DE //RS485 Direction pin
#define GroundRE 13 // RE
#endif

SoftwareSerial RS485Serial(SSerialRX, SSerialTX);

#define  Q05 9  

// and at a glimpse informs you of your slaves register layout.

//////////////// registers of your slave ///////////////////
enum 
{     
  // just add or remove registers and your good to go...
  // The first register starts at address 0
  ADC_VAL,     
  PWM_VAL,        
  HOLDING_REGS_SIZE // leave this one
  // total number of registers for function 3 and 16 share the same register array
  // i.e. the same address space
};

unsigned int holdingRegs[HOLDING_REGS_SIZE]; // function 3 and 16 register array
////////////////////////////////////////////////////////////

void setup()
{

  pinMode(SSerialTxControl, OUTPUT);  
  pinMode(GroundRE, OUTPUT);
  

  digitalWrite(GroundRE,LOW);
  modbus_configure(&RS485Serial, 9600, SERIAL_8N2, 1, SSerialTxControl, HOLDING_REGS_SIZE, holdingRegs);

  // modbus_update_comms(baud, byteFormat, id) is not needed but allows for easy update of the
  // port variables and slave id dynamically in any function.
  modbus_update_comms(9600, SERIAL_8N2, 1);
  
  pinMode(Q05, OUTPUT);
}

void loop()
{
  modbus_update();
  
  holdingRegs[ADC_VAL] = analogRead(A0); // update data to be read by the master to adjust the PWM
  
  analogWrite(Q05, holdingRegs[PWM_VAL]>>2); // constrain adc value from the arduino master to 255
  
}

Contact us at industrialshields@industrialshields.com if you need more information.