1. 程式人生 > 程式設計 >使用Idea簡單快速搭建springcloud專案的圖文教程

使用Idea簡單快速搭建springcloud專案的圖文教程

部落格園Logo
首頁
新聞
博問
專區
快閃記憶體
班級

程式碼改變世界
搜尋
註冊
登入
返回主頁
八卦程式
程式改變生活
部落格園
首頁
新隨筆
聯絡
訂閱
管理
使用Modbus4J進行RTU模式串列埠通訊

Modus協議是由MODICON(現為施耐德電氣公司的一個品牌)在1979年開發的,是全球第一個真正用於工業現場的匯流排協議,應用非常廣泛,可謂大名鼎鼎。

理論性的東西就不多介紹了,推薦一本書《Modbus軟體開發實戰指南》,楊更更著,寫得非常好,從理論到實戰,手把手教你玩轉Modbus,不過程式碼實戰部分使用的是C#,筆者沒練過這項武功,還是看一下Java中怎麼應用吧,網上資料多用Modbus4J,就選它了。

Modbus4J原始碼:https://github.com/infiniteautomation/modbus4j

Modbus4J沒有提供底層串列埠驅動,因此需要先掌握一些Java串列埠程式設計的能力,快速入門可以參考筆者之前寫的《Java串列埠程式設計例子》這篇文章,本文就是在此基礎上進行的,也應用了其中的串列埠程式設計工具類程式碼。

建立專案
新建modbus4j專案,如下圖所示:

原始碼地址:https://github.com/wu-boy/modbus4j.git

測試步驟
實現底層串列埠驅動

Modbus4J沒有提供底層串列埠驅動,因此使用串列埠工具類SerialPortUtils來開啟和關閉串列埠,程式碼如下:

public class SerialPortUtils {

private static Logger log = LoggerFactory.getLogger(SerialPortUtils.class);

/**
 * 打卡串列埠
 * @param portName 串列埠名
 * @param baudRate 波特率
 * @param dataBits 資料位
 * @param stopBits 停止位
 * @param parity 校驗位
 * @return 串列埠物件
 */
public static SerialPort open(String portName, Integer baudRate, Integer dataBits,
                              Integer stopBits, Integer parity) {
    SerialPort result = null;
    try {
        // 通過埠名識別埠
        CommPortIdentifier identifier = CommPortIdentifier.getPortIdentifier(portName);
        // 開啟埠,並給埠名字和一個timeout(開啟操作的超時時間)
        CommPort commPort = identifier.open(portName, 2000);
        // 判斷是不是串列埠
        if (commPort instanceof SerialPort) {
            result = (SerialPort) commPort;
            // 設定一下串列埠的波特率等引數
            result.setSerialPortParams(baudRate, dataBits, stopBits, parity);
            log.info("開啟串列埠{}成功", portName);
        }else{
            log.info("{}不是串列埠", portName);
        }
    } catch (Exception e) {
        log.error("開啟串列埠{}錯誤", portName, e);
    }
    return result;
}

/**
 * 關閉串列埠
 * @param serialPort
 */
public static void close(SerialPort serialPort) {
    if (serialPort != null) {
        serialPort.close();
        log.warn("串列埠{}關閉", serialPort.getName());
    }
}

}
實現Modbus4J串列埠包裝器介面

Modbus4J提供了串列埠包裝器介面,但是沒有提供實現,因此自己新建一個實現類SerialPortWrapperImpl,作用是為Modbus4J提供串列埠物件SerialPort和操作串列埠的方法,例如開啟/關閉串列埠,獲取串列埠輸入/輸出流等,核心程式碼如下:

模擬從站裝置

RtuSlaveTest類模擬了一個地址為1的從站裝置,使用串列埠“COM2“(請提前使用虛擬串列埠軟體Virtual Serial Port Driver模擬出來COM1和COM2串列埠),通過ModbusFactory建立RtuSlave,然後模擬線圈狀態、離散輸入狀態、保持暫存器和輸入暫存器的資料,程式碼中有詳細註釋,程式碼如下:

