SCADA/HMI communication via Modbus.

Hello.

Found really nice SCADA/HMI software, few limitations on free version but if, with your help my friends i figure out this Modbus system it really is worth for buying.

Here´s the link for the software: Winlog Lite: free SCADA software | SCADA free download.

Yesterday i tested it with two temp sensors attached to Arduino UNO and after many hours got it finally working. Sketch i used is here:
And original sketch was copied here: http://mango.serotoninsoftware.com/forum/posts/list/0/567.page#2721[/size][/size][/size]

#include <ModbusSlave.h>

//TMP36 Pin Variables
int temperaturePin = 2; //the analog pin the TMP36's Vout (sense) pin is connected to
int temperaturePin2 = 3; //the resolution is 10 mV / degree centigrade 
                        //(500 mV offset) to make negative temperatures an option
int temptest = 1 ;  
int temptest2 = 1 ;

//Arduino sketch example with 2 holding regs:
void setup()
{
	  /* Modbus setup example, the master must use the same COM parameters */
	  /* 115200 bps, 8N1, two-device network */
//	  regs[MB_REG0]=153;
//	  regs[MB_REG1]=456;

	  init_mb_slave(115200, 'n', 0);
}


void loop()
{
    /* This is all for the Modbus slave */
    start_mb_slave(MB_SLAVE, regs, MB_REGS);

    /* your code goes here */
 float temperature = getVoltage(temperaturePin);  //getting the voltage reading from the temperature sensor
 temperature = (((temperature * 5) * 100));          //converting from 10 mv per degree wit 500 mV offset
                                                  //to degrees ((volatge - 500mV) times 100)
 float temperature2 = getVoltage(temperaturePin2);
 temperature2 = (((temperature2 * 5) * 100));
 
// Serial.println(temperature);    
// Serial.println(regs[MB_REG0]);    //printing the result
// delay(100);       
temptest = (temperature);
regs[MB_REG0]=temptest;

temptest2 = (temperature2);
regs[MB_REG1]=temptest2;

    /* handle write event */
    if (written.num_regs) {
   ///     ....
	  written.num_regs=0;
    }
}  

/*
 * getVoltage() - returns the voltage on the analog input defined by
 * pin
 */
float getVoltage(int pin){
return (analogRead(pin) * .004882814); //converting from a 0 to 1024 digital range
                                        // to 0 to 5 volts (each 1 reading equals ~ 5 millivolts
}

Thing that i really don´t understand is those "regs[MB_REG0]=153; and regs[MB_REG1]=456;".. Are those REGS "memory locations" where i can save analog input readings, so MB_REG0 is temp sensor 1 and MB_REG1 is temp sensor 2 and so on? And what are those values 153 and 456?
Tried to add MB_REG2 but compiler said that MB_REG2 is not declared in this scope.

Winlog gate configuration i used addresses 3:0 for temp sensor 1 and 3:1 for temp sensor 2. Here is part of the Winlog manual for Modbus addressing and no matter how long i read and spell that text it doesn´t make any sense with those Arduino MB_REG addresses...

30011 : Holding register 0011 (16 bit).Obsolete

3:11 : Holding register 11 (16 bit).

3h:Bh : Holding register 11 (16 bit).

3h:10h:Bh : Holding register 11 (16 bit) with write function 10h instead of 6h.

40004 : Input register 0004 (16 bit).Obsolete

4:4 : Input register 4 (16 bit).

4h:4h : Input register 4 (16 bit).

7: Exception Status.

330011 : Holding register 0011 (32 bit float).Obsolete

33:11 : Holding register 11 (32 bit float).

21h:Bh : Holding register 11 (32 bit float).

440004 : Input register 0004 (32 bit float). Obsolete

44:4 : Input register 4 (32 bit float).

2Ch:4h : Input register 4 (32 bit float).

And yet again i spent allmost whole day at work to search information about Arduino Modbus configurations, addresses and everything but without any breakthrough which would cleared this thing in to my mind. So... If here is somebody Modbus <-> Arduino Expert, could you please give some links, hints, example sketches or anything what would clear this problem.

Hey I also don't understand ModBus Addresses in Winlog. Please help us! I'm also facing the same problem that I can't point the addresses in Winlog to arduino....

Hello.

Few days ago i finally found a solution. Actually it is very simple to commucate between Arduino and Winlog via Modbus.
I'm not saying that i fully understand this addressing system, but my guess is that the addresses you put to your Arduino sketch eg. You want to read analog values MB_REG1, MB_REG2, MB_REG3 etc. equals Winlog addresses 30000, 30001, 30002 etc. You get the point?

I also managed to make a sketch with two LM35 temp sensors and one led. Led status is controlled from Winlog analog output value cause in modbusSlave library doesn't support other function codes than 3,6 and 10. But if it works that way, i'm very happy. XD

