Modbus RTU with the Bmini shield

From Biemme Italia Wiki
Jump to: navigation, search

Contents

Introduction

The BMini shield has a RS485 transceiver (MAX1487 datasheet) and it supports modbus RTU communication. You have to download the library, configure it and you are ready to go!

If you were looking for the BminiIO library, there exist a wiki page on that topic.

Prerequisites

We suppose that you are already familiar with Arduino statements, Arduino IDE, and how Arduino MCU works in general. In case you are not, please refer to Arduino Getting Started tutorial or any good Arduino book. All the examples that we will present, are tested with Arduino 1.0.1.

Library download and installation

The Arduino library that you can use for managing modbus requests is simple-modbus. There exist two versions, one for Slave and the other for Master devices. Select the one you need depending on the function your device will have in the project architecture.

The versions we use in the examples are:

As with any other Arduino libraries, you can place it under the libraries directory of the Arduino installation. In case you are not familiar with that or you are not able to identify the correct directory, please take a look at this brief tutorial that explains where Arduino libraries must be placed.

Initialization

In order to use the library, you have to include the header file in the sketch and declare an array that will store the values of the registers (for slave devices). The code might be the following:

#include "SimpleModbusSlave.h"
enum
{
  // just add or remove registers and your good to go...
  // The first register starts at address 0
  ADC0,
  ADC1,
  ADC2,
  ADC3,
  LED_STATE,
  BUTTON_STATE,
  TOTAL_ERRORS,
  // leave this one
  TOTAL_REGS_SIZE
  // total number of registers for function 3 and 16 share the same register array
};
 
unsigned int holdingRegs[TOTAL_REGS_SIZE];

where you can customize the enum with as many registers as you need (for the maximum value please refer to the library wiki). Use

#include "SimpleModbusMaster.h"

for master devices.

The previous statements must be at the top of the Arduino sketch. Indeed, add this library initialization call in the setup section:

void setup(){
  // modbus RTU library initialization for slave devices
  modbus_configure(BAUDRATE, NODE_ID, ENABLE_PIN, TOTAL_REGS_SIZE);
}

where you have to specify:

  • the BAUDRATE: many rates are supported. However, please check the baudrate of your master node and the maximum baudrate allowed by the MAX1487 transceiver. Master and slave devices must have the same baudrate.
  • the NODE_ID of the slave device. Maximum value supported is 128.
  • the Arduino ENABLE_PIN: for ARDUINO MINI is 13, for ARDUINO ETHERNET is 9 and for ARDUINO UNO is 9
  • TOTAL_REGS_SIZE, that is the total number of registers

For master devices:

void setup(){
  // modbus RTU library initialization for master devices
  modbus_configure(BAUDRATE, timeout, polling, retry_count, ENABLE_PIN, packets, TOTAL_NO_OF_PACKETS);
}

Modbus RTU slave through RS485

J3 connector for RS485 modbus communication. See BMini PCB Component Layout for details.

The connector that is used for modbus communication is the J3. Please make sure that the GND of the master device is connected to the GND of the BMini shield.

The following code snippet will create a slave modbus node with NODE_ID 1. It will store all the digital inputs states into the modbus holding register in such a way a master can remotely get these values and acts accordingly. The enumeration are inserted in this example but not used. You can use it if you need to access the holding register by using names instead of numbers, i.e., writing for instance holdingRegs[DIGIN0] instead of holdingRegs[0].

#include "SimpleModbusSlave.h"
 
enum 
{     
  // The first register starts at address 0
  DIGIN0,     
  DIGIN1,        
  DIGIN2,
  DIGIN3,
  TOTAL_ERRORS,
  // leave this one
  TOTAL_REGS_SIZE 
  // total number of registers for function 3 and 16 share the same register array
};
 
//array that contains the registers
unsigned int holdingRegs[TOTAL_REGS_SIZE];
 
void setup(){
 
  //modbus initialization: baudrate, node_id, enable_pin and total number of registers
  modbus_configure(38400, 1, 13, TOTAL_REGS_SIZE);
 
}
 
int i;
void loop(){
 
  //modbus registers updates
  holdingRegs[TOTAL_ERRORS] = modbus_update_regs(holdingRegs);
 
  for(i=1; i < 5; i++){
    //store the digital input states into the holding registers
    holdingRegs[i-1] = get_inputs(i);
  }
 
}

Troubleshooting

  • Managing slow I/O external modules together with modbus RTU library should be properly coded. In fact, blocking requests to I/O modules might alter the time needed by the Arduino in order to reply to modbus call generating timeouts in the master node. A straightforward solution might be to architecture your projects with non blocking statements.

Complete examples

Slave device

#include "SimpleModbusSlave.h"
#include "BminiIO.h"
 
enum 
{     
  // just add or remove registers and your good to go...
  // The first register starts at address 0
  ADC0,     
  ADC1,        
  ADC2,
  ADC3,
  ADC4,
  ADC5,  
  LED_STATE,
  BUTTON_STATE,
  TOTAL_ERRORS,
  // leave this one
  TOTAL_REGS_SIZE 
  // total number of registers for function 3 and 16 share the same register array
};
 
unsigned int holdingRegs[TOTAL_REGS_SIZE];
int i,j=0;
 
void setup(){
	//initialize the BMini library for I/O
	bmini_init();
 
	//configure the modbus slave node: baudrate, node_id, enable_pin and total number of registers
	modbus_configure(38400, 1, 13, TOTAL_REGS_SIZE);
 
}
 
void loop(){
 
  holdingRegs[TOTAL_ERRORS] = modbus_update_regs(holdingRegs);
 
  //when a digital input goes to HIGH, the corresponding relay goes to HIGH
  for(i=1; i < 5; i++){
    if (get_inputs(i)==1){
      relay(i,HIGH);
    }else{
      relay(i,LOW);
    }
 
  }
 
  //set pwm: connect them to leds for instance
  pwm(1,j);
  pwm(2,j);
 
  //store one analog value and one pwm value into the first two registers
  holdingRegs[ADC0] = analogReadPin(1);
  holdingRegs[ADC1] = j;    
 
  j+=5;
  if (j>255){
    j=0;
  }
 
}

Master device

Will be published soon.

Hacking

The BMini shield has a LED for the modbus communication. If you are using the Arduino Mini 05 board, you can enable it by hacking the SimpleModbus library source code (file SimpleModbusSlave.cpp). Just add a

digitalWrite(12, HIGH);

at the beginning of the sendPacket function and a

digitalWrite(12, LOW);

at the end of it.

Licensing

This documentation is licensed under the Creative Commons Attribution-ShareAlike License 3.0. Take a look at Simple-Modbus library web site for the licence.

Personal tools
Namespaces

Variants
Actions
Structure
Store