Hot questions for Using Transmission Control Protocol in modbus

Question:

I am using jamod library to connect to the modbus and i have connected to the modbus simulator and read the value successfully but i want to read the value in the real time.

My problem is i want to change the value in the textfield if the value is changed in the simulator.This is my code below

VBox vb = new VBox();
        vb.setAlignment(Pos.CENTER);
        TextField tf1 = new TextField();
        TextField tf2 = new TextField();
        TextField tf3 = new TextField();
        vb.getChildren().addAll(tf1,tf2,tf3);
        StackPane root = new StackPane();
        root.getChildren().add(vb);
        InetAddress inet = InetAddress.getLocalHost();
        TCPMasterConnection con = new TCPMasterConnection(inet);
        con.setPort(502);
        con.connect();
        ReadMultipleRegistersRequest req=new 
        ReadMultipleRegistersRequest(0,5);

        ModbusTCPTransaction trans = new ModbusTCPTransaction(con);
        trans.setRequest(req);


            trans.execute();
            ReadMultipleRegistersResponse res = 
(ReadMultipleRegistersResponse) trans.getResponse();
            tf1.setText(String.valueOf(res.getRegisterValue(0)));
            tf2.setText(String.valueOf(res.getRegisterValue(1)));
            tf3.setText(String.valueOf(res.getRegisterValue(2)));

Answer:

poll values

define a Runnable that will poll data

Runnable r = new Runnable(){

    @Override
    public void run(){
        //TODO: define abort criteria for boolean:isRunning
        while(isRunning){
            //TODO define int:pollDelay
            Thread.sleep(pollDelay);

            //here you poll for new results
            trans.setRequest(req);
            ReadMultipleRegistersResponse res = 
                (ReadMultipleRegistersResponse) trans.getResponse();
            tf1.setText(String.valueOf(res.getRegisterValue(0)));
            ...
        }
    }
}

then start the runnable instead of aquiring data only once

VBox vb = new VBox();
vb.setAlignment(Pos.CENTER);
TextField tf1 = new TextField();
...

ModbusTCPTransaction trans = new ModbusTCPTransaction(con);

Runnable r = new ... //see code above
new Thread(r).start(); //starts the polling

this code is neither compiling nor running, but it gives you hints on how to poll data continously...

Question:

i tried the modbus slave program from the jamod library.I can set a input register with:

spi.addInputRegister(new SimpleInputRegister(45));

i can set 3 input registers with:

spi.addInputRegister(new SimpleInputRegister(45));
spi.addInputRegister(new SimpleInputRegister(45));
spi.addInputRegister(new SimpleInputRegister(4563));

This will be the registers 0,1 and 2. How can i set this registers do register address 100,101,102? Do i have to add some fake registers?

greets Andreas


Answer:

You can create "fake" registers by adding registers in a loop. This won't create a hole in the Modbus map, so those "fake" registers will be usable by any masters and they will won't cause ILLEGAL ADDRESS EXCEPTION responses.

I have modified j2mod, which is a fork of jamod, so it supports sparse Modbus maps as of SVN revision 95. j2mod is also available on SourceForge.

Question:

I am trying to write code in Java for a simple SCADA/HMI to connect my computer to a PLC via Modbus TCP. I wrote the code to switch ON/OFF 5 coils on my PLC, but the application works very slow – when I press the button twice (which is the condition to swich ON/OFF the coil) the PLC takes 4-6 seconds to get the command. But I want it to work quickly.

In the code I wrote the main class, in which I establish the connection, and the thread class, in which I execute the ModBusTCPTransaction for each coil. I call the thread class as »Daemon« and start it in main class. But maybe this is not the approach that things should be done – maybe anyone can write down how usually tese type of SCADA/HMI systems are done/work, just in 2/3 sentences… Do I even need a deamon thread class…?

Here is my code

import java.net.*;
import java.io.*;
import net.wimpi.modbus.*;
import net.wimpi.modbus.msg.*;
import net.wimpi.modbus.io.*;
import net.wimpi.modbus.net.*;
import net.wimpi.modbus.util.*;
import java.awt.Color;
import java.awt.FlowLayout;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.Graphics;

