【物联网篇】PHP通过Modbus Tcp实时获取设备数据

前言:

        最近接触了一个关于PLC工控的小项目,大概场景是,对方一个茶叶工厂。已经通过各种设备组成了自动化的工控系统。并且也让我的一个朋友做了茶园监控和茶园天气环境等的web页面展示,但是还没有工控设备的数据显示。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

需求:

        工控设备已经连接到了一台作为上机位的电脑上,所以要获取设备数据。需要在同一局域网上,通过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,弹出参数窗口,可以按下面确认。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

(2). 配置函数,点击setup->slave definition,弹出参数窗口,默认OK就可以。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

(3). 修改某项数据的值,双击对应的框,弹出后修改OK就可以。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

2. 从机参数说明。

(1). ID, 机子的设备标识,是slave definition的slave ID

(2). F, 当前节点的函数码,主机获取代码获取设置数据,需要指定的函数。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

 

3. 查看发送和接收数据明细。

(1). 点击display,弹出面板。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

4. 注意事项。

modbus slave每次连接只能维持10分钟,可能是没有激活。

 

一.  Modbus Poll

1.  通过Tcp获取从机上的数据。

(1).  连接,点击connection->connection, 选择TCP/IP。

(2). 修改为slave机子对应的IP地址和端口,点击保存。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

(3). 连接成功后,查看读写定义,可以按指定slave配置修改。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

(4). 连接失败,Mbpoll面板会提示红色字体。面板文字说明如下。

Tx = 4表示向主站发送数据帧次数,图中为4次; Error = 0表示通讯错误次数,图中为0次; ID = 1表示模拟的Modbus子设备的设备地址,图中地址为1;F = 03表示所使用的Modbus功能码,图中为03功能码; SR = 1000ms表示扫描周期。红字部分,表示当前的错误状态,“No Connection”表示未连接状态。

(5). 查看读写数据。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

 

PHP代码演示:

1. modbus类库包下载。

composer require adduc/phpmodbus

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

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)

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

从机设备上数据的内容地址不对,可以根据slave的definition的参数,报错可以查看ModbusMaster类的responseCode方法。

请求的quantity数超过slave定义的quantity数量也会报内容地址错误,请求只能小于定义的数量。

6.  关于返回的数组。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

如果请求的是5个数据,phpmodbus会返回元素为10的数组。如果是2个,则返回4个元素数组,以此类推。

7. 关于返回数组与slave的数据块地址数据对应的方式。

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

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


?>

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

【物联网篇】PHP通过Modbus Tcp实时获取设备数据

上一篇:JVM学习01—下载编译jdk源码并进行调试


下一篇:javascript中常用的一些功能及正则表达式的用法