2015-02-07 73 views
0

我想用簡單的SCADA/HMI編寫Java代碼,通過Modbus TCP將我的電腦連接到PLC。我編寫了代碼來開啓/關閉PLC上的5個線圈,但應用程序工作非常緩慢 - 當我按下按鈕兩次(這是開關線圈的條件)時,PLC需要4-6秒才能獲得命令。但我希望它能夠快速工作。java Modbus TCP SCADA/HMI工作速度非常慢

在代碼中,我編寫了建立連接的主類和線程類,其中爲每個線圈執行ModBusTCPTransaction。我把這個線程類稱爲»守護進程«,並在主類中啓動它。但是,也許這不是應該完成的方法 - 也許任何人都可以寫下這樣的SCADA/HMI系統通常是完成/工作,只需2/3個句子......我是否還需要一個deamon線程類......?

這裏是我的代碼

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(); 
     } 

    } 

} 

回答

0

你看着Wireshark的,看響應時間是什麼樣的呢?也許該設備響應速度慢。另外,你現在有這樣的設置方式,你一直在寫所有五個線圈,這可能並不理想。

由於你的線圈地址是連續的,你也可以使用WriteMultipleCoils函數(0x0F)在一個請求中寫入所有五個線圈。

+0

我現在已經使用了函數WriteMultipleCoilsRequest,現在SCADA的工作速度非常快。現在我正在無限循環中執行事務(daemon theread) - 事務每隔100毫秒發生一次,或者通常這些類型的SCADA只執行一次事務 - 當我更改事件(按下一個按鈕)時。 ?持有寄存器,它們的交易是否在無限循環中連續執行,或者只有在發生更改時才執行(SCADA上的十進制值被更改)。 – taDEUS 2015-02-09 16:21:47

+0

您通常不會連續不斷地重複寫入相同的值。讀取值是另一回事......大多數工業協議沒有任何訂閱或未經請求的機制,因此使用輪詢。 – 2015-02-10 01:28:18

+0

什麼是實際»輪詢«,我一直在網上搜索,但沒有找到任何明確的解釋 - 輪詢是否意味着執行modbus事務..?那麼讀取價值是什麼 - 也用它來輪詢..? – taDEUS 2015-02-16 15:28:20