Monday 10 February 2014

Modbus Slave example

How to implement it

  1. Open Arduino 1.0.5 or higher and create a new sketch.
  2. Create a data array that shall be linked to the Modbus network. This data array should contain any data to be exchanged (for example, digital inputs, analog inputs, analog outputs or pulses to an stepper).
  3. Add "Modbus.ino" file with Sketch / add file. Until I do not creat the library, there is no other choice. :-(
  4. Push Ctrl+Shft+N to add another TAB to the project.
  5. Type this:
Modbus slave(1,0,0);

void setup() {
  slave.begin( 19200 );
}

void loop() {
  slave.poll( au16data, 16 );
}
This shall create an object called "slave" at node number 1 and shall start its serial at 19200 baud. Arduino defaults are 8N1. At the end of the loop() section, there must be a poll request and the data array linked to the poll.

How to debug it

Before connecting the Arduino to the real world, a good choice is to debug its application with a simulator. There are good simulators for Modbus like:
Though Modbus library does most of the Serial work, it's a serial port and serial ports feature several settings. These settings need to be looked carefully before any attempt.

For those not proficient with these things, I strongly recommend to read something like this.

The serial port should have the next settings:
  • baudrate (common baudrates are 1200, 2400, 4800, 9600, 19200, 38400, 57600 and 115200);
  • bits per byte (7 or 8);
  • bits at the end of the byte (1, 1.5 or 2);
  • parity (none, even or odd).
Apart from these, there are other questions such as: Which port is being used for this USB-to-serial adapter? Depending on the PC OS,

With QModbus, my example looks like this:


18 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Indeed function codes 3 and 4 share the same code. Function code 6 just writes a single register.
    You can make a try with QModbus. Tell me something!

    ReplyDelete
  3. Hi
    Today compiled code on Arduino Uno and I have a Max485. With your example I was able to read the example array and write to it with Qmodbus.
    I put something like

    if (au16data[0] == 1 )
    ledpin high
    else
    ledpin low

    and it turned off and on depending on what I wrote to register with Qmodbus. So far so good.

    I was able to read and write up to address 15. What if I want to write to address 34 (22h)? Or even address 40001?
    I am trying to make a slave that will return values (function code 4) on addresses from 10 to 34. And also return different values when I write 0 or 164h to address 0.
    Thank you for your knowledge

    ReplyDelete
    Replies
    1. Hi JKLMan,
      I welcome any comments.

      It could have been even easier. Something like:
      digitalWrite( ledpin, (au16data[0] == 1) );

      Regarding to your questions,

      "What if I want to write to address 34 (22h)?"

      You should need to expand au16data declaration and add 34 or more values to au16data. You shall find this at the beginning of the code. Then, just modify
      slave.poll( au16data, new_range );

      "Or even address 40001?"

      Be careful with this. Modbus registers use to start with 1, 2, 3 or 4 plus a 4 digit hexadecimal number. This library does not distinguish between registers. Some devices point to different values for 30001 and 40001. This depends on its implementation.
      Here address 40001 would read register 0 or 1, but don't try it with QModbus, because it works as this library.

      "I am trying to make a slave that will return values (function code 4) on addresses from 10 to 34. And also return different values when I write 0 or 164h to address 0."

      This may be a different Modbus implementation. I can consider this suggestion for future releases, but not now.

      Good Luck!

      Delete
  4. I have been trying to recreate your system using Qmodbus and the downloaded software from this site. I seem to be getting CRC errors which lead to exceptions (29) and CRCs displayed in red on Qmodbus. I have been using a Uno and Arduino IDEs 1.0, 1.0.1, and 1.5.4 on a Windows 7 64 bit laptop. Any thoughts on how to resolve this?
    Thanks

    ReplyDelete
  5. It's really difficult to answer you with so little information. Can you send me your sketch and some screenshots?

    ReplyDelete
    Replies
    1. I have worked on the interface and seemed to solve the exception problems however the code and Qmodbus aren't working together. I have confirmed that the hardware is working by having the arduino uno respond to a character typed in Putty on my Windows PC. I have been using a Xprotolab Portable Oscilloscope to confirm that QModbus sends a message but the Uno doesn't respond. I have been using the Slave code and the code download which you suggested on this site.

      Delete
    2. Chip,
      Before pushing anything, I try it with an Arduino Duemilianove and QModbus. Indeed this code has been shared at the Arduino Forum and was checked by several users. My code has been compiled with IDE 1.0.5 under Linux 64. A situation like your report doesn't fit into a platform or version problem. It may be because any addition to the code.
      Can you send me your code, please?

      Delete
  6. The code successfully Uploaded . But i am facing problem in getting responses. "DIdn.t receive any data from Slave. I have configure slave ID 3 to 1.

    ReplyDelete
    Replies
    1. This is commonly caused by a wrong setting in your Modbus Master software. It is making queries to a Modbus Slave at address 1 instead of using address 3, as set in this example.

      Delete
    2. that means code will not work if any different ID.

      Delete
    3. The code does work with any slave ID number, but the slave doesn't answer messages which aren't refered to it.

      Delete
  7. Dear suby,

    With your code i successfully Uploaded code. I can read analog values.I wanted to How to put data into your word in the code. As i understand au16data[1] is array . If i have floating value. How can put like low bye of word and higher byte of word in your code. Can you able put also some snap shot for checking output.

    ReplyDelete
  8. Try to split this floating value into 2 words:
    - the first word can be its integer part
    - the second word can be its decimal part multiplied by 1000.
    Something like this (it is not compiled!):

    int iWord1 = (int) floating_value;
    int iWord2 = (int) ((floating_value - (float) iWord1)*1000)

    ReplyDelete
  9. Hi i am getting an error why trying to compile the file..'Modbus does not name a type'..how y'all guys do it? sorry i'm quite new to arduino and modbus..thnks

    ReplyDelete
    Replies
    1. That's because you haven't included the Modbus module in your Arduino sketch.
      You declare an object that belongs to Modbus class, but I have no Modbus class in your project.

      Delete
  10. Hi Suby,
    great work.

    Im using the example above and try to access all 16 Registers by using QMod Cmd "01 03 00 00 00 10".
    Unfortunatly, I Receive an error "Slave threw exception 'Illegal data address' or function not implemented"

    If I'am using QMod Cmd "01 03 00 00 00 0f" all is working fine.

    Is that a Library or QMod Issue?


    ReplyDelete
    Replies
    1. Thanks, Helge!
      I'm afraid that there may be an issue with my Library regarding the number of registers. I shall correct it in its next release amongst a lot of other things: full documentation with Doxygen, full Modbus Master and examples for Master and Slave.
      Regards,

      Delete