写点什么

PHP 通过 Modbus Tcp 实时获取设备数据

作者:北桥苏
  • 2023-05-12
    广东
  • 本文字数:2535 字

    阅读完需:约 8 分钟

前言:

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

?>
复制代码




用户头像

北桥苏

关注

公众号:ZERO开发 2023-05-08 加入

专注后端实战技术分享,不限于PHP,Python,JavaScript, Java等语言,致力于给猿友们提供有价值,有干货的内容。

评论

发布
暂无评论
PHP通过Modbus Tcp实时获取设备数据_物联网_北桥苏_InfoQ写作社区