我用 3 个月,把 20 年的工业调试经验做成了微信小程序

从 Modbus 调试到 PID 整定,从串口通信到传感器标定,这款工具集成了工程师最常用的 20+ 专业计算器


前言:一个工程师的”执念”

我是一名工业自动化工程师,从业 20 年,待过设备厂商、集成商,也做过甲方。

这些年,我见过太多工程师在现场的”狼狈”:

  • 背着十几斤重的电脑跑现场,就为了调试一个 Modbus 设备
  • 忘带 USB 转串口线,整个项目停工半天
  • 电脑上的软件要收费,破解版还怕有病毒
  • PID 参数不会整,打电话问厂家,等半天回复
  • 传感器标定靠手算,计算器按错一次,全部重来

最痛苦的一次,是某次深夜抢修。客户的 PLC 通信故障,我赶到时已经是晚上 10 点。结果发现忘带电脑,只能打电话让同事送,折腾到凌晨 3 点才搞定。

那一刻我就想:为什么不能只带手机就去现场?

于是,我花了整整 3 个月,利用业余时间开发了这款 Modbus 调试助手 微信小程序。

它不仅仅是一个调试工具,更是我 20 年经验的结晶。


一、核心功能:20+ 专业工具,装进手机

1.1 Modbus 调试全家桶

小程序最核心的功能,就是 完整的 Modbus 协议栈支持

(1)Modbus Poll – 主站轮询工具

这是使用频率最高的功能,没有之一。

支持的功能码:

功能码名称用途
FC01Read Coils读取线圈状态(开关量输出)
FC02Read Discrete Inputs读取离散输入(开关量输入)
FC03Read Holding Registers读取保持寄存器(最常用)
FC04Read Input Registers读取输入寄存器(只读)
FC05Write Single Coil写入单个线圈
FC06Write Single Register写入单个寄存器
FC15Write Multiple Coils写入多个线圈
FC16Write Multiple Registers写入多个寄存器
FC17Report Slave ID通报客户端 ID
FC22Mask Write Register掩码写寄存器(改单个 bit)
FC23Read/Write Multiple同时读/写多个寄存器
FC43/14Read Device ID读取设备标识

连接方式:

  • Modbus TCP:支持任意 IP 和端口,自动保存连接历史
  • 蓝牙连接:支持普通蓝牙转 485 模块和 PACO 蓝牙适配器
  • 端口转发:支持路由器端口映射(如外部 1502 → 内部 502)

数据显示格式:

同一个寄存器的原始数据,支持 7 种显示格式 一键切换:

Signed(有符号)   →  -32768 ~ 32767
Unsigned(无符号) →  0 ~ 65535
Hex(十六进制)    →  0x0000 ~ 0xFFFF
Long(长整型)     →  32 位整数
Float(浮点型)    →  IEEE 754 单精度
Float Swapped      →  字节反转浮点
Binary(二进制)   →  0000 0000 0000 0001

💡 实际案例:某温度传感器返回 0x4248 0x0000,如果按 16 位整数看是 17480 和 0,完全不对。切换到 Float 格式,显示 50.0,这才是实际温度值。

高级工具:

  • 通讯监视面板:实时记录所有 Tx/Rx 原始报文,支持暂停/继续,一键分享
  • TC 测试中心:手动输入 Hex 字符串发送,查看原始响应,调试自定义协议
  • 实时图表:输入要监控的寄存器地址,柱状图实时显示数值变化
  • 请求报文预览:在设置界面实时显示即将发送的 RTU/ASCII 帧结构(含 CRC/LRC 校验)

(2)Modbus Slave – 从站模拟器

这个功能很多人忽略,但其实非常实用。

使用场景:

  • 测试上位机软件(如组态王、WinCC)
  • 验证 PLC 程序逻辑
  • 培训新员工(无需真实设备)
  • 开发阶段模拟从站响应

支持功能:

  • 模拟线圈、离散输入、保持寄存器、输入寄存器
  • 自定义初始值
  • 支持批量设置地址范围
  • 实时显示主站请求报文

(3)Modbus RTU/TCP/ASCII – 协议详解

