zoukankan      html  css  js  c++  java
  • 【物联网篇】PHP通过Modbus Tcp实时获取设备数据

    前言:

            最近接触了一个关于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
    
    
    ?>

    个人网站:www.zerofc.cn 公众号:ZEROFC_DEV QQ交流群:515937120 QQ:2652364582 头条号:1637769351151619 B站:286666708 大鱼号:北桥苏
  • 相关阅读:
    AcWing 1027. 方格取数 dp
    AcWing 1014. 登山 dp
    acwing 482. 合唱队形 dp
    LeetCode 1463. 摘樱桃II dp
    LeetCode 100. 相同的树 树的遍历
    LeetCode 336. 回文对 哈希
    LeetCode 815. 公交路线 最短路 哈希
    算法问题实战策略 DARPA大挑战 二分
    算法问题实战策略 LUNCHBOX 贪心
    AcWing 1100. 抓住那头牛 BFS
  • 原文地址:https://www.cnblogs.com/zerofc/p/14827916.html
Copyright © 2011-2022 走看看