public class RtuSlaveTest {

public static void main(String[] args) {
    createRtuSlave();
}

public static void createRtuSlave(){
    // 設定串列埠引數,串列埠是COM2,波特率是9600
    SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl("COM2", 9600,
            SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, 0, 0);

    // Modbus工廠,可以建立RTU、TCP等不同型別的Master和Slave
    ModbusFactory modbusFactory = new ModbusFactory();

    final ModbusSlaveSet slave = modbusFactory.createRtuSlave(wrapper);

    // 這玩意網上有人叫做過程影像區,其實就是暫存器
    // 暫存器裡可以設定線圈狀態、離散輸入狀態、保持暫存器和輸入暫存器
    // 這裡設定了從站裝置ID是1
    BasicProcessImage processImage = new BasicProcessImage(1);
    processImage.setInvalidAddressValue(Short.MIN_VALUE);
    slave.addProcessImage(processImage);

    // 新增監聽器,監聽slave線圈狀態和保持暫存器的寫入
    processImage.addListener(new MyProcessImageListener());

    setCoil(processImage);
    setInput(processImage);
    setHoldingRegister(processImage);
    setInputRegister(processImage);

    // 開啟執行緒啟動從站裝置
    new Thread(() -> {
        try {
            slave.start();
        }
        catch (ModbusInitException e) {
            e.printStackTrace();
        }
    }).start();

    /*new Timer().schedule(new TimerTask() {
        @Override
        public void run() {
            // 間隔1秒修改從站裝置1的保持暫存器資料
            updateHoldingRegister(slave.getProcessImage(1));
        }
    }, 1000, 1000);*/
}

private static void setCoil(ProcessImage processImage){
    // 模擬線圈狀態
    processImage.setCoil(0, true);
    processImage.setCoil(1, false);
    processImage.setCoil(2, true);
}

private static void setInput(ProcessImage processImage){
    // 模擬離散輸入狀態
    processImage.setInput(0, false);
    processImage.setInput(1, true);
    processImage.setInput(2, false);
}

private static void setHoldingRegister(ProcessImage processImage){
    // 模擬保持暫存器的值
    processImage.setHoldingRegister(0,(short) 11);
    processImage.setHoldingRegister(1,(short) 22);
    processImage.setHoldingRegister(2,(short) 33);
}

private static void updateHoldingRegister(ProcessImage processImage){
    // 模擬修改保持暫存器的值
    processImage.setHoldingRegister(0, (short) RandomUtil.randomInt(0, 100));
    processImage.setHoldingRegister(1,(short) RandomUtil.randomInt(0, 100));
    processImage.setHoldingRegister(2,(short) RandomUtil.randomInt(0, 100));
}

private static void setInputRegister(ProcessImage processImage){
    // 模擬輸入暫存器的值
    processImage.setInputRegister(0,(short) 44);
    processImage.setInputRegister(1,(short) 55);
    processImage.setInputRegister(2,(short) 66);
}

}
使用Modbus Poll測試模擬的從站裝置

Modbus Poll和Modbus Slave分別是主站裝置模擬工具和從站裝置模擬工具,是Modbus開發最常用的兩個測試軟體,下載地址:https://www.modbustools.com/

網上最近出現了一個國產軟體Mthings,能夠同時支援模擬主從機功能,據說功能強大還有使用手冊,免安裝免費使用!筆者由於參考了《Modbus軟體開發實戰指南》這本書,就沒使用Mthings,有興趣的同學可以試用。

設定連線引數
下載安裝後,開啟連線引數進行設定,如下圖所示:

RtuSlaveTest類使用了串列埠COM2來模擬從站裝置,因此這裡選擇COM1,選擇RTU模式,點選OK。

定義讀寫規則
選擇選單【Setup】->【Read/Write Definition…】,如下圖所示:

設定從站裝置地址為1,功能碼03是讀取保持暫存器資料,暫存器地址為0,數量為3,因為RtuSlaveTest程式中模擬了3個數據,點選OK,如下圖所示:

可以看到讀取到了RtuSlaveTest程式中模擬的3個暫存器的資料,注意別忘了先啟動RtuSlaveTest程式!

選擇不同的功能碼就可以讀取不同的資料,01讀取線圈狀態,02讀取離散輸入狀態,03讀取保持暫存器,04讀取輸入暫存器。

模擬主站裝置

實際開發中可能更多的是開發主站裝置程式,RtuMasterTest程式碼如下:

public class RtuMasterTest {

public static void main(String[] args) throws Exception{
    createRtuMaster();
}

private static void createRtuMaster() throws Exception{
    // 設定串列埠引數,串列埠是COM1,波特率是9600
    SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl("COM1", 9600,
            SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, 0, 0);
    ModbusFactory modbusFactory = new ModbusFactory();
    ModbusMaster master = modbusFactory.createRtuMaster(wrapper);
    master.init();

    // 從站裝置ID是1
    int slaveId = 1;

    // 讀取保持暫存器
    readHoldingRegisters(master, slaveId, 0, 3);
    // 將地址為0的保持暫存器資料修改為0
    writeRegister(master, slaveId, 0, 0);
    // 再讀取保持暫存器
    readHoldingRegisters(master, slaveId, 0, 3);
}

private static void readHoldingRegisters(ModbusMaster master, int slaveId, int start, int len) throws Exception{
    ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, start, len);
    ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.send(request);
    if (response.isException()){
        System.out.println("讀取保持暫存器錯誤,錯誤資訊是" + response.getExceptionMessage());
    }else {
        System.out.println("讀取保持暫存器=" + Arrays.toString(response.getShortData()));
    }
}