小程序对三种传输模式都有详细说明和实战示例。

RTU vs ASCII 对比:

特性RTUASCII
编码方式二进制ASCII 文本
校验方式CRC16LRC
帧长度较短(高效)约为 RTU 2 倍
帧标识3.5 字符静默间隔“:” 开头 + CR LF 结尾
适用场景大多数工业设备老旧设备/调制解调器

CRC16 算法实现(核心代码):

// MODBUS CRC-16 (低字节在前)
calcCRC16(bytes) {
  let crc = 0xFFFF;
  for (let i = 0; i < bytes.length; i++) {
    crc ^= bytes[i];
    for (let j = 0; j < 8; j++) {
      if (crc & 0x0001) {
        crc = (crc >> 1) ^ 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }
  const lo = crc & 0xFF;
  const hi = (crc >> 8) & 0xFF;
  return lo.toString(16).toUpperCase().padStart(2, '0') + ' ' + 
         hi.toString(16).toUpperCase().padStart(2, '0');
}

LRC 算法实现:

// MODBUS ASCII LRC
calcLRC(bytes) {
  let sum = 0;
  for (let i = 0; i < bytes.length; i++) {
    sum += bytes[i];
  }
  const lrc = ((~sum) + 1) & 0xFF;
  return lrc.toString(16).toUpperCase().padStart(2, '0');
}

1.2 串口调试助手

这是第二个高频使用的功能。

核心特性:

  • 三种连接方式:蓝牙 / TCP / UDP
  • 全参数配置:波特率(9600/19200/38400/57600/115200)、数据位、停止位、校验位
  • 收发区独立设置
    • 接收区:ASCII/HEX 切换、时间戳、自动换行、显示行号、自动滚动
    • 发送区:ASCII/HEX 切换、自动解析转义符(\r\n \t)、循环发送
  • 四种校验方式:CRC-16、累加和、LRC、异或校验
  • 实时统计:RX/TX 字节数、一键复位

实战案例 1:蓝牙调试 PACO 设备

PACO 是一款常用的蓝牙 485 适配器,小程序对其做了深度优化。

// 构建 PACO 命令 (80 字节固定长度)
buildPacoCommand(cmdType, param = '') {
  let cmd = '';
  switch(cmdType) {
    case 'read485':
      cmd = 'PACO-Setting-Code-PACO-FXY-BT-485-R-485Setting.';
      break;
    case 'write485':
      cmd = `PACO-Setting-Code-PACO-FXY-BT-485-W-485Setting:${param}.`;
      break;
    case 'readName':
      cmd = 'PACO-Setting-Code-               -R-PartNumber.';
      break;
    case 'writeName':
      cmd = `PACO-Setting-Code-PACO-FXY-BT-485-W-DeviceName:${param}.`;
      break;
  }
  // 补齐到 76 字符,末尾加 PACO
  const paddedCmd = cmd.padEnd(76, ' ') + 'PACO';
  return paddedCmd;
}

可以读写 PACO 设备的:

  • 485 参数(波特率/数据位/停止位/校验位)
  • 设备名称(最大 7 字符)

实战案例 2:TCP 端口限制问题

微信小程序对端口有严格限制,这是一个大坑。

// 微信小程序端口限制检查
const forbiddenPorts = [1099, 1433, 1521, 1719, 1720, 1723, 
  2049, 2375, 3128, 3306, 3389, 3659, 4045, 5060, 5061, 
  5432, 5984, 6379, 6000, 6566, 7001, 7002, 8443, 8888, 
  9200, 9300, 10051, 10080, 11211, 27017, 27018, 27019];

if (portNum < 1024) {
  // 禁止连接 1024 以下端口(如 502)
  uni.showModal({ 
    title: '端口受限', 
    content: '微信小程序禁止连接 1024 以下端口,请使用 APP 版本或更换端口', 
    showCancel: false 
  });
  return;
}

if (portNum >= 8000 && portNum <= 8100) {
  // 禁止连接 8000-8100 端口
  uni.showModal({ 
    title: '端口受限', 
    content: '微信小程序禁止连接 8000-8100 端口,请更换端口', 
    showCancel: false 
  });
  return;
}

解决方案:
在路由器做端口转发,比如外部 1502 → 内部 502。


1.3 专业计算器系列

这部分是我花心思最多的,也是最能体现”经验价值”的地方。

(1)PID 自整定计算器

PID 参数整定是自动控制系统的核心,也是很多工程师的痛点。

支持的整定方法:

方法适用场景特点
齐格勒 – 尼科尔斯第一法阶跃响应实验经典方法,适用面广
齐格勒 – 尼科尔斯第二法临界振荡法需要找到临界增益
Cohen-Coon大滞后系统对滞后系统效果好
IMC(内模控制)高性能要求参数可调,灵活性高
极点配置特定动态响应需要系统模型

输入参数:

  • 延迟时间 L(秒)
  • 时间常数 T(秒)
  • 过程增益 K
  • λ 参数(IMC 专用)

输出结果:

  • 比例增益 Kp
  • 积分时间 Ti
  • 微分时间 Td
  • 推荐配置(如控制器类型、控制变量选择)

核心算法(齐格勒 – 尼科尔斯第一法):

// Ziegler-Nichols 第一法(阶跃响应法)
zieglerNichols1st(L, T, K) {
  // Kp = 1.2 * T / (K * L)
  // Ti = 2 * L
  // Td = 0.5 * L
  const kp = 1.2 * T / (K * L);
  const ti = 2 * L;
  const td = 0.5 * L;
  return { kp, ti, td };
}

实战案例:

某温度控制系统,通过阶跃响应实验得到:

  • 延迟时间 L = 2.5s
  • 时间常数 T = 8.0s
  • 过程增益 K = 1.0

代入公式计算:

  • Kp = 1.2 × 8.0 / (1.0 × 2.5) = 3.84
  • Ti = 2 × 2.5 = 5.0s
  • Td = 0.5 × 2.5 = 1.25s

将这三个参数输入 PID 控制器,系统响应快速且超调小。

(2)传感器标定计算器

传感器标定是现场调试的常规工作,但手算容易出错。

支持四种模式:

① 线性标定(最常用)

适用于 4-20mA、0-10V 等线性传感器。

标定公式:Y = kX + b

其中:
k = (Y2 - Y1) / (X2 - X1)  // 斜率
b = Y1 - k * X1            // 截距

快速换算表:

百分比信号值 (mA)工程值 (℃)
0%4.000.00
25%8.0025.00
50%12.0050.00
75%16.0075.00
100%20.00100.00

② 多点拟合

适用于非线性传感器(如热电偶、热电阻)。

支持:

  • 二次曲线拟合
  • 三次曲线拟合
  • 最小二乘法

③ 温度专用模式

内置常用温度传感器分度表:

  • PT100 热电阻
  • K 型热电偶
  • J 型热电偶
  • E 型热电偶
  • T 型热电偶

④ 误差分析

计算:

  • 绝对误差
  • 相对误差
  • 满量程误差
  • 线性度

实战案例:

某压力变送器,量程 0-10bar,输出 4-20mA。

标定点设置:

  • 低点:4mA → 0bar
  • 高点:20mA → 10bar

计算结果:

  • k = (10 – 0) / (20 – 4) = 0.625
  • b = 0 – 0.625 × 4 = -2.5

标定公式:Y = 0.625X – 2.5

验证:

  • 输入 12mA → Y = 0.625 × 12 – 2.5 = 5.0bar ✓
  • 输入 20mA → Y = 0.625 × 20 – 2.5 = 10.0bar ✓

(3)校验计算工具

这个工具集成了 10+ 种工业通信协议常用的校验算法。

支持功能:

校验类型说明适用场景
MODBUS RTU CRC-1616 位循环冗余校验Modbus RTU 协议
MODBUS ASCII LRC纵向冗余校验Modbus ASCII 协议
校验和(16 位)累加和取低 16 位简单协议
异或校验(8 位)所有字节异或自定义协议
西门子 S7 校验和S7 通信协议专用西门子 PLC
三菱 FX 求和校验三菱通信协议三菱 PLC
BCC 校验块校验字符串口通信
IP/TCP 校验和网络协议校验TCP/IP 栈
欧姆龙 FINS FCSFINS 协议校验欧姆龙 PLC
CAN CRCCAN 总线校验汽车电子

使用方法:

  1. 选择校验类型
  2. 输入原始 HEX 数据
  3. 自动计算校验码
  4. (可选)附加校验码后发送

实战案例:Modbus RTU 命令

原始数据:01 03 00 00 00 01

计算 CRC-16:

  • 输入 6 字节
  • 计算得 CRC = 0x840A
  • 低字节在前:84 0A

完整报文:01 03 00 00 00 01 84 0A


1.4 其他专业工具

小程序还有 15+ 专业工具,这里简单列举:

(1)PLC 调试工具

  • Q06 开关调试助手:专门针对 Q06 系列开关的调试工具
  • X160 调试工具:X160 设备专用调试
  • ZLAN 设备管理器:有人物联网 ZLAN 系列设备管理

(2)执行器调试

  • 调光调试助手:0-10V/PWM 调光器调试
  • 8 路继电器控制:多路继电器批量控制
  • 伺服脉冲计算:伺服电机脉冲当量计算

(3)变频器调试

  • 变频器调试工具:支持主流变频器参数设置

(4)其他计算器

  • 压力变送器调试:差压/压力变送器计算
  • 远程协助工具:实时共享调试画面

二、技术架构:小程序也能做专业工具

2.1 技术选型

前端框架: uni-app

选择理由:

  • 一套代码编译到微信小程序、H5、APP
  • 丰富的组件库
  • 良好的蓝牙/TCP/UDP API 支持

UI 框架: colorUI + 自定义组件

数据存储:

  • 本地存储:uni.setStorageSync
  • 连接历史记录
  • 项目配置保存

2.2 核心技术难点

(1)蓝牙 BLE 连接

微信小程序的蓝牙 API 有一些限制,需要特殊处理。

难点 1:服务特征值查找

不同蓝牙模块的 Service UUID 和 Characteristic UUID 不同,需要智能查找。

// 遍历所有服务查找可写特征
findWritableCharacteristic() {
  if (this.currentServiceIndex >= this.allServices.length) {
    // 所有服务都遍历完了
    if (this.foundWriteChar) {
      this.finishBluetoothConnection();
    } else {
      uni.showToast({ title: '未找到可写特征', icon: 'none' });
    }
    return;
  }

  const service = this.allServices[this.currentServiceIndex];
  
  uni.getBLEDeviceCharacteristics({
    deviceId: this.connectedDeviceId,
    serviceId: service.uuid,
    success: (res) => {
      const characteristics = res.characteristics;
      
      // 查找策略:
      // 1. 优先找同时支持 write 和 notify 的特征(双向通信)
      // 2. 其次找只支持 write 的特征
      // 3. 最后找支持 writeNoResponse 的特征
      let writeChar = characteristics.find(c =>
        c.properties.write === true &&
        (c.properties.notify === true || c.properties.indicate === true)
      );
      
      if (!writeChar) {
        writeChar = characteristics.find(c => c.properties.write === true);
      }
      
      if (!writeChar) {
        writeChar = characteristics.find(c => c.properties.writeNoResponse === true);
      }
      
      if (writeChar) {
        this.writeCharacteristicId = writeChar.uuid;
        this.foundWriteChar = true;
        this.finishBluetoothConnection();
        return;
      }
      
      // 当前服务未找到,继续下一个
      this.currentServiceIndex++;
      this.findWritableCharacteristic();
    }
  });
}

难点 2:PACO 设备 80 字节单包发送

PACO 设备需要一次发送 80 字节,但 BLE 默认 MTU 只有 20 字节。

解决方案:

// 设置 BLE MTU(最大传输单元)
setBLEMTU(deviceId, callback) {
  if (wx.setBLEMTU) {
    wx.setBLEMTU({
      deviceId: deviceId,
      mtu: 512,  // 设置为 512 字节
      success: (res) => {
        console.log('MTU 设置成功');
        callback && callback();
      },
      fail: (err) => {
        console.error('MTU 设置失败', err);
        callback && callback();
      }
    });
  } else {
    callback && callback();
  }
}

(2)TCP Socket 通信

微信小程序的 TCP Socket API 是异步的,需要处理连接超时、数据分包、粘包等问题。

连接超时处理:

const connTimeout = setTimeout(() => {
  if (!self.isConnected) {
    uni.hideLoading();
    uni.showToast({ title: '连接超时', icon: 'none' });
    try { tcp.close(); } catch(e) {}
    self.tcpSocket = null;
  }
}, 8000);  // 8 秒超时

tcp.onConnect(function(res) {
  clearTimeout(connTimeout);
  self.isConnected = true;
  // ...
});

数据分包处理:

handleTcpResponse(hexData) {
  const hex = hexData.replace(/\s+/g, '');
  
  // 将接收到的数据添加到缓冲区
  for (let i = 0; i < hex.length; i += 2) {
    this.receiveBuffer.push(parseInt(hex.substr(i, 2), 16));
  }

  // 使用 MBAP 头的 Length 字段判断帧完整性
  while (this.receiveBuffer.length >= 7) {
    const mbapLength = (this.receiveBuffer[4] << 8) | this.receiveBuffer[5];
    const totalFrameLength = 6 + mbapLength;

    if (this.receiveBuffer.length >= totalFrameLength) {
      // 提取完整的一帧
      const frame = this.receiveBuffer.splice(0, totalFrameLength);
      this.parseModbusTcpResponse(frame);
    } else {
      // 数据不完整,等待更多数据
      break;
    }
  }
}

(3)大数据处理

串口调试时,如果长时间运行,会产生大量数据。

优化策略:

// 消息缓冲区管理
maxMessageCount: 800,  // 最多保存 800 条
maxVisibleMessageChars: 240,  // 每条最多显示 240 字符

trimMessageBuffer() {
  const maxTotalChars = this.maxMessageCount * this.maxVisibleMessageChars * 2;
  
  while (this.messages.length > this.maxMessageCount || 
         this.totalMessageChars > maxTotalChars) {
    const removed = this.messages.shift();
    if (removed && removed.data) {
      this.totalMessageChars -= removed.data.length;
    }
  }
}

// 超长消息自动截断,支持展开/收起
isMessageTruncated(msg) {
  return !!(msg && msg.data && 
            msg.data.length > this.maxVisibleMessageChars);
}

getDisplayMessage(msg) {
  if (!msg || !msg.data) return '';
  if (msg.expanded || !this.isMessageTruncated(msg)) {
    return msg.data;
  }
  return msg.data.slice(0, this.maxVisibleMessageChars) + '…';
}

三、设计理念:工程师懂工程师

3.1 Win7 风格界面

很多人问为什么用 Win7 风格?

因为 熟悉

大多数工业工程师天天对着电脑,Win7 的界面是最熟悉的。看到这种风格,就有”专业工具”的感觉。

设计细节:

  • 渐变蓝色标题栏
  • 立体边框(外浅内深)
  • 灰色背景 + 白色内容区
  • 等宽字体显示数据(Courier New)

3.2 远程协助功能

这个功能是我在现场调试时想到的。

场景:
现场设备故障,我搞不定,需要同事远程协助。但传统方式只能电话描述,效率极低。

解决方案:

// 生成协助会话码
startRemoteAssist() {
  const sessionId = generateRandomSessionId();
  this.remoteAssistSessionId = sessionId;
  this.remoteAssistShowPanel = true;
  
  // 实时转发通信数据
  this.remoteAssistForward('tx', 'Tx', data);
  this.remoteAssistForward('rx', 'Rx', data);
  
  // 接收远程命令
  this._executeRemoteCommand(cmd);
}

使用流程:

  1. 点击”远程协助”
  2. 生成 6 位会话码
  3. 分享给微信好友
  4. 对方打开后,实时查看通信数据
  5. 对方可以远程发送命令

价值:

  • 无需截图/录屏
  • 实时双向通信
  • 支持多人协作

3.3 数据导出分享

现场调试完,经常需要把数据发给同事或存档。

导出格式:

【串口调试 - 通信记录】
导出时间:2026-04-05 11:00:00
共 50 条记录
发送:1200 字节,接收:800 字节
========================================

[11:00:00.123] 发送:01 03 00 00 00 01 84 0A
[11:00:00.456] 接收:01 03 02 00 0A B9 C8
[11:00:01.123] 发送:01 03 00 00 00 0A C5 CD
...

========================================
来自:Modbus 调试助手 微信小程序

实现方式:

buildExportLogContent(options = {}) {
  let content = `${options.title || '【串口调试 - 通信记录】'}\n`;
  content += `导出时间:${new Date().toLocaleString()}\n`;
  content += `共 ${this.messages.length} 条记录\n`;
  content += `发送:${this.sentCount} 字节,接收:${this.receivedCount} 字节\n`;
  content += `${'='.repeat(40)}\n\n`;

  this.messages.forEach((msg) => {
    const direction = msg.type === 'sent' ? '发送' : '接收';
    content += `[${msg.time}] ${direction}: ${msg.data}\n`;
  });

  content += `\n${'='.repeat(40)}\n`;
  content += `来自:Modbus 调试助手 微信小程序`;
  
  return content;
}

四、用户反馈:真实的声音

上线 2 个月,已经有 5000+ 工程师在使用。

反馈 1:

“太方便了!以后出差只带手机就够了。昨天去现场,客户都惊讶我怎么只带个手机就搞定了。”
—— 江苏,自动化工程师,王工

反馈 2:

“PID 整定计算器帮了大忙。以前整定参数要试半天,现在输入 L/T/K,直接出结果。”
—— 广东,控制工程师,李工

反馈 3:

“远程协助功能太强了。现场遇到问题,直接分享给同事,5 分钟搞定,以前至少要半小时电话沟通。”
—— 浙江,技术支持,张工

反馈 4:

“传感器标定计算器很实用。我们厂有几百个传感器,以前标定要手算,现在输入两个点,自动出公式。”
—— 山东,仪表工程师,刘工


五、未来规划

5.1 短期计划(1-3 个月)

  • 增加 OPC UA 客户端
  • 支持 MQTT 协议调试
  • 增加 BACnet 协议支持
  • 云端项目同步(VIP 功能)

5.2 中期计划(3-6 个月)

  • APP 版本(突破微信小程序端口限制)
  • 支持脚本功能(Lua/JavaScript)
  • 增加图表分析功能(趋势图、频谱分析)
  • 设备数据库(常见设备参数模板)

5.3 长期愿景

做一个工业工程师的”百宝箱”

只要是现场调试能用到的工具,都集成到这个小程序里。

让工程师:

  • 少背点东西,轻装上阵
  • 少加点班,早点回家
  • 少一些烦恼,多一些效率

六、写在最后

做这个小程序的初衷,不是为了赚钱。

只是想解决自己的痛点,顺便帮到更多同行。

20 年的经验告诉我:工具的价值,不在于功能多花哨,而在于真正解决问题。

每一个功能,都是我现场调试时真实遇到过的痛点。

每一行代码,都凝聚着我对这个行业的热爱。

如果你也是工业工程师,希望这个小程序能帮到你。

如果你有任何建议,欢迎反馈。

让我们一起,让工业调试变得更简单。


附录:使用方式

方式 1:微信扫码

20年经验凝聚:Modbus调试助手介绍插图1

方式 2:微信搜索

搜索”Modbus 调试助手”

方式 3:朋友分享

点击朋友分享的卡片直接进入


关于作者

20 年工业自动化经验,待过设备厂商、集成商、甲方。

现专注于工业物联网、边缘计算、智能控制。

欢迎交流:


参考资料

[1] Modbus Application Protocol Specification V1.1b3
[2] 齐格勒 – 尼科尔斯 PID 整定方法
[3] 微信小程序蓝牙开发文档
[4] IEEE 754 浮点数标准
[5] CRC16 算法原理与实现

相关新闻

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

cloud@modbus.cn

QQ
微信