Arduino Modbus

Hello People,

I'm trying to use Modbus to send some information to the KepWare (OPC server).
and it's easy if i use variables type "int" or "char".

But i need to send one "int" and one string with 10 char.
I made some testes and using a holding register i can send just one char... Mb.R[0] = myString*;*
So do you know if is possible to send one complete string (10 char) to the kepware? like "ABCDEFGHIJ"
If not or if you know other way/protocol to send those two variables by Ethernet shield, please let me know.
Thanks,
*LC *

one char is 8 bits, one register is 16 bits. you need 5 registers for 10 chars.

The ModBus protocol does not support the transmission of strings but as Juraj wrote above you may store the contents of your string in several 16bit holding registers.

BTW: ModBus TCP is not the default type, if you just write ModBus people usually expect you to mean ModBus RTU.

So do you know if is possible to send one complete string (10 char) to the kepware? like "ABCDEFGHIJ"

Is the string length fixed? Do you control the software that receives this "string"? Is the Kepware a client or a server in the ModBus TCP terms?

If not or if you know other way/protocol to send those two variables by Ethernet shield, please let me know.

Probably the best known protocol today is HTTP. I think it's more important what other protocols your Kepware device understands. Unfortunately you forgot the link to that product's datasheet/manual.

Hello Guys,

Thanks for your comments and you are right, i need to share more details in order you have more information to evaluate better the options.

So, the Kepware is the master and the arduino is the slave.
There is the code that i'm using to some tests:

#include <SPI.h>
#include <Ethernet.h>
#include "Mudbus.h"

//uncomment if you want to see debug info
//#define DEBUG

Mudbus Mb;
//Function codes 1(read coils), 3(read registers), 5(write coil), 6(write register)
//signed int Mb.R[0 to 125] and bool Mb.C[0 to 128] MB_N_R MB_N_C
char myString[] = "ABCDEFGHIJ";
void setup()
{
uint8_t mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x51, 0x06 };
uint8_t ip[] = { 192, 168, 1, 10 };
uint8_t gateway[] = { 192, 168, 1, 1 };
uint8_t subnet[] = { 255, 255, 255, 0 };
Ethernet.begin(mac, ip, gateway, subnet);
//Avoid pins 4,10,11,12,13 when using ethernet shield
}

void loop()
{
//modbus TCP update
Mb.Run();
Mb.R[0] = 0x42;
Mb.R[1] = 0x43;
Mb.R[2] = 0x44;
Mb.R[3] = 0x45;
Mb.R[4] = 0x46;
Mb.R[5] = 0x47;
Mb.R[6] = 0x48;
Mb.R[7] = 0x49;
Mb.R[8] = 0x50;
Mb.R[9] = 0x51;

Mb.R[25] = analogRead(1);
Mb.R[26] = analogRead(2);
delay(20);

}

The Link to the Kepware is: KEPserverEX OT Connectivity Platform | PTC

My goal is share one string of 10 char like "ABCDEFGHIJ" with the Kepware.
As you are saying, if i use one register i can share one char, but nothing more... it works good if i share 1 int.

My test is to load in Hex one char in each register Mb.R[0...9] and then in the Kepware i say to read from 400001.10 (1 to 10) and i just read the first register... i already change many different ways on the Kepware and on the arduino and i didn't find one way to do this...

attached is one picture if it help...

If someone have new ideas or need need more information, i can provide it!

Thanks

Excuse me if I'm pedantic but in ModBus TCP there is no master and no slave but clients and servers. That's not that unimportant because in standard ModBus (RTU) you really can have just one master that controls all it's slaves but in ModBus TCP you can have several clients asking the same server although usually you have the same setup with just one client and several servers.

The Link to the Kepware is: KEPserverEX OT Connectivity Platform | PTC

Why do you want to communicate with this device in ModBus? I wasn't even able to find ModBus in the supported protocols but it speaks MQTT, SNMP and a lot of other protocols, all of them easier to use for string transmission than ModBus TCP.

#include "Mudbus.h"

Unfortunately your choice of library (you forgot the link to it: GitHub - luizcantoni/mudbus: Automatically exported from code.google.com/p/mudbus) is not the best. The quality is quite weak, no limit checks and the like, don't use this in a productive environment.

My goal is share one string of 10 char like "ABCDEFGHIJ" with the Kepware.

What will be the real content of this string? I'm quite sure you won't send the start of the alphabet to the KepserverEX.

As you are saying, if i use one register i can share one char, but nothing more... it works good if i share 1 int.

No, we say one register can hold two characters. But that doesn't help you much if the transported data is a real string.

My test is to load in Hex one char in each register Mb.R[0...9] and then in the Kepware i say to read from 400001.10 (1 to 10) and i just read the first register..

If you try to read register 40001 (register number 400001 does not exister, register numbers are 16bit) the mudbus library will probably freeze your Arduino because it will access any memory far outside the area that was allocated by the sketch. As I said, the library is quite low quality.

Please specify what you want to achieve and not how you think it should be achieved. What kind of data is the Arduino sensing? What will the KepserverEX do with that data?

Hi pylon,

you are right, was my mistake to write master and slave, so client and server is the right one.

I choose Modbus because i already use it for integers and it works good, and i was trying to use it again for strings... now you are make me change the plans... :wink:

Is clear that is not my goal to to send the alphabet to the kepware, but it's just one example...
In fact i need to send two integers (part counter) and two strings with the part number with 10 char. The data will be shared with SAP and managed by SAP.
But my doubts is to choose the best driver for the Kepware that could be compatible with arduino. And Modbus tcp i already know something and with integers is working good.... I just need to put this information on the Kepware, after is other person that will manage this information in SAP.

