【物聯網篇】PHP通過Modbus Tcp實時獲取裝置資料

語言: CN / TW / HK

前言:

        最近接觸了一個關於PLC工控的小專案,大概場景是,對方一個茶葉工廠。已經通過各種裝置組成了自動化的工控系統。並且也讓我的一個朋友做了茶園監控和茶園天氣環境等的web頁面展示,但是還沒有工控裝置的資料顯示。

需求:

        工控裝置已經連線到了一臺作為上機位的電腦上,所以要獲取裝置資料。需要在同一區域網上,通過modbus tcp請求對方已經開放的埠。拿到資料儲存到資料庫,最後web介面只用按時間順序獲取資料庫的資料。

        因為訪問對方電腦需要他們提供授權,所以這裡演示就以modbus的除錯工具,以及後面PHP程式碼請求示例。

 

工具:

1.  Modbus Slave: 從機端模擬軟體,這裡測試可以把他作為服務端,PHP為客戶端就是取該機子的資料。

2.   Modbus Poll: 主機模擬器,用於測試和除錯Modbus從裝置,這裡測試也只是把他當做客戶端使用。

3.   ModScan32:  主機/從機模擬程式 ,以後介紹。

4.   MThings:  一個國產免費軟體, 既可以模擬主機裝置 又可以模擬從機裝置,以後介紹。

以上軟體,可以掃描下面二維碼,輸入“modbus模擬” 獲取地址。

 

工具操作:

一.  Modbus Slave

1. 建立TCP/IP連線。

(1). 點選connection->connection,彈出引數視窗,可以按下面確認。

(2). 配置函式,點選setup->slave definition,彈出引數視窗,預設OK就可以。

(3). 修改某項資料的值,雙擊對應的框,彈出後修改OK就可以。

2. 從機引數說明:

(1). ID, 機子的裝置標識,是slave definition的slave ID

(2). F, 當前節點的函式碼,主機獲取程式碼獲取設定資料,需要指定的函式。

 

3. 檢視傳送和接收資料明細。

(1). 點選display,彈出面板。

4. 注意

modbus slave每次連線只能維持10分鐘,可能是沒有啟用。

 

一.  Modbus Poll

1.  通過Tcp獲取從機上的資料。

(1).  連線,點選connection->connection, 選擇TCP/IP。

(2). 修改為slave機子對應的IP地址和埠,點選儲存。

 

(3). 連線成功後,檢視讀寫定義,可以按指定slave配置修改。

(4). 連線失敗,Mbpoll面板會提示紅色字型。面板文字說明如下。

Tx = 4表示向主站傳送資料幀次數,圖中為4次; Error = 0表示通訊錯誤次數,圖中為0次; ID = 1表示模擬的Modbus子裝置的裝置地址,圖中地址為1;F = 03表示所使用的Modbus功能碼,圖中為03功能碼; SR = 1000ms表示掃描週期。紅字部分,表示當前的錯誤狀態,“No Connection”表示未連線狀態。

(5). 檢視讀寫資料。

 

PHP程式碼演示:

1. modbus類庫包下載。

composer require adduc/phpmodbus

2. 編寫請求 "03 Read Holding Registers"函式示例程式碼。

<?php
/**
* author: bqs
* desc: 請求modbus地址
* 公眾號: ZERO開發
*/

require_once 'vendor/adduc/phpmodbus/Phpmodbus/ModbusMaster.php';

	// Modbus master UDP
	$modbus = new ModbusMaster("127.0.0.1", "TCP");
	
	// Read multiple registers
	try {
		$recData = $modbus->readMultipleRegisters(1, 0, 5);
	}
	catch (Exception $e) {
		// Print error information if any
		echo $modbus;
		echo $e;
		exit;
	}
	
	var_dump($recData);die;
	
	// Print data in string format
	echo PhpType::bytes2string($recData);


?>

3. 環境要求。

1. PHP的LAMP環境已經搭建完畢
2. 可以不用配置虛擬域名,直接localhost訪問modubus_tcp_pro.php檔案
3. PHP版本最好是5.5,因為7.0以上執行會對類的建構函式命名報錯
4. PHP5.5擴充套件開啟了php_sockets

5. 執行成功後,返回資料,陣列的索引需要計算匹配modbus slave的地址名
6. 計算方式: (索引-1)/2

4. readMultipleRegisters說明。

引數1:unitId, modbus裝置ID,參考slave的slave ID
引數2:reference, 地址號,在裝置記憶體中,資料的地址引用,參考slave配置的地址
引數3:quantity,線圈,要去裝置中讀取的資料量,參考slave配置的quantity

 

5. 請求異常的幾種情況。

(1). socket_connect() failed

slave的連線停止了,需要重新開啟。

(2). Modbus response error code: 2 (ILLEGAL DATA ADDRESS)

從機裝置上資料的內容地址不對,可以根據slave的definition的引數,報錯可以檢視ModbusMaster類的responseCode方法。

請求的quantity數超過slave定義的quantity數量也會報內容地址錯誤,請求只能小於定義的數量。

6.  關於返回的陣列。

如果請求的是5個數據,phpmodbus會返回元素為10的陣列。如果是2個,則返回4個元素陣列,以此類推。

7. 關於返回陣列與slave的資料塊地址資料對應的方式。

8. 獲取裝置上指定資料塊的實際的資料。

(1). 列舉某資料塊下索引對應的標識。

// 資料庫裝置的資料描述
	$devicesDataBlock = [
		"0" => "weather",
		"1" => "water",
		"2" => "voice",
		"3" => "electric",
		"4" => "air"
	];

(2).  根據返回陣列的過濾出有用的索引,並匹配裝置資料標識。

實際的資料塊索引 = (返回陣列的索引-1)/2 

前提處於2的不能有餘數,所以只需要對結果做判斷,完整程式碼如下。

<?php
/**
* author: bqs
* desc: 請求modbus地址
* 公眾號: ZERO開發
*/

require_once 'vendor/adduc/phpmodbus/Phpmodbus/ModbusMaster.php';

	// Modbus master UDP
	$modbus = new ModbusMaster("127.0.0.1", "TCP");
	
	// Read multiple registers
	try {
		$recData = $modbus->readMultipleRegisters(1, 0, 5);
	}
	catch (Exception $e) {
		// Print error information if any
		echo $modbus;
		echo $e;
		exit;
	}
	
	// 資料庫裝置的資料描述
	$devicesDataBlock = [
		"0" => "weather",
		"1" => "water",
		"2" => "voice",
		"3" => "electric",
		"4" => "air"
	];
	
	$realData = [];
	
	foreach($recData as $key => $value) {
		$indexs = ($key-1)/2;
		if (($key-1)%2 == 0) {
			$realData[$devicesDataBlock[$indexs]] = $value;
		}
	}
	
	var_dump($realData);die;
	
	// Print data in string format
	echo PhpType::bytes2string($recData);
	
	// 00050000000601030000000A


?>

 

 

 

 

分享到: