Java接口開發及Modbus Slave仿真使用 Modbus TCP協議

一、ModbusTcp簡介
什麼是ModbusTcp?

/1、Modbus rtu和Modbus tcp兩個協議的本質都是MODBUS協議,都是靠MODBUS寄存器地址來交換數據;
/2、但所用的硬件接口不一樣,Modbus RTU一般採用串口RS232C或RS485/422,而Modbus TCP一般採用以太網口。
/3、現在市場上有很多協議轉換器,可以輕鬆的將這些不同的協議相互轉換 如:Intesisbox可以把modbus rtu轉換成Modbus tcp實際上Modbus協議包括ASCII、RTU、TCP。
/4、標準的Modicon控制器使用RS232C實現串行的Modbus。Modbus的ASCII、RTU協議規定了消息、數據的結構、命令和就答的方式,數據通訊採用Maser/Slave方式。 
/5、Modbus協議需要對數據進行校驗,串行協議中除有奇偶校驗外,ASCII模式採用LRC校驗,RTU模式採用16位CRC校驗.
/6、ModbusTCP模式沒有額外規定校驗,因爲TCP協議是一個面向連接的可靠協議。
/7、TCP和RTU協議非常類似,只要把RTU協議的兩個字節的校驗碼去掉,然後在RTU協議的開始加上5個0和一個6並通過TCP/IP網絡協議發送出去即可。

二、報文解析
本報文以電力逆變器設備的報文做解析
1、查詢指令
(發送)00 00 00 00 00 06[k1]  01[k2]  03[k3]  00[k4]  00[k5]  00[k6]  00[k7] 
[k1]起始字符組,長度,代表後面還有6個字節
[k2]設備地址
[k3]讀指令
[k4]寄存器地址高8位
[k5]寄存器地址低8位
[k6]寄存器數量高8位
[k7]寄存器數量低8位
(返回)00 00 00 00 00 25[k1]  01[k2]  03[k3]  22[k4] (自定義功能碼字節區)
[k1]起始字符組,長度,代表後面還有25個字節
[k2]設備地址
[k3]讀指令
[k4]表示接下來數據字節的長度

2、控制指令(啓動/停止)
(發送)00 00 00 00 00 06[k1]  01[k2]  06[k3]  00 12 00 01[k4]
[k1]起始字符組,長度,代表後面還有6個字節
[k2]設備地址
[k3]寫指令
[k4]00=停止/01=啓動
(返回)同上


3、逆變功率設定指令
(發送)00 00 00 00 00 06[k1]  01[k2]  06[k3]  00 13 00[k4]  00[k5] 
[k1]起始字符組,長度,代表後面還有6個字節
[k2]設備地址
[k3]寫指令
[k4]功率設定高字節
[k5]功率設定低字節
(返回)同上

 

請求報文案例:

主站向從站發送請求報文:01 03 00 01 00 02 95 CB

 

01代表設備地址 

03代表功能碼(讀取保存寄存器的值) 

00 01代表採集點對應的寄存器號

00 02代表讀取兩個連續寄存器的值

95 CB代表01 03 00 01 00 02計算多得的CRC校驗值 

從站向主站放回的數據報文:01 03 04 00 00 00 00 FA 33 

01代表設備地址 

03代表功能碼(讀取保存寄存器的值)

04代表設備返回的數據個數(單位爲字節)

00 00 00 00代表爲數據返回的連續兩個寄電器的數據

FA 33代表01 03 04 00 00 00 00計算所得的CRC校驗碼




1、ModbusTCP仿真
  ModbusSlave(軟件官方網站地址)是一個從站設備仿真軟件,它用於接收主設備的命令包,並回送數據包;可用於測試和調試Modbus主站設備,便於觀察Modbus通信過程中的各種報文。ModbusPoll及ModbusSlave支持ModbusRTU, ASCII,TCP/IP等協議。

  首先,瞭解MODBUS支持的部分功能代碼,以十進制表示,如下表所示。

