Flutter Modbus通信插件modbus_master的使用
Flutter Modbus通信插件modbus_master的使用
modbus_master
是一个易于使用的包,它使得 Dart 程序可以作为一个 Modbus/TCP 主设备。
目前支持的功能
- 离散输入
- 读取单个离散输入
- 线圈
- 读取单个线圈
- 写入单个线圈
- 输入寄存器
- 读取单个输入寄存器
- 保持寄存器
- 读取单个保持寄存器
- 写入单个保持寄存器
当前实现
- 目前只实现了 TCP IPv4。
- 使用单一流对象来接收所有从站设备的响应。
- 此包在单独的隔离区处理套接字网络部分,以使主线程可以自由处理其他任务,如 Flutter 的 UI 部分。
- 此包可以在支持 dart:io 和 dart:isolate 的所有平台上使用,即 WINDOWS, LINUX, MACOS, ANDROID, IOS。
关于此包的重要信息
每个请求都会生成响应
- 如果在超时时间内未从从站设备收到响应,则库将生成错误响应,并将其放入
responses()
流中。 - 发送第一个请求到从站设备时,会建立连接并保持连接状态。
- 每次发送请求到从站设备时,首先检查连接是否已建立。
- 如果连接已建立,则发送请求。
- 如果发现连接断开,则尝试重新建立连接。
- 如果已有 247 个活动连接,并且向新地址发送请求,则最早建立的连接会被断开,新的连接会被建立。
- 如果执行了
close
方法,则首先生成所有待处理请求的响应。之后,关闭所有活动连接。
超时
- 如果从站设备在超时时间内未响应,包将生成错误响应。超时时间在两种不同场景下有所不同:
- 场景 1:当连接已经建立时
- 如果在超时时间内(默认为 1000 毫秒)未生成响应,则主设备生成错误响应。
- 超时时间 = 请求超时(默认 1000 毫秒)
- 场景 2:当连接尚未建立时
- 主设备尝试建立连接。
- 如果在套接字连接超时时间内(默认 2000 毫秒)未建立连接,则主设备生成错误响应。
- 如果连接已建立,则如果在超时时间内(默认 1000 毫秒)未生成响应,则主设备生成错误响应。
- 最大超时时间 = 套接字连接超时时间(默认 2000 毫秒)+ 请求超时时间(默认 1000 毫秒)
- 场景 1:当连接已经建立时
限制
- 只支持 IPv4,不支持 IPv6。
- 只能同时连接 247 个从站设备,超过 247 个时,最早的连接会被断开。
- 只能一次读取单个元素,不支持读取多个线圈或多个寄存器。
- 只能一次写入单个元素,不支持写入多个线圈或多个寄存器。
- 需要 dart 3.0 及以上版本,因为它使用了 dart 记录。
使用此库的步骤
- 在需要创建对象的函数中添加
async
关键字。 - 创建
ModbusMaster
类的实例。
final modbusMaster = await ModbusMaster.start();
- 监听响应流。
modbusMaster.responses().listen(
(response) {
print(response);
}
);
- 使用以下命令向从站发送请求:
- 读取单个线圈
modbusMaster.readCoil(
ipv4: '192.168.29.163',
portNo: 502,
elementNumberOneTo65536: 11,
);
- 读取单个离散输入
modbusMaster.readDiscreteInput(
ipv4: '192.168.1.5',
elementNumberOneTo65536: 11,
);
- 读取单个保持寄存器
modbusMaster.readHoldingRegister(
ipv4: '192.168.1.5',
elementNumberOneTo65536: 11,
);
- 读取单个输入寄存器
modbusMaster.readInputRegister(
ipv4: '192.168.1.5',
elementNumberOneTo65536: 11,
);
- 写入单个线圈
modbusMaster.writeCoil(
ipv4: '192.168.1.5',
elementNumberOneTo65536: 11,
valueToBeWritten: true,
);
- 写入单个保持寄存器
modbusMaster.writeHoldingRegister(
ipv4: '192.168.1.5',
elementNumberOneTo65536: 11,
valueToBeWritten: 15525,
);
- 最后调用
close
方法以关闭所有 TCP 连接并停止modbusMaster
。
modbusMaster.close();
示例代码
1. 首先启动 Modbus/TCP 服务器(即从站设备)使用 pyModbusTCP 库
from pyModbusTCP.server import ModbusServer
import time
import socket
# 获取 IPv4 地址
host_ip = socket.gethostbyname(socket.gethostname())
modbusServer = ModbusServer(host=host_ip, port=502, no_block=True)
try:
print('正在尝试启动 MODBUS/TCP 从站服务器')
modbusServer.start()
print(f'MODBUS/TCP 从站服务器在线于 {host_ip}')
set_coil = True
while True:
if set_coil:
# 线圈地址是线圈编号减一,因此 11-1 写入
modbusServer.data_bank.set_coils(11-1, bit_list=[True])
print('线圈 11 已设置')
else:
modbusServer.data_bank.set_coils(11-1, bit_list=[False])
print('线圈 11 已复位')
print('等待 5 秒钟')
time.sleep(5)
set_coil = not set_coil
except Exception as error:
print(error)
print(f'尝试停止 MODBUS/TCP 从站服务器于 {host_ip}')
modbusServer.stop()
print('MODBUS/TCP 从站服务器已离线')
2. 检查 Modbus/TCP 服务器(从站)是否在线
- 使用 Windows PowerShell 命令检查服务器端口是否打开
# 使用你的设备 IP 地址,该地址由 Python 脚本打印
netstat -na | Select-String "192.168.29.163:502"
- 当套接字监听时,
netstat
命令会显示
TCP 192.168.29.163:502 0.0.0.0:0 LISTENING
- 当套接字关闭时,
netstat
命令不会显示任何内容
3. 使用 Dart 代码与 ModbusMaster 库读取从站设备(pyModbusTCP 服务器)的线圈值
import 'modbus_master_isolate.dart';
void main() {
testReadingCoil();
}
void testReadingCoil() async {
final modbusMaster = await ModbusMaster.start();
int countResponseReceived = 0;
modbusMaster.responses().listen(
(response) {
++countResponseReceived;
print(response);
if (countResponseReceived >= 3) {
// 收到三个响应后关闭 modbusMaster
modbusMaster.close();
}
},
);
for (int i = 1; i <= 5; ++i) {
print('-> 请求 $i');
try {
modbusMaster.readCoil(
ipv4: '192.168.29.163',
portNo: 502,
elementNumberOneTo65536: 11,
);
} catch (e) {
// 执行读取请求后调用 close 方法时会抛出异常
print('读取过程中出现异常 $e');
}
await Future.delayed(Duration(seconds: 5));
}
}
4. 通过反复按 Ctrl+C 关闭 Python 脚本
- 使用
netstat
命令检查套接字是否打开。 - 如果 Python 脚本已结束但套接字仍然打开,使用 Python 语句关闭
modbusServer
modbusServer.stop()
更多关于Flutter Modbus通信插件modbus_master的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复
更多关于Flutter Modbus通信插件modbus_master的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用modbus_master
插件进行Modbus通信的示例代码。这个示例将展示如何设置Modbus客户端,连接到Modbus服务器,并读取和写入寄存器。
首先,确保你的Flutter项目中已经添加了modbus_master
依赖。在pubspec.yaml
文件中添加以下依赖:
dependencies:
flutter:
sdk: flutter
modbus_master: ^1.0.0 # 请使用最新版本号
然后运行flutter pub get
来获取依赖。
接下来是示例代码,展示如何使用modbus_master
插件:
import 'package:flutter/material.dart';
import 'package:modbus_master/modbus_master.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ModbusTcpClient? _client;
String _result = "";
@override
void initState() {
super.initState();
_initModbusClient();
}
@override
void dispose() {
_client?.close();
super.dispose();
}
Future<void> _initModbusClient() async {
_client = ModbusTcpClient('192.168.1.100', port: 502); // 替换为你的Modbus服务器地址和端口
await _client!.connect();
if (_client!.isConnected!) {
setState(() {
_result = "Connected to Modbus server";
});
// 读取保持寄存器示例(功能码03)
Uint8List response = await _client!.readHoldingRegisters(slaveId: 1, startAddress: 0, numberOfPoints: 10);
List<int> registers = Uint16List.view(response.buffer, response.byteOffset, response.length ~/ 2).toList();
print("Holding Registers: $registers");
// 写入单个保持寄存器示例(功能码06)
Uint8List writeResponse = await _client!.writeSingleRegister(slaveId: 1, startAddress: 0, value: 12345);
print("Write Single Register Response: $writeResponse");
// 写入多个保持寄存器示例(功能码16)
List<int> valuesToWrite = [67890, 111213];
Uint8List multipleWriteResponse = await _client!.writeMultipleRegisters(slaveId: 1, startAddress: 10, values: valuesToWrite);
print("Write Multiple Registers Response: $multipleWriteResponse");
} else {
setState(() {
_result = "Failed to connect to Modbus server";
});
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Modbus Master Example'),
),
body: Center(
child: Text(_result),
),
),
);
}
}
代码解释:
- 依赖添加:在
pubspec.yaml
中添加modbus_master
依赖。 - 客户端初始化:在
_initModbusClient
方法中创建并连接到Modbus TCP客户端。 - 读取保持寄存器:使用
readHoldingRegisters
方法读取保持寄存器。 - 写入单个保持寄存器:使用
writeSingleRegister
方法写入单个保持寄存器。 - 写入多个保持寄存器:使用
writeMultipleRegisters
方法写入多个保持寄存器。 - UI显示:在UI中显示连接结果。
注意事项:
- 请确保Modbus服务器正在运行,并且IP地址和端口号正确。
- 根据实际需要调整寄存器地址和值。
- 在实际项目中,你可能需要添加更多的错误处理和状态管理。
这个示例代码展示了如何使用modbus_master
插件进行基本的Modbus通信。根据你的需求,你可以进一步扩展和修改这个示例。