# QtModbus **Repository Path**: qt-adventure-works/QtModbus ## Basic Information - **Project Name**: QtModbus - **Description**: QtModbus是一个基于Qt框架开发的Modbus通信客户端应用程序,支持Modbus TCP和Modbus RTU两种协议。项目采用MVC架构设计,提供暗黑风格的用户界面,适用于工业自动化、物联网设备通信等场景。 - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-09 - **Last Updated**: 2026-06-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # QtModbus - Modbus通信客户端 ## 项目简介 QtModbus是一个基于Qt框架开发的Modbus通信客户端应用程序,支持Modbus TCP和Modbus RTU两种协议。项目采用MVC架构设计,提供暗黑风格的用户界面,适用于工业自动化、物联网设备通信等场景。 ## 技术框架 ### 核心技术栈 - **Qt Framework**: 5.12.9 (支持C++14标准) - **Qt Modules**: - `core`: Qt核心模块 - `gui`: GUI图形界面模块 - `widgets`: 窗口部件模块 - `serialbus`: Modbus串行总线模块 - `serialport`: 串口通信模块 - **编译器**: MSVC (Microsoft Visual C++) - **架构模式**: MVC (Model-View-Controller) - **多线程**: 使用QThread实现工作线程,避免阻塞UI ### 支持的Modbus功能 - 读取线圈 (功能码 0x01) - 读取离散输入 (功能码 0x02) - 读取保持寄存器 (功能码 0x03) - 读取输入寄存器 (功能码 0x04) - 写入单个线圈 (功能码 0x05) - 写入单个寄存器 (功能码 0x06) - 写入多个线圈 (功能码 0x0F) - 写入多个寄存器 (功能码 0x10) ### Modbus数据类型说明 | 数据类型 | 功能码 | 读写权限 | 典型用途 | | ------------------------ | ------------- | ---- | --------- | | Coils(线圈) | 01读/05写单/15写多 | 可读可写 | 开关量输出 | | Discrete Inputs(离散输入) | 02 | 只读 | 开关量输入 | | Holding Registers(保持寄存器) | 03读/06写单/16写多 | 可读可写 | 参数设置、输出值 | | Input Registers(输入寄存器) | 04 | 只读 | 传感器数据、测量值 | ## 项目结构 ``` QtModbus/ ├── QtModbus.pro # Qt项目文件 ├── main.cpp # 程序入口 ├── modbusconfig.h # Modbus配置和宏定义 ├── build.bat # Windows编译脚本 │ ├── config/ # 配置文件目录 │ └── 编译命令.md # 编译相关说明 │ ├── model/ # 数据模型层 (MVC中的Model) │ ├── modbusmodel.h # 数据模型头文件 │ └── modbusmodel.cpp # 数据模型实现 │ ├── view/ # 视图层 (MVC中的View) │ ├── mainwindow.h # 主窗口头文件 │ ├── mainwindow.cpp # 主窗口实现 │ └── mainwindow.ui # Qt Designer界面文件 │ ├── controller/ # 控制器层 (MVC中的Controller) │ ├── modbuscontroller.h # 控制器头文件 │ └── modbuscontroller.cpp # 控制器实现 │ ├── worker/ # 工作线程层 │ ├── modbusworker.h # 工作线程头文件 │ └── modbusworker.cpp # 工作线程实现 │ └── x64/ # 编译输出目录 ├── debug/ # Debug版本输出 │ └── QtModbusd.exe # Debug可执行文件 └── release/ # Release版本输出 ``` ### 架构说明 #### Model层 (model/) - **ModbusModel**: 负责管理Modbus通信相关的数据 - 连接参数管理(地址、端口、波特率、从站ID等) - 寄存器数据存储(保持寄存器、输入寄存器) - 线圈数据存储(线圈、离散输入) - 连接状态管理 #### View层 (view/) - **MainWindow**: 提供用户交互界面 - 暗黑风格UI设计 - 连接配置界面 - 数据读写操作按钮 - 日志显示窗口 - 数据显示区域 #### Controller层 (controller/) - **ModbusController**: 协调Model和Worker之间的交互 - 单例模式设计 - 管理工作线程 - 请求队列管理 - 信号槽机制通信 #### Worker层 (worker/) - **ModbusWorker**: 在独立线程中执行Modbus通信操作 - 避免阻塞主界面线程 - 支持TCP和RTU两种协议 - 异步通信处理 - 错误处理和重试机制 ## 编译和运行 ### 环境要求 - Qt 5.12.9 或更高版本 - Microsoft Visual C++ 编译器 - Windows操作系统 ### 编译步骤 #### 方法1: 使用Qt Creator 1. 使用Qt Creator打开 `QtModbus.pro` 文件 2. 选择编译配置 (Debug/Release) 3. 点击构建按钮进行编译 #### 方法2: 使用命令行 ```bash # 运行编译脚本 build.bat # 或手动执行 qmake QtModbus.pro nmake # 或 mingw32-make ``` ### 运行程序 ```bash # Debug版本 cd x64/debug QtModbusd.exe # Release版本 cd x64/release QtModbus.exe ``` ## 仿真测试 ### 推荐的第三方测试工具 #### 1. Modbus Poll + Modbus Slave (推荐 - 专业调试工具) **特点**: 功能完善、界面友好、支持TCP和RTU协议 **下载地址**: **工具说明**: - **Modbus Poll**: 模拟Modbus主站(Master),用于测试从站设备 - **Modbus Slave**: 模拟Modbus从站(Slave),用于测试主站设备 - 支持30天免费试用 **使用步骤**: 1. 下载并安装Modbus Slave 2. 启动程序,选择连接类型 (TCP/IP或Serial) 3. 配置从站参数: - 从站ID: 1 (与QtModbus配置一致) - TCP端口: 60000 (TCP模式) - 串口: COM2, 波特率: 115200 (RTU模式) 4. 在寄存器窗口中设置测试数据 5. 点击"Connection" -> "Connect"启动从站服务 6. 使用QtModbus连接测试 #### 2. Modbus Simulator (免费) **特点**: 免费开源、支持多从站模拟 **下载地址**: **使用步骤**: 1. 下载并安装Modbus Simulator 2. 配置从站参数 3. 启动TCP或RTU从站 4. 使用QtModbus连接测试 #### 3. pymodbus (Python库 - 免费) **特点**: 完全免费、可编程、适合自动化测试 **安装步骤**: ```bash pip install pymodbus ``` **创建测试从站脚本** (test\_slave.py): ```python from pymodbus.server import StartAsyncTcpServer from pymodbus.datastore import ModbusServerContext, ModbusSlaveContext from pymodbus.datastore import ModbusSequentialDataBlock # 创建数据存储 store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [0]*100), co=ModbusSequentialDataBlock(0, [0]*100), hr=ModbusSequentialDataBlock(0, [0]*100), ir=ModbusSequentialDataBlock(0, [0]*100) ) context = ModbusServerContext(slaves=store, single=True) # 启动TCP从站 StartAsyncTcpServer(context=context, address=("127.0.0.1", 502)) ``` **运行测试从站**: ```bash python test_slave.py ``` #### 4. libmodbus (C库 - 免费) **特点**: 轻量级、高性能、跨平台 **下载地址**: **使用步骤**: 1. 下载并编译libmodbus 2. 使用示例代码创建从站 3. 编译并运行从站程序 4. 使用QtModbus连接测试 ### 测试流程 #### TCP模式测试 1. **启动测试从站**: - 使用Modbus Slave或其他工具启动Modbus TCP从站 - 监听地址: 127.0.0.1:60000 - 从站ID: 1 2. **配置QtModbus**: - 协议类型: TCP - IP地址: 127.0.0.1 - 端口: 502 - 从站ID: 1 3. **执行测试**: - 点击"连接"按钮 - 测试读取保持寄存器 (地址: 0, 数量: 10) - 测试读取线圈 (地址: 0, 数量: 10) - 测试写入单个寄存器 (地址: 0, 值: 1234) - 测试写入单个线圈 (地址: 0, 值: true) - 测试写入多个寄存器 - 测试写入多个线圈 4. **验证结果**: - 在QtModbus日志窗口查看操作结果 - 在测试工具中验证数据是否正确更新 #### RTU模式测试 1. **准备虚拟串口**: - 使用com0com或Virtual Serial Port Driver创建虚拟串口对 (如COM1-COM2) - 下载地址: - com0com: - Virtual Serial Port Driver: 2. **启动测试从站**: - 使用Modbus Slave或其他工具启动Modbus RTU从站 - 串口: COM1 - 波特率: 115200 - 数据位: 8 - 停止位: 1 - 校验位: None - 从站ID: 1 3. **配置QtModbus**: - 协议类型: RTU - 串口: COM2 - 波特率: 9600 - 数据位: 8 - 停止位: 1 - 校验位: None - 从站ID: 1 4. **执行测试**: - 按照TCP模式的测试步骤进行测试 ### 测试检查清单 - [ ] 成功连接到从站设备 - [ ] 成功读取保持寄存器 - [ ] 成功读取输入寄存器 - [ ] 成功读取线圈 - [ ] 成功读取离散输入 - [ ] 成功写入单个寄存器 - [ ] 成功写入单个线圈 - [ ] 成功写入多个寄存器 - [ ] 成功写入多个线圈 - [ ] 正确处理连接失败情况 - [ ] 正确处理超时情况 - [ ] 正确处理非法地址错误 - [ ] 日志信息正确显示 ## 配置说明 ### 默认配置参数 - TCP端口: 60000 - RTU波特率: 115200 - 从站ID: 1 - 超时时间: 1000ms - 重试次数: 3次 - 最大寄存器数量: 125 - 最大线圈数量: 2000 ### 地址范围 - 寄存器地址: 0-65535 - 线圈地址: 0-65535 - 从站ID: 1-247 ## 代码规范 - 遵循Qt C++编码规范 - 使用Doxygen风格的注释 - 函数大括号放在下一行 - 不添加不必要的代码注释 - 所有日志信息使用中文 ## 版本信息 - 当前版本: 1.0.0 - 最后更新: 2026-03-03 ## 已知问题与解决方案 ### Modbus RTU模式多线程问题 **问题描述**: 在Qt 5.8 - 5.12版本中,使用QModbusRtuSerialMaster进行多线程操作时,可能会出现以下问题: - 程序随机卡死或崩溃 - 报错 `ASSERT failure in processQueue: "response timer active"` - 报错 `ASSERT failure in processQueue: "unexpected state:"` **影响范围**: 仅影响 **RTU串口模式**,TCP模式不受影响 **根本原因**: QModbusRtuSerialMaster类内部定时器状态管理存在缺陷,这是Qt官方的Bug,在Qt 5.13版本中已修复。 **解决方案**: 1. **推荐方案:升级Qt版本** - 升级到Qt 5.13或更高版本(官方已修复此Bug) 2. **临时解决方案** - 本项目已在代码中实现RTU模式请求间隔控制(≥500ms) - TCP模式无此限制,可快速连续请求 3. **替代方案** - 如条件允许,使用TCP模式代替RTU模式 **代码改进**: - 本项目已实现了以下改进: - 添加了 `initWorker` 方法确保 ModbusWorker 对象被正确移动到子线程 - 修改了 `createModbusClient` 方法确保 Modbus 客户端对象在子线程中创建 - RTU模式下自动控制请求间隔≥500ms,避免触发Bug - TCP模式无请求间隔限制,可快速连续操作 - 使用QEventLoop同步等待方式处理请求 **参考链接**: ## 许可证 本项目仅供学习和研究使用。 ## 联系方式 如有问题或建议,请联系项目维护者。