代碼    中文名稱    英文名稱    位操作/字操作    操作數量
01    讀線圈狀態    READ COIL STATUS    位操作    單個或多個
02    讀離散輸入狀態    READ INPUT STATUS    位操作    單個或多個
03    讀保持寄存器    READ HOLDING REGISTER    字操作    單個或多個
04    讀輸入寄存器    READ INPUT REGISTER    字操作    單個或多個
05    寫線圈狀態    WRITE SINGLE COIL    位操作    單個
06    寫單個保持寄存器    WRITE SINGLE REGISTER    字操作    單個
15    寫多個線圈    WRITE MULTIPLE COIL    位操作    多個
16    寫多個保持寄存器    WRITE MULTIPLE REGISTER    字操作    多個
  參數設置: 
  點擊菜單“Setup”中“Slave Definition.. F2”進行參數設置,會彈出如下圖對話框



  其中: 
  (1)Slave ID:設備ID; 
  (2)Function:對應上表所對應的Modbus功能,例如本文所選用的“03 Holding Register…”,與下文Java代碼“見類ReadHoldingRegistersResponse ”所對應。 
  (3)Address:寄存器地址; 
  (4)Quantity:數量。

  打開ModbusSlave軟件,爲方便起見,本文采用默認的地址(localhost,與下文第二段代碼對應“見類ClientForTests ”),功能碼,寄存器數量,單擊Connection->connect,在彈出的窗口設置connection爲TCP/IP,端口Port設置爲30502,點擊OK,如下圖所示,從端配置完畢。



  注意: 
  (1)本文連接Connection採用Modbus TCP/IP協議; 
  (2)網絡地址爲本地地址,127.0.0.1; 
  (3)端口與下文第二段代碼“見類ClientForTests”中的地址和端口設置爲“30502”; 
  (4)選擇“Ignore Unit ID”,如果不選擇,測試程序返回空值。
--------------------- 


 /**
     * 讀保持寄存器上的內容
     *
     * @param ip        從站IP
     * @param port      modbus端口
     * @param start     起始地址偏移量
     * @param readLenth 待讀寄存器個數
     * @return
     */
    public static String modbusTCP(String ip, int port, int start, int readLenth) {
        ModbusFactory modbusFactory = new ModbusFactory();
        // 設備ModbusTCP的Ip與端口,如果不設定端口則默認爲502
        IpParameters params = new IpParameters();
        params.setHost("116.62.210.27");
//        設置端口,默認502
        if (502 != 15835) {
            params.setPort(15835);
        }
        ModbusMaster tcpMaster = null;
        tcpMaster = modbusFactory.createTcpMaster(params, true);
        try {
            tcpMaster.init();
            System.out.println("========初始化成功=======");
        } catch (Exception e) {
            return null;
        }
        ModbusRequest modbusRequest = null;
        try {
            //功能碼03   讀取保持寄存器的值
            modbusRequest = new ReadHoldingRegistersRequest(1, start, readLenth);
        } catch (Exception e) {
            e.printStackTrace();
        }
        ModbusResponse modbusResponse = null;
        try {
            modbusResponse = tcpMaster.send(modbusRequest);
        } catch (Exception e) {
            e.printStackTrace();
        }
        ByteQueue byteQueue = new ByteQueue(1024);
        modbusResponse.write(byteQueue);
        System.out.println("功能碼:" + modbusRequest.getFunctionCode());
        System.out.println("從站地址:" + modbusRequest.getSlaveId());
        System.out.println("收到的響應信息大小:" + byteQueue.size());
        System.out.println("收到的響應信息值:" + byteQueue);
        //數據解析
        Float fl = toBytes(String.valueOf(byteQueue));
        return fl.toString();
    }

//----------------------------------------------解析16進制數據
    public static Float toBytes(String s) {
        if (s.startsWith("["))
            s = s.substring(1);
        if (s.endsWith("]"))
            s = s.substring(0, s.length() - 1);
        String parts = s.replaceAll("[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……& amp;*()——+|{}【】‘;:”“’。,、?|-]", "");
        Float value = Float.intBitsToFloat(Integer.valueOf(parts.trim(), 16));
        System.out.println("value=================" + value);
        return value;


    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章