And by the way... I'm using different modbusSlave library what i used fisrt time. And if you read carefully that "old" library there is said that it is example for reading two registers. So unless you don't modify that library code i think that it is not possible to add more than two registers to your Arduino sketch. With this "new" library i can have at least six registers, guess that there is possible to use max. number of registers which was 256... Wasn't it?

But if you or someone else need more help or examples from Arduino sketch or Winlog gate configuration, please feel free to ask...

Hey I would love if you may please explain me Configuration and Gate settings;

  1. Tell me which one to choose in configuration? There are 3 options; Modbus ASCII, Modbus RTU, Modbus RTU TCP, which one need to be selected.

  2. How many gates are required and which type (numeric I guess)??? I would really appreciate if you may please tell me detailed configuration of gates i.e. addressing, device entry in gates, min & max values, data types etc...

Sorry for inconvenience but please help :frowning:
Thanks...

The main problem that occurs in communication is I think the device number in sampling configuration of gate. So please if you may explain the gate's configuration details. Thanks!

Hello.

Sorry that i haven't been visited here lately and tomorrow i have lots of time so i can make step by step instructions how to make Arduino and Winlog communicate with each other.
But here's some "first aid" to your problem.

The protocol what you must use in your projects is ModBus RTU. And be sure that you have exactly same settings in Winlog options and Arduino sketch. I've used COM Port8, Baud rate:115200, Stop Bits:1, Data Bits:8, Parity:None and Register Format: Standard mode.
Read- and Write Timeout: 2000 ms and Query pause:50 ms.

In Arduino sketch Slave id. is set to 1 so when you make devices to your Winlog project your device number must be same than your Arduino Slave id.

Now because Arduino Modbus library uses ModBus functions 3,6 and 10 and Winlog supports only function 3 of those, you must use numeric gate for all your data what you want to read / write from / to Arduino.
Here's Arduino basic ModBus sketch:

#include <ModbusSlave.h>
/* create new mbs instance */
ModbusSlave mbs;

/* slave registers */
enum {
        MB_A1,        /* analogIn 1 */
        MB_A2,        /* analogIn 2 */
        MB_A3,        /* analogIn 3 */
        MB_A4,        /* analogIn 4 */
        MB_A5,        /* analogIn 5 */
        MB_6,         /* own test register*/
        MB_REGS=6       /* dummy register. using 0 offset to keep size of array */
};

int regs[MB_REGS];
unsigned long wdog = 0;         /* watchdog */
unsigned long tprev = 0;         /* previous time*/

void setup(){

  /* Modbus slave configuration parameters */
  const unsigned char SLAVE = 1;      /* slaveId */
  const long BAUD = 115200;             /* baud rate */
  const char PARITY = 'n';             /* n=none; e=even; o=odd */
  const char TXENPIN = 0;              /* output driver enable pin */

  /* configure msb with config settings */
  mbs.configure(SLAVE,BAUD,PARITY,TXENPIN);

}

void loop()
{
/* pass current register values to mbs */
  if(mbs.update(regs, MB_REGS))
  //wdog = millis();

  /* ADC reads are slow. sample every 5 seconds */
  //if ((millis() - wdog) > 5000)  {
    regs[MB_A1] = analogRead(A1); /* read input A1 */
    regs[MB_A2] = analogRead(A2); /* read input A2 */
    regs[MB_A3] = analogRead(A3); /* read input A3 */
    regs[MB_A4] = analogRead(A4); /* read input A4 */
    regs[MB_A5] = analogRead(A5); /* read input A5 */

  //}

}

So if you want to read analog input 1 with Winlog, use address 30000 or 3:0 in your Winlog numeric gate. Set sample to Always and sampling frequency to value how often you want to read that value. Eg. if frequency is set to 1 Winlog polls your address 3:0 every secon, if set to 2 it polls that address every other second and so on. So sampling frequency depends on what kind of information you are reading or writing. In room temperature measurements it isn't necessary to use 1 or even 5 second polling time, but that's my opinion. :smiley:

In gate configuration channel field you must use same channel where you configured ModBus RTU parameters and in device field your Arduino slave id. So maybe easiest way is to set channel number, device number and slave id. to 1.
Set Min. Max. and Start value to 0 so no limits or init. value is used. In data type use U_WORD if your Arduino measuring scale is between 0-65535 or use float if you think that your scale doesn't fit for that. ]:smiley:

In conversion fields Measured val.1 and Engineering val.1 set to 0 and Measured val.2 and Engineering val.2 set to something, eg 10000. If those 2nd values are equal, no scaling is done in Winlog.