private static void writeRegister(ModbusMaster master, int slaveId, int offset, int value) throws Exception{
    WriteRegisterRequest request = new WriteRegisterRequest(slaveId, offset, value);
    WriteRegisterResponse response = (WriteRegisterResponse) master.send(request);
    if (response.isException()){
        System.out.println("寫保持暫存器錯誤,錯誤資訊是" + response.getExceptionMessage());
    }else{
        System.out.println("寫保持暫存器成功");
    }
}

}
先啟動RtuSlaveTest從站裝置模擬程式,再啟動RtuMasterTest主站裝置模擬程式,可以看到雙方控制檯均有預期輸出,RtuMasterTest能夠讀寫RtuSlaveTest中的資料。

參考資料
1、初探ModBus4j簡單使用指南
2、使用java的modbus4j的Rtu方式獲取監測資料
3、Modbus java slave app

分類: Java
標籤: Modbus
好文要頂 關注我 收藏該文
八卦程式
關注 - 0
粉絲 - 0
+加關注
1 0
« 上一篇: Java串列埠程式設計例子
posted @ 2021-01-04 21:37 八卦程式 閱讀(49) 評論(1) 編輯 收藏

評論列表
#1樓 2021-01-04 23:50 TYR
有使用netty+rxtx實現的經驗嗎?我目前用這種方式。
後期想用jssc替換掉,因為netty實現,程式碼提示過期。。。
支援(0) 反對(0)
重新整理評論重新整理頁面返回頂部
登入後才能發表評論,立即 登入 或 註冊, 訪問 網站首頁
【推薦】News: 大型組態、工控、模擬、CADGIS 50萬行VC++原始碼免費下載
【推薦】有你助力,更好為你——部落格園使用者消費觀調查,附帶小驚喜!
【推薦】AWS攜手部落格園為開發者送福利,註冊立享12個月免費套餐
【推薦】七牛雲新老使用者同享 1 分錢搶 CDN 1TB流量大禮包!
【推薦】了不起的開發者,擋不住的華為,園子裡的品牌專區
【推薦】未知數的距離,毫秒間的傳遞,聲網與你實時互動
【推薦】新一代 NoSQL 資料庫,Aerospike專區新鮮入駐

相關博文:
· modbus4j中使用modbustcp/ip和modbusrtuovertcp/ip模式
· modbus-RTU-crc16——c語言
· 西門子1200與陀螺儀和稱重感測器的RTU輪詢通訊
· ArrayList實現原理(JDK1.8)
· 十分鐘掌握Pandas(上)——來自官網API
» 更多推薦…

最新 IT 新聞:
· 蛋殼之後,房企們能否成為長租公寓的“解藥”?
· 高通驍龍480釋出:採用8nm工藝 處理器效能相比上一代翻倍
· 第九城市股價漲逾50%觸發熔斷,公告稱將開展數字貨幣業務
· 不造整車造部件 華為駕車向何方?
· NASA回顧2020年在國際空間站上進行的關鍵實驗
» 更多新聞…
公告
暱稱: 八卦程式
園齡: 2年6個月
粉絲: 0
關注: 0
+加關注
< 2021年1月 >
日 一 二 三 四 五 六
27 28 29 30 31 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 1 2 3 4 5 6
搜尋

找找看

谷歌搜尋
我的標籤
Modbus(1)
串列埠程式設計(1)
隨筆分類
Java(2)
隨筆檔案
2021年1月(2)
最新評論

  1. Re:使用Modbus4J進行RTU模式串列埠通訊
    有使用netty+rxtx實現的經驗嗎?我目前用這種方式。
    後期想用jssc替換掉,因為netty實現,程式碼提示過期。。。
    –TYR
    閱讀排行榜
  2. 使用Modbus4J進行RTU模式串列埠通訊(49)
  3. Java串列埠程式設計例子(7)
    評論排行榜
  4. 使用Modbus4J進行RTU模式串列埠通訊(1)
    推薦排行榜
  5. 使用Modbus4J進行RTU模式串列埠通訊(1)
    Copyright © 2021 八卦程式
    Powered by .NET 5.0 on Kubernetes