
一、 前期准备1. 硬件链路NMC-G2 网卡插入山特 UPS 智能卡槽网线一头插网卡网口一头插电脑 / 交换机UPS 开机市电正常供电网卡指示灯绿灯常亮。2. 获取网卡 IP打开官网下载的NMC-utility-tool-1.0.4_Windows.zip工具下载过程查看NMC-G2网络管理卡 资料官网下载流程-CSDN博客工具自动扫描局域网列表里会显示 NMC-G2 的 IP例192.168.0.50记下来。设置电脑和网卡处于同一局域网网段。3. 网卡后台开启 Modbus TCP 服务浏览器输入网卡 IP登录 Web 管理页默认账号 admin/admin左侧菜单设置 → 通信协议勾选开启Modbus TCP确认端口 502、从站 ID1保存固件低于 2.4.0-r0上传红色 tar 固件包 SANTAK_NMCG2_updatePackage-2.4.0-r0.tar下载过程查看NMC-G2网络管理卡 资料官网下载流程-CSDN博客升级否则寄存器数据不全。二、Qt 工程基础配置1. .pro 文件添加 Modbus 模块QT core gui widgets modbus network CONFIG c112. 核心原理回顾对应你的协议截图NMC-G2 把 UPS 所有数据存在保持寄存器功能码 03 读取0x0000~0x004F文本信息型号、序列号1 个寄存器存 2 个 ASCII 字符0x0060~0x0065告警故障位掩码0x0070UPS 运行模式0 市电 / 1 电池 / 2 旁路 / 3 故障0x0080 起电压、负载、电池容量数值 ÷10 等于真实值3. 通信逻辑说明Qt 程序 Modbus 客户端主站NMC-G2Modbus 服务端从站 ID1端口 502所有 UPS 状态存储在保持寄存器使用功能码 03 批量读取数据分两类解析规则文本UPS 型号1 个寄存器 2 个 ASCII 字符高字节在前读到 0 终止数值电压 / 负载寄存器数值 ÷10 得到真实值运行模式寄存器 0x00700 市电、1 电池、2 旁路、3 故障告警寄存器 0x0060二进制位标记各类故障。三、完整可运行 Qt 代码直接复制使用头文件 mainwindow.h#ifndef MAINWINDOW_H #define MAINWINDOW_H #include QMainWindow #include QModbusTcpClient #include QTimer class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent nullptr); ~MainWindow(); private: QModbusTcpClient* m_modbus; QTimer* m_pollTimer; // 解析寄存器ASCII字符串读取UPS型号专用 QString parseStr(const QVectorquint16 regs, int startAddr, int wordLen); // 定时读取UPS全部寄存器 void readUpsAllData(); // Modbus数据接收回调解析打印所有状态 void onDataRecv(QModbusReply* reply); }; #endif实现文件 mainwindow.cpp#include mainwindow.h #include QModbusDataUnit #include QModbusReply #include QDebug MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), m_modbus(new QModbusTcpClient(this)), m_pollTimer(new QTimer(this)) { // 这里改成你工具扫描到的NMC-G2网卡IP QString cardIp 192.168.0.50; m_modbus-setConnectionParameter(QModbusDevice::NetworkAddressParameter, cardIp); m_modbus-setConnectionParameter(QModbusDevice::NetworkPortParameter, 502); // 绑定信号 connect(m_pollTimer, QTimer::timeout, this, MainWindow::readUpsAllData); connect(m_modbus, QModbusTcpClient::errorOccurred, this, [](){ qDebug() Modbus通信错误 m_modbus-errorString(); }); // 连接网卡 if(m_modbus-connectDevice()) { qDebug() 成功连接NMC-G2网卡开始轮询UPS状态; m_pollTimer-start(2000); // 2秒读取一次实时状态 } else { qDebug() 网卡连接失败请检查IP和网线; } } MainWindow::~MainWindow() { m_pollTimer-stop(); if(m_modbus-isConnected()) m_modbus-disconnectDevice(); } // 按照协议文档规则解析寄存器里的型号、序列号字符串 QString MainWindow::parseStr(const QVectorquint16 regs, int startAddr, int wordLen) { QString result; for(int i0; iwordLen; i) { int regIndex startAddr i; if(regIndex regs.size()) break; quint16 word regs[regIndex]; // 拆分高低字节文档规定高字节在前 char high (word 8) 0xFF; char low word 0xFF; if(high 0) break; result.append(QChar(high)); if(low 0) break; result.append(QChar(low)); } return result; } // 发起读取请求一次性读取0 ~ 0x90所有寄存器覆盖全部UPS状态 void MainWindow::readUpsAllData() { // 读取保持寄存器起始地址0读取144个Word QModbusDataUnit readCmd(QModbusDataUnit::HoldingRegisters, 0, 0x90); QModbusReply* reply m_modbus-sendReadRequest(readCmd, 1); // 从站ID固定1 if(!reply) return; if(!reply-isFinished()) connect(reply, QModbusReply::finished, this, MainWindow::onDataRecv); else reply-deleteLater(); } // 收到网卡返回数据解析UPS各类状态 void MainWindow::onDataRecv(QModbusReply *reply) { if(reply-error() ! QModbusDevice::NoError) { qDebug() 读取寄存器失败 reply-errorString(); reply-deleteLater(); return; } QVectorquint16 regList reply-result().values(); // 1. 读取UPS型号0x0010起始32个Word QString upsModel parseStr(regList, 0x0010, 32); qDebug() 【UPS型号】 upsModel; // 2. 读取运行模式 地址0x0070 quint16 modeCode regList[0x0070]; QString runMode; switch(modeCode) { case 0: runMode 市电正常供电; break; case 1: runMode 电池放电已停电; break; case 2: runMode 旁路模式; break; case 3: runMode UPS故障; break; default: runMode 未知状态; } qDebug() 【运行模式】 runMode; // 3. 输入市电电压 地址0x0082数值/10 float inputVol regList[0x0082] / 10.0f; qDebug() 【输入电压】 inputVol V; // 4. 输出负载百分比 地址0x0088数值/10 float loadRate regList[0x0088] / 10.0f; qDebug() 【负载占比】 loadRate %; // 5. 电池剩余容量 地址0x0090 quint16 batCap regList[0x0090]; qDebug() 【电池容量】 batCap %; // 6. 告警掩码 地址0x0060 quint16 alarm regList[0x0060]; if(alarm ! 0) qDebug() 【存在告警】告警掩码二进制 QString::number(alarm,2); else qDebug() 【告警状态】无故障; qDebug() ---------------------------; reply-deleteLater(); }1. 什么是「功能码 03」Modbus TCP 规定客户端你的 Qt 程序发给网卡NMC-G2的指令里用数字区分你想做什么操作这个数字就叫功能码。03 读保持寄存器你现在读 UPS 电压、型号、负载全部用这个其他功能码你暂时用不上01 读开关、06 写参数、16 批量写参数简单理解03 固定暗号告诉网卡我要读取 UPS 存在寄存器里的数据。2. 什么是「批量读取」网卡里存放 UPS 数据的寄存器有上百个型号、电压、负载、告警分占不同地址。 有两种读取方式单次只读 1 个寄存器读电压发一次请求、读负载再发一次请求来回频繁通信卡顿、效率低批量读取一次网络请求告诉网卡「从地址 0 开始连续读 144 个寄存器」网卡一次性把所有数据打包返回给 Qt。 只收发 1 次报文就能拿到全部 UPS 状态这就是批量读取。main.cpp#include QApplication #include mainwindow.h int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }四、运行后输出示例【UPS型号】SANTAK C10K 【运行模式】市电正常供电 【输入电压】225.4 V 【负载占比】32.0 % 【电池容量】98 % 【告警状态】无故障 --------------------------- 【UPS型号】SANTAK C10K 【运行模式】电池放电已停电 【输入电压】0.0 V 【负载占比】32.0 % 【电池容量】96 % 【存在告警】告警掩码二进制1 ---------------------------五编译问题报错含义Qt 找不到modbus模块工程无法识别 Modbus 相关类QModbusTcpClient等编译直接告警失败。1. 进入目录运行MaintenanceTool.exe打开文件夹C:\Qt\Qt5.12.12目录里直接存在MaintenanceTool.exe双击即可启动。2选择「添加或移除组件」进入对应版本Qt 5.12.123展开MSVC 2017 64-bit勾选Qt Modbus模块4点击下一步完成安装重启 Qt Creator