更新记录
1.0.0(2026-09-16) 下载此版本
初版
平台兼容性
uni-app
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | 4.4 | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | √ | √ |
ModbusTCP 通信工具 (SL-WX-ModbusTcp.js)
基于 HTML5+ plus.android 调用 java.net.Socket 实现的 ModbusTCP 二进制协议通信工具,仅支持 Android App(5+) 环境。非 Android 环境调用任何方法会自动 reject 并弹窗提示。
⚠️ 关于 plus.net 的说明:HTML5+ 的
plus.net模块仅提供XMLHttpRequest(HTTP 请求),并不提供原生 TCP Socket API。ModbusTCP 是基于 TCP 的二进制协议,必须使用 Socket。因此本工具通过plus.android.importClass('java.net.Socket')调用 Java 原生 Socket 实现,仅 Android 可用;iOS 需要另行开发 uni 原生插件(Objective-C / Swift)。
目录结构
components/SL-WX-ModbusTcp
└── SL-WX-ModbusTcp.js
快速开始
import modbus from '@/components/SL-WX-ModbusTcp/SL-WX-ModbusTcp.js'
// 1. 连接 PLC
await modbus.connect('192.168.1.10', 502, 3000)
// 2. 读 BOOL(线圈,功能码 1)—— 起始地址 1,数量 1
const bools = await modbus.readBool(1, 1, 1, 1)
// → [true]
// 3. 读 INT16(保持寄存器,功能码 3)—— 起始地址 1000,数量 4
const ints = await modbus.readInt(1000, 4, 1, 3)
// → [1234, -5678, 90, 100]
// 4. 读 INT32(占 2 寄存器)—— 地址 1000,字节序 CDAB
const i32 = await modbus.readInt32(1000, 1, 'CDAB', 3)
// 5. 读 FLOAT(占 2 寄存器)—— 地址 2000,字节序 CDAB
const f = await modbus.readFloat(2000, 1, 'CDAB', 3)
// → 3.14
// 6. 写 BOOL(线圈,功能码 5)
await modbus.writeBool(1, true, 1)
// 7. 写 INT16(保持寄存器,功能码 6)
await modbus.writeInt(1000, 12345, 1)
// 8. 写 INT32(占 2 寄存器,功能码 16)
await modbus.writeInt32(1000, 123456789, 'ABCD', 1)
// 9. 写 FLOAT(占 2 寄存器,功能码 16)
await modbus.writeFloat(2000, 3.14159, 'ABCD', 1)
// 10. 断开
await modbus.disconnect()
环境检测
if (!modbus.isApp() || !modbus.isAndroid()) {
const platform = modbus.getPlatformName() // 'H5' | '微信小程序' | ...
uni.showModal({ title: '提示', content: `当前为${platform},无法使用 ModbusTCP` })
return
}
核心特性
- 完整 ModbusTCP 协议栈:自行构建/解析 MBAP Header(7 字节)+ PDU,支持功能码 1/2/3/4/5/6/16,覆盖线圈、离散输入、保持寄存器、输入寄存器的读写。
- BOOL / INT16 / INT32 / FLOAT 四种数据类型:读写齐全,INT32 与 FLOAT 自动处理双寄存器拼接。
- 4 种字节序:ABCD(大端)/ DCBA(小端)/ BADC / CDAB(字交换),适配不同 PLC 厂商的 32 位数据存储顺序。
- 从站号可配:每次读写可指定
unitId(1~247,默认 1),适配多从站现场。 - 浮点精度截断:
readFloat返回值自动toFixed(6)截断 IEEE 754 float32 精度噪声,无需手动处理。 - 异常响应解析:自动识别 Modbus 异常响应(功能码最高位 = 1),抛出含异常码与中文说明的错误。
- Transaction ID 校验:每帧递增并校验响应帧的事务标识,防止串帧。
- 粘包处理:按功能码与请求参数计算预期响应长度,精确读取,无需额外处理粘包。
- 连接自动清理:
connect前自动关闭旧 Socket / InputStream / OutputStream,可安全重复调用。 - Promise 化 API:所有读写方法返回 Promise,配合 async/await 流畅书写。
- 平台自动检测:非 Android App 环境调用自动 reject 并弹窗提示,附带
isApp()/isAndroid()/getPlatformName()环境检测工具。
API 列表
连接 / 断开
connect(host, port, timeout) → Promise<true>
建立到 PLC 的 TCP 连接。连接前会自动清理旧连接。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
host |
String | — | PLC 的 IP 地址,如 '192.168.1.10' |
port |
Number | 502 |
ModbusTCP 标准端口 502 |
timeout |
Number | 3000 |
连接超时与读取超时(毫秒),超时后抛出 SocketTimeoutException |
disconnect() → Promise<true>
断开连接,依次关闭 InputStream、OutputStream、Socket,释放 Java 侧资源。
isConnected() → Boolean
同步方法,返回当前是否处于已连接状态。
读取
readBool(addr, count, unitId, funcCode) → Promise<Boolean[]>
读取线圈或离散输入,返回布尔值数组。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
addr |
Number | — | 起始地址(0-based),如 1 表示从第 1 个线圈开始 |
count |
Number | 1 |
读取数量,1~2000 |
unitId |
Number | 1 |
从站号(1~247) |
funcCode |
Number | 1 |
功能码:1 = 读线圈(可读可写区域),2 = 读离散输入(只读区域) |
readInt(addr, count, unitId, funcCode) → Promise<Number[]>
读取保持寄存器或输入寄存器,返回有符号 16 位整数数组(-32768~32767)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
addr |
Number | — | 起始寄存器地址(0-based),如 1000 |
count |
Number | 1 |
读取寄存器数量,1~125 |
unitId |
Number | 1 |
从站号(1~247) |
funcCode |
Number | 3 |
功能码:3 = 读保持寄存器(可读可写区域),4 = 读输入寄存器(只读区域) |
readInt32(addr, unitId, wordOrder, funcCode) → Promise<Number>
读取 32 位有符号整数,占 2 个连续寄存器。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
addr |
Number | — | 起始寄存器地址(0-based) |
unitId |
Number | 1 |
从站号(1~247) |
wordOrder |
String | 'ABCD' |
字节序,见「字节序说明」章节。可选:ABCD / DCBA / BADC / CDAB |
funcCode |
Number | 3 |
功能码:3 = 保持寄存器,4 = 输入寄存器 |
readFloat(addr, unitId, wordOrder, funcCode) → Promise<Number>
读取 32 位浮点数,占 2 个连续寄存器。返回值已做 toFixed(6) 精度截断。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
addr |
Number | — | 起始寄存器地址(0-based) |
unitId |
Number | 1 |
从站号(1~247) |
wordOrder |
String | 'ABCD' |
字节序,见「字节序说明」章节。可选:ABCD / DCBA / BADC / CDAB |
funcCode |
Number | 3 |
功能码:3 = 保持寄存器,4 = 输入寄存器 |
写入
writeBool(addr, value, unitId) → Promise<true>
写单个线圈(功能码 5)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
addr |
Number | — | 线圈地址(0-based) |
value |
Boolean | — | true = ON(发送 0xFF00),false = OFF(发送 0x0000) |
unitId |
Number | 1 |
从站号(1~247) |
writeInt(addr, value, unitId) → Promise<true>
写单个保持寄存器(功能码 6)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
addr |
Number | — | 寄存器地址(0-based) |
value |
Number | — | 有符号 16 位整数,范围 -32768~32767 |
unitId |
Number | 1 |
从站号(1~247) |
writeInt32(addr, value, wordOrder, unitId) → Promise<true>
写 32 位有符号整数,占 2 个连续寄存器(功能码 16)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
addr |
Number | — | 起始寄存器地址(0-based) |
value |
Number | — | 有符号 32 位整数,范围 -2147483648~2147483647 |
wordOrder |
String | 'ABCD' |
字节序,见「字节序说明」章节。可选:ABCD / DCBA / BADC / CDAB |
unitId |
Number | 1 |
从站号(1~247) |
writeFloat(addr, value, wordOrder, unitId) → Promise<true>
写 32 位浮点数,占 2 个连续寄存器(功能码 16)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
addr |
Number | — | 起始寄存器地址(0-based) |
value |
Number | — | 浮点数,如 3.14 |
wordOrder |
String | 'ABCD' |
字节序,见「字节序说明」章节。可选:ABCD / DCBA / BADC / CDAB |
unitId |
Number | 1 |
从站号(1~247) |
环境检测
isApp() → Boolean
同步方法,返回当前是否运行在 App 环境(APP-PLUS 编译条件)。
isAndroid() → Boolean
同步方法,返回当前是否为 Android 平台。非 Android 的 App 环境(如 iOS)返回 false。
getPlatformName() → String
同步方法,返回当前平台名称字符串,用于提示文案。可能的返回值:'H5' / '微信小程序' / '支付宝小程序' / '当前平台'。
功能码说明
| 功能码 | 名称 | 数据类型 | 操作 | 方法 |
|---|---|---|---|---|
| 1 | Read Coils | BOOL | 只读 | readBool(addr, count, unitId, 1) |
| 2 | Read Discrete Inputs | BOOL | 只读 | readBool(addr, count, unitId, 2) |
| 3 | Read Holding Registers | INT16 | 读写 | readInt / readInt32 / readFloat (默认 funcCode) |
| 4 | Read Input Registers | INT16 | 只读 | readInt(addr, count, unitId, 4) 等 |
| 5 | Write Single Coil | BOOL | 只写 | writeBool(addr, value, unitId) |
| 6 | Write Single Register | INT16 | 只写 | writeInt(addr, value, unitId) |
| 16 | Write Multiple Registers | INT16 | 只写 | writeInt32 / writeFloat(内部使用) |
字节序说明
32 位数据(INT32 / FLOAT)占用 2 个连续寄存器,共 4 字节。不同 PLC 的字节排列顺序不同,本工具支持 4 种字节序:
| 字节序 | 含义 | 字节顺序(寄存器 1 高/低 + 寄存器 2 高/低) | 适用 PLC |
|---|---|---|---|
| ABCD | 大端(高字在前,高字节在前) | [A B] [C D] | 多数 PLC 默认 / 莫迪康 |
| DCBA | 小端(低字在前,低字节在前) | [D C] [B A] | 部分西门子 |
| BADC | 字交换 + 字节交换 | [B A] [D C] | 部分施耐德 |
| CDAB | 字交换(高字在后) | [C D] [A B] | 部分台达 / 信捷 |
大多数 PLC 默认 ABCD,调用时可不传
wordOrder参数(自动取默认值)。具体字节序请参考设备厂商文档。
使用示例
示例 1:读线圈状态(BOOL)
// 读地址 1~8 的 8 个线圈
const bools = await modbus.readBool(1, 8, 1, 1)
// bools = [true, false, true, true, false, false, true, false]
示例 2:读保持寄存器(INT16)
// 读地址 1000~1003 的 4 个保持寄存器
const ints = await modbus.readInt(1000, 4, 1, 3)
// ints = [1234, -5678, 90, 100]
示例 3:读浮点数(FLOAT,32 位)
// 读地址 2000 的 float(占 D2000~D2001 两个寄存器),字节序 ABCD
const f = await modbus.readFloat(2000, 1, 'ABCD', 3)
// f = 3.14
示例 4:写线圈(BOOL)
// 写线圈地址 1 为 ON
await modbus.writeBool(1, true, 1)
// 写线圈地址 2 为 OFF
await modbus.writeBool(2, false, 1)
示例 5:写浮点数(FLOAT,32 位)
// 写 float 到地址 2000(占 D2000~D2001),字节序 ABCD
await modbus.writeFloat(2000, 3.14159, 'ABCD', 1)
示例 6:批量轮询示例
async function poll() {
try {
const [bools, ints, f] = await Promise.all([
modbus.readBool(1, 8, 1, 1), // 线圈状态
modbus.readInt(1000, 4, 1, 3), // 寄存器值
modbus.readFloat(2000, 1, 'ABCD', 3) // 浮点数
])
console.log('bools:', bools)
console.log('ints:', ints)
console.log('float:', f)
} catch (e) {
console.error('轮询失败:', e.message)
await modbus.disconnect()
}
}
// 每 1 秒轮询一次
setInterval(poll, 1000)
ModbusTCP 帧结构
MBAP Header(7 字节)
| 偏移 | 长度 | 字段 | 说明 |
|---|---|---|---|
| 0 | 2 | Transaction ID | 事务标识,递增;响应帧回传相同值 |
| 2 | 2 | Protocol ID | 协议标识,Modbus 固定为 0x0000 |
| 4 | 2 | Length | 后续字节数(Unit ID + PDU) |
| 6 | 1 | Unit ID | 从站号(1~247) |
PDU
| 偏移 | 长度 | 字段 | 说明 |
|---|---|---|---|
| 7 | 1 | Func Code | 功能码 |
| 8+ | N | Data | 数据(请求/响应内容) |
异常响应
| 偏移 | 长度 | 字段 | 说明 |
|---|---|---|---|
| 7 | 1 | Exception Func | 功能码 + 0x80(最高位为 1 标识异常) |
| 8 | 1 | Exception Code | 异常码(1=非法功能码,2=非法地址 等) |
注意事项
-
仅 Android:本工具基于
plus.android.importClass('java.net.Socket'),iOS 不适用。iOS 需要开发 uni 原生插件(Objective-C / Swift 实现 BSD Socket)。 -
网络权限:App 需要在
manifest.json中声明android.permission.INTERNET权限(HBuilderX 默认已包含)。 -
局域网要求:手机与 PLC 必须在同一局域网,且 PLC 已开启 ModbusTCP 服务(默认端口 502,具体启用方式请参考设备厂商文档)。
-
超时设置:
connect时设置timeout(默认 3000ms),同时作为setSoTimeout读超时。读不到数据会在 timeout 后抛出java.net.SocketTimeoutException。 -
数据范围:
readBool单次最多 2000 个readInt单次最多 125 个寄存器readInt32/readFloat实际读 2 个寄存器writeInt范围 -32768~32767writeInt32范围 -2147483648~2147483647
-
字节序选择:不同 PLC 厂商对 32 位数据在寄存器中的存储顺序不同。多数 PLC 默认
ABCD,若读出的数据明显异常(如很大的随机数),尝试切换为CDAB或DCBA。 -
连接复用:
connect前会自动清理旧连接,可重复调用。但建议调用disconnect后再connect,避免资源泄漏。 -
异常处理:所有方法 reject 时返回的是原始 Java 异常对象或包装的 Error,可通过
e.message获取中文错误说明。Modbus 异常响应(如非法地址)会被解析为'Modbus 异常响应:功能码 0x3,异常码 0x2(非法数据地址)'。 -
粘包处理:ModbusTCP 响应长度可预期(根据功能码与请求参数可计算),本工具按预期长度读取,无需处理粘包。但若网络异常导致响应残缺,
_readBytes会在读到 EOF(返回 -1)时抛出'连接已关闭'错误。 -
离开页面:建议在页面
onUnload生命周期中调用disconnect(),避免 Socket 资源泄漏。 -
浮点精度:
readFloat返回值已做toFixed(6)精度截断,避免 IEEE 754 float32 的精度噪声(如3.140000104904175→3.14)。如需更高精度可自行处理原始寄存器值。
预览界面说明
预览页面 pages/modbustcp/modbustcp.vue 提供完整的交互式调试面板,包含以下区域:
| 区域 | 默认地址 | 说明 |
|---|---|---|
| 连接配置 | — | IP / 端口 / 从站号 / 字节序(ABCD / DCBA / BADC / CDAB) |
| 读 BOOL | 1 | 功能码 1(线圈)/ 2(离散输入),支持批量读取,结果以 ON/OFF 网格展示 |
| 写 BOOL | 1 | 功能码 5,ON / OFF 切换写入 |
| 读 INT | 1000 | 功能码 3(保持寄存器)/ 4(输入寄存器),支持批量读取 |
| 写 INT | 1000 | 功能码 6(INT16)/ 16(INT32),可切换类型 |
| 读 FLOAT | 2000 | 功能码 3,占 2 个寄存器,结果自动截断精度噪声 |
| 写 FLOAT | 2000 | 功能码 16,占 2 个寄存器 |
| 操作日志 | — | 记录最近 50 条操作结果,支持清空 |

收藏人数:
下载插件并导入HBuilderX
下载插件ZIP
赞赏(0)
下载 108
赞赏 1
下载 12606362
赞赏 1949
赞赏
京公网安备:11010802035340号