Arduino Modbus RTU - Arduino controls HMI via RS485 [Github]

Hi everyone,

I'm newbie in this forum, this is my first post, if I have any mistake, please help me to fix it! Thanks!

I'm writing new Modbus RTU library for arduino (master and slave) based on SimpleModbus. The reason why I create new library because I've tried to use SimpleModbus to communicate with my HMI screen but it reported a lot of errors.

  • If I just send 1 packet, it's ok. But when I increase the packet, some errors appear.
  • The polling time to work with library is too long, if I have 10 packets, and polling time is 100ms => 1 packet will be updated after 1 second.

I've tested with this library and it work well.

As you can see in the video. the transfer rate is about 38 packets/second => cycle time is 1/38 ~ 26.32ms. So if I have 10 packets, update time for each packet is 263,2ms without any error.

Note that the program above runs with rtos, the cycle time (polling) is only 21ms, but the transfer rate is 38 packets/sec. If I use polling by arduino loop, with polling = 21ms, transfer rate is only 23 packets/sec

When using polling by arduino loop, transfer rate can be smaller than 23packets/sec depend on your program, if you run a lot of code, the transfer rate will be decreased. polling can be as short as 2ms, transfer rate will be 40packets/sec (not better than using rtos 21ms~38packets/sec)

The library is worked with both arduino AVR and ARM, it does not require two separate library.
I'm going to put Modbus master and slave in same library. It will be easier to use.

You can download library at github:

Youtube video:

Thanks you.

(and I'm sorry about my english :smiley: )

Example code:

#include "ModbusXT.h"

#define TIMEOUT 500   //Timeout for a failed packet. Timeout need to larger than polling
#define POLLING 20     //Wait time for next request . Unit in ms

#define BAUD        57600  
#define RETRIES     10    //How many time to re-request packet frome slave if request is failed
#define BYTE_FORMAT SERIAL_8E1
#define TxEnablePin 2   //Arduino pin to enable transmission

#define print(x)  Serial.print(x)
#define println(x) Serial.println(x)

//Name for register in regs[]
enum {
  button1,
  button2,
  button3,
  number_entry,
  password_entry,
  slider,
  total_packets,
  total_requests,
  total_failed,
  transfer_rate,
  transfer_delay,
  led_grn,
  led_blue,
  led_red,
  graph,
  TOTAL_REGS //=15
};

// This is the easiest way to create new packets
// Add as many as you want. TOTAL_NO_OF_PACKETS
// is automatically updated.
enum {
  PACKET1,
  PACKET2,
  NO_OF_PACKET  //=2
};

// Masters register array
uint16_t regs[TOTAL_REGS];

//Modbus packet
Packet packets[NO_OF_PACKET];

// Access individual packet parameter. Uncomment it if you know what you're doing
// packetPointer packet1 = &packets[PACKET1];
// packetPointer packet2 = &packets[PACKET2];

int graph_value = 0;
int slider_value = 0;

long sm,em,dm;

const uint8_t hmiID = 1;  //ID of HMI. The ID need to match, unless program will not work

uint16_t temp,num;

//Modbus Master class define
Modbus master;  

void setup()
{
  //Config packets and register
  master.configure(packets, NO_OF_PACKET, regs);

  //Config individual packet: (packet, ID, Function, Address, Number of register or data, start register in master register array)
  master.construct(&packets[PACKET1], hmiID, READ_HOLDING_REGISTERS, 0, 6, 0);

  master.construct(&packets[PACKET2], hmiID, PRESET_MULTIPLE_REGISTERS, 100, 9, 6);

  //Start Modbus
  master.begin(&Serial1, BAUD, BYTE_FORMAT, TIMEOUT, POLLING, RETRIES, TxEnablePin);

  Serial.begin(57600);  //debug on serial0

  println("Arduino Modbus Master");

  pinMode(13, OUTPUT);
}

void loop()
{
  master.update();  //polling

  sm = millis();

  graph_value++;  //update graph data, just increase from -32768 to 32767 (signed int)

  regs[total_packets] = NO_OF_PACKET;             //Total number of packet, here is 2
  regs[total_requests] = master.total_requests(); //Update all requested packets. Take a look on ModbusXT.h
  regs[total_failed] = master.total_failed();     //Update all failed packet
  regs[graph] = graph_value;  //Update graph value

  //If button is press, turn on HMI's LED
  for (uint8_t i=0;i<3;i++)
  {
    if (regs[i] == 1)      
      regs[i+11] = 1;
    else
      regs[i+11] = 0;
  }

  //If Led green is on (or button 0 = 1) turn on Led on arduino
  if (regs[led_grn])
    digitalWrite(13, HIGH);
  else
    digitalWrite(13, LOW);

  //Print number value on HMI
  if (num != regs[number_entry] )
  {
    num = regs[number_entry];
    print("Number: ");
    println(num);
  }

  //Print slider value on HMI
  if (slider_value != regs[slider] )
  {
    slider_value = regs[slider];
    print("Slider: ");
    println(slider_value);
  }

  //update transfer rate and transfer delay
  if ( (sm-dm) > 1000) //update 1s
  {
    dm = sm;
    regs[transfer_rate] = regs[total_requests] - temp;
    temp = regs[total_requests];
    regs[transfer_delay] = (unsigned int) ((NO_OF_PACKET*100000UL)/regs[transfer_rate]);
  }

}//end loop

and I'm sorry about my english

Why? It was perfect.

I've just uploaded library to github. you can download at 1st post! Thanks!

Why it ino file always error when compile

Why it ino file always error when compile

That is a useless question with your telling us which version of the IDE you are using, which Arduino you are compiling for, and what the errors are.

Hi ,

I am studying about Modbus recently . May I ask if Caddish or any one still following this topic ? Any update about "put Modbus master and slave in same library" ?

Best regards,
Sidney (Koalachi)

Hi,
Can someone help to communicate and control, "Arduino Mega2560" with "Wecon Levi700 HMI".
Thanks In Advance.

I can help you. Give me more specifics about your problem. Tell me what library do you use in your sketch, and what hardware are you using.

Hi sir I need this dop panel's display software and arduino connection diagram