As i'm not very expert on Kepware, i fond this way to work with integers, but now i need something more (strings) and i y can do it without change the driver on the Kepware will be perfect, but if with your recommendations i fond something different but if work, i'm open to test and investigate more about it.

Do you think that it can be more easy using MQTT and SNMP i will go investigate. To be honest i don't know what is it, but i will investigate.

If you have other idea, please share in the topic, i will appreciate.

Let me thank you for you support.

LC

In fact i need to send two integers (part counter) and two strings with the part number with 10 char.

If the strings are of fixed length (10 characters) you may use the ModBus registers if that's the method you are already familiar with.

You can define the register number for every pair of characters and it will be the same as transferring a few more integers.

Yes, but it is not working at all...
at this moment i just can read one char, even if i declare two on the arduino...

Evan is i load just one char in each register, after in the kepware i'm not reach all the array. i just rad the char from each register in different tag's on the kepware....

Someone of you have other idea?

Thanks
LC

at this moment i just can read one char, even if i declare two on the arduino...

Post the code you're currently working with.

Evan is i load just one char in each register, after in the kepware i'm not reach all the array. i just rad the char from each register in different tag's on the kepware....

Sorry, I don't understand that. If you have one character in a register, the registers value is simply the ASCII value of that character. I don't see a problem.

0x42 is 'B' in the ASCII table.

Hi,

Yes, the conversions from ASCII and HEX are as you are saying.

There is the code:

#include <SPI.h>
#include <Ethernet.h>
#include "Mudbus.h"

//uncomment if you want to see debug info
//#define DEBUG

Mudbus Mb;
//Function codes 1(read coils), 3(read registers), 5(write coil), 6(write register)
//signed int Mb.R[0 to 125] and bool Mb.C[0 to 128] MB_N_R MB_N_C
char myString[] = "ABCDEFGHIJ";
void setup()
{
uint8_t mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x51, 0x06 };
uint8_t ip[] = { 192, 168, 1, 10 };
uint8_t gateway[] = { 192, 168, 1, 1 };
uint8_t subnet[] = { 255, 255, 255, 0 };
Ethernet.begin(mac, ip, gateway, subnet);
//Avoid pins 4,10,11,12,13 when using ethernet shield
}

void loop()
{
//modbus TCP update
Mb.Run();

Mb.R[0] = 0x41;
Mb.R[1] = 0x42;
Mb.R[2] = 0x43;
Mb.R[3] = 0x44;
Mb.R[4] = 0x45;
Mb.R[5] = 0x46;
Mb.R[6] = 0x47;
Mb.R[7] = 0x48;
Mb.R[8] = 0x49;
Mb.R[9] = 0x50;

Mb.R[25] = analogRead(1);
Mb.R[26] = analogRead(2);
delay(20);

}

I think that the problem could be with the Kepware too... Because the Kepware can't be read all registers as i'm thinking...

Maybe i'm doing something wrong and declaring one char in each register, and i'm creating the tag on Kepware as HR 400001.20L and thinking that Kepware will read from 400001 to 400020 on the low byte (first byte of the resgister) and it is just read the Register 400001.(1...20) and in fact it is just the register 400001 from 1 to 20 bytes and they are empty because in fact it have jus two bytes, the rest should stay empty.

Maybe it could work if i found one way to create one register with more them 2 bytes.... i'ts impossible i think...

the other solution could be find other way to create one tag on the Kepware that can really allow to ready the array from the 400001 to 400010 and allow concatenate all in one array....

i'm trying but without success....

Maybe i'm doing something wrong and declaring one char in each register, and i'm creating the tag on Kepware as HR 400001.20L and thinking that Kepware will read from 400001 to 400020 on the low byte (first byte of the resgister) and it is just read the Register 400001.(1...20) and in fact it is just the register 400001 from 1 to 20 bytes and they are empty because in fact it have jus two bytes, the rest should stay empty.

Don't expect us to understand the syntax of the kepware device. It looks to me that this command reads bits 1 to 20, because bytes would exactly be what you needed.

Maybe it could work if i found one way to create one register with more them 2 bytes.... i'ts impossible i think...

BTW: you shouldn't name your screenshots *.jpg when they are PNGs in fact.
Yes, because the ModBus standard defines registers to be 16 bits and there's not exception.

Hello pylon,

Thanks for your support.
In fact i found the solution... But i still with doubts... The only change in the code that i made was:

{Mb.R[0] = 0x4241;}
{Mb.R[1] = 0x4443;}
{Mb.R[2] = 0x4645;}
{Mb.R[3] = 0x5847;}
{Mb.R[4] = 0x5858;}

instead of:

Mb.R[0] = 0x4241;
Mb.R[1] = 0x4443;
Mb.R[2] = 0x4645;
Mb.R[3] = 0x5847;
Mb.R[4] = 0x5858;

and the result is what i was trying... for example "ABCDEFGXXX" in the same tag....

So, for me it's done, but if someone can explain me what is the difference between " {Mb.R[0] = 0x4241;} and "Mb.R[0] = 0x4241;" i will appreciate it.

Thanks a lot for your availability.
And as it is the goal of the forum, i'm sharing with you all my tests and results.

Thanks.

So, for me it's done, but if someone can explain me what is the difference between " {Mb.R[0] = 0x4241;} and "Mb.R[0] = 0x4241;" i will appreciate it.

Actually, there is none. The curly braces are absolutely not necessary.

Let me agree with you... in fact before (without braces) was not working, after i put the braces an it start working... and i keep like that....

Now you are saying that is the same.... now i remove the braces to test and it works too.... i'm confuse...

The important is that is working, but something was wrong.... maybe something during the compilation/transfer or something else... :confused: :confused: :confused:

Thanks