Then save your gate configuration, make template and code and finally execute your project. Should work.

I don't promise but i try to make those instructions in tomorrow and attach that file to my next post. There will be example how to write analog value to Arduino and how to read individual bit states (digital inputs) to Winlog using numeric gate. Not saying that i am expert with this but at least it works with that way which i've made it. :stuck_out_tongue:

Hello.

Now i've made instructions how to make this Arduino Winlog system to work. These are just basic instructions how to make template, gates and channel and device configuration so hopefully this gives some basic knowledgement for your projects.

Here's Arduino sketch i've used in this project:

#include <ModbusSlave.h>

/* create new mbs instance */
ModbusSlave mbs;
int Ohjaus;
int ledPin = 7;
int OUT_TE0101;
int OUT_TE0102;
int OUT_XE0111;
int OUT_SP010;
int TI010;
int DigIn1;
int DigIn2 = 0;
int DigIn3 = 0;
int DigIn4 = 0;
int buttonPin = 2;
int buttonState;
int cnt;

/* slave registers */
enum {
        MB_TE0101,        /* analogIn 1 */
        MB_TE0102,        /* analogIn 2 */
        MB_XE0111,        /* analogIn 3 */
        MB_A4,            /* analogIn 4 */
        MB_TE0103,        /* analogIn 5 */
        MB_TS010,
        MB_SP010,
        MB_TI010,
        MB_STR,
        MB_REGS=100       /* dummy register. using 0 offset to keep size of array */
};

int regs[MB_REGS];
unsigned long wdog = 0;         /* watchdog */
unsigned long tprev = 0;         /* previous time*/

void setup(){

  /* Modbus slave configuration parameters */
  const unsigned char SLAVE = 1;        /* slaveId */
  const long BAUD = 115200;             /* baud rate */
  const char PARITY = 'n';              /* n=none; e=even; o=odd */
  const char TXENPIN = 0;               /* output driver enable pin */
  digitalWrite(ledPin, LOW);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);


  /* configure msb with config settings */
  mbs.configure(SLAVE,BAUD,PARITY,TXENPIN);
}

void loop()
{
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);
/* pass current register values to mbs */
  if(mbs.update(regs, MB_REGS))
  //wdog = millis();
if (buttonState == HIGH){
  DigIn1 = 1;}

else{
  DigIn1 = 0;}
  /* ADC reads are slow. sample every 5 seconds */
  //if ((millis() - wdog) > sampleTime)  {
    regs[MB_TE0101] = analogRead(A1); /* read input A1, temp sensor 1 */
    regs[MB_TE0102] = analogRead(A2); /* read input A2, temp sensor 2 */
    regs[MB_XE0111] = analogRead(A3); /* read input A3, light sensor */
    regs[MB_A4] = analogRead(A4);     /* read input A4 */
    regs[MB_TE0103] = analogRead(A5); /* read input A5, temp sensor 3 */
    Ohjaus = regs[MB_TS010];          /* temperature control bit */
    OUT_SP010 = regs[MB_SP010];       /* temperature setpoint */
    regs[MB_TI010] = (analogRead(A1) + analogRead(A2)) / 2;   /* two temp sensor average reading to Winlog*/
    regs[MB_STR] = (DigIn1 + DigIn2 + DigIn3 + DigIn4);       /* Arduino digital inputs */
    TI010 = (analogRead(A1) + analogRead(A2)) / 2;        /* two temp sensor average reading to Arduino*/    



  //}

if(Ohjaus == 1 && TI010 < OUT_SP010 ){  
  digitalWrite(ledPin, HIGH);}              /* temp control on if temp lower than setpoint and cntrl bit is 1 */
if(Ohjaus == 0 || Ohjaus == 1 && (TI010 + 0.5) > OUT_SP010 ){
  digitalWrite(ledPin, LOW);}              /* temp control off if temp higher than setpoint + hysteresis and cntrl bit is 1, or cntrl bit is 0 */

}

ArduinoWinlog.rar (1.15 MB)

These lines in ur program creates problems:

  1. ModbusSlave mbs;
  2. mbs.configure(SLAVE,BAUD,PARITY,TXENPIN);
  3. if(mbs.update(regs, MB_REGS)); etc

Tell me if there is anything else that need to be copied to the sketch folder.

Thank you for responding me. I was busy so couldn't get back here for a while. :slight_smile:

could please somevone tell me what is wrong with those codes besause on the boton last line from the first code the written its says that is wrong? is this the full code or just a bit?

Brilliant contribution

usmanktg:
Brilliant contribution

You saying this is briliant, does this work for you? Have you tried using scada software with your arduino?

Just for anyone coming past this. I have managed to use my arduino with factory talk view, wonderware intouch and wintr. Using kepserver as the middle man.