// 1. daemon class
class NitCoil extends Thread {

    private WriteCoilRequest coil_req = null;
    private ModbusTCPTransaction trans = null;
    private int i;

    NitCoil(String s , int i) {
        super(s);
        this.i = i;
    }

    public void run(){
        try {
        while(true) {
            coil_req = new WriteCoilRequest(i, ModbusTest.coil_con[i]);
            trans = new ModbusTCPTransaction(ModbusTest.con);
            trans.setRequest(coil_req);
            trans.execute();
            this.sleep((int)(Math.random()*100));
        }
        } catch (Exception ex) {
            ex.printStackTrace();
    }
    }

}
//2. main class
public class ModbusTest {

    public static TCPMasterConnection con = null;
    public static boolean[] coil_con = {false,false,false,false,false};
    public static void main(String[] args) {

      try {

          /* Variables for storing the parameters */
          InetAddress addr = null; //the slave's address
          int port = Modbus.DEFAULT_PORT;
          int repeat = 1; //a loop for repeating the transaction

          //3. Setup the parameters
          if (args.length < 1) {
              System.exit(1);
          } else {
              try {
                  String astr = "192.168.0.25:502"; 
                  int idx = astr.indexOf(':');
                  {
                      port = Integer.parseInt(astr.substring(idx+1));
                      astr = astr.substring(0,idx);
                  }
                  addr = InetAddress.getByName(astr);
                  if (args.length == 1) {
                      repeat = Integer.parseInt(args[0]);
                  }
              } catch (Exception ex) {
                  ex.printStackTrace();
                  System.exit(1);
              }
          }

          //4. Open the connection
          con = new TCPMasterConnection(addr);
          con.setPort(port);
          con.connect();

          //5. defining frame, panel, button
          JFrame frame = new JFrame("JFrame Example");
          JPanel panel = new JPanel();
          panel.setLayout(new FlowLayout());
          JLabel label = new JLabel("This is a label!");

          //6. creating 5 buttons             
          JButton[] button = new JButton[5];

          for (int j = 0; j < 5; j++){
               final int temp = j;
               button[j] = new JButton(String.valueOf(j));

          //7. button
          button[j].setText("Switch ON light "+j);

          button[j].addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                 if (coil_con[temp] == true) 
                     coil_con[temp] = false; 
                    else
                     coil_con[temp] = true;
            }
            });
          };
          panel.add(label);
          panel.add(button[0]);
          panel.add(button[1]);
          panel.add(button[2]);
          panel.add(button[3]);
          panel.add(button[4]);

          //8. call of demon
          NitCoil n1 = new NitCoil("daemon1", 0);
          n1.setDaemon(true);
          n1.start();
          NitCoil n2 = new NitCoil("daemon2", 1);
          n2.setDaemon(true);
          n2.start();
          NitCoil n3 = new NitCoil("daemon3", 2);
          n3.setDaemon(true);
          n3.start();
          NitCoil n4 = new NitCoil("daemon4", 3);
          n4.setDaemon(true);
          n4.start();
          NitCoil n5 = new NitCoil("daemon5", 4);
          n5.setDaemon(true);
          n5.start();


          //9. Close the connection
          JButton buttonClose = new JButton();
          buttonClose.setText("disconnect");

          buttonClose.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                 ModbusTest.con.close();
            }
            }); 
          panel.add(buttonClose);  
          panel.setBackground(Color.green);

          frame.add(panel);
          frame.setSize(300, 300);
          frame.setLocationRelativeTo(null);
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setVisible(true);

      } catch (Exception ex) {
        ex.printStackTrace();
      }

    }  

}

Answer:

Have you looked at Wireshark to see what the response times are like? Maybe the device is slow to respond.

Also, the way you currently have this set up, you're continuously writing all five coils all the time, which is probably not ideal.

Since your coil addresses are contiguous you could also be using the WriteMultipleCoils function (0x0F) to write to all five coils in one request.