You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用NModBus时WriteMultipleRegister抛异常及WriteSingleRegister写入异常求助

问题分析与解决方案

一、WriteMultipleRegistersAsync 抛出 IOException 但数据写入成功

原因

每次点击按钮都新建 ModbusController 和 TcpClient,写完后未正确释放连接资源,导致设备主动断开连接时,程序尝试读取响应报文失败;或者频繁创建连接引发设备端的连接处理异常。

解决方案

  1. 复用连接而非每次新建
    初始化 ModbusController 一次(比如在窗体加载时),而非每次点击按钮都创建新实例:

    private ModbusController controller;
    
    private void Form_Load(object sender, EventArgs e) {
        controller = new ModbusController("172.16.100.106", 502);
        // 设置超时时间,避免因设备响应慢导致异常
        controller.ModbusMaster.Transport.ReadTimeout = 5000;
    }
    
    private async Task<bool> WriteToRegister() {
        ushort value = ushort.Parse(txtValue.Text);
        ushort address = (ushort)int.Parse(txtRegister.Text);
        ushort[] data = [value];
    
        try {
            await controller.WriteData(address, data);
            return true;
        } catch (Exception ex) {
            MessageBox.Show(ex.ToString());
            return false;
        }
    }
    

    同时在 ModbusController 中暴露 ModbusMaster 属性,方便设置超时:

    public class ModbusController {
        private TcpClient tcpClient;
        public IModbusMaster ModbusMaster { get; private set; }
    
        public ModbusController(string ipAddress, int port) {
            tcpClient = new TcpClient(ipAddress, port);
            var factory = new ModbusFactory();
            ModbusMaster = factory.CreateMaster(tcpClient);
        }
    
        public async Task WriteData(ushort startAddress, ushort[] data) {
            await ModbusMaster.WriteMultipleRegistersAsync(1, startAddress, data);
        }
    
        // 窗体关闭时释放资源
        public void Dispose() {
            ModbusMaster?.Dispose();
            tcpClient?.Close();
            tcpClient?.Dispose();
        }
    }
    

    记得在窗体关闭时调用 controller.Dispose() 释放资源。

  2. 使用 using 确保资源自动释放
    如果必须每次新建连接,用 using 包裹 ModbusController,确保连接用完即关闭:

    try {
        using (var tempController = new ModbusController("172.16.100.106", 502)) {
            tempController.ModbusMaster.Transport.ReadTimeout = 5000;
            await tempController.WriteData(address, data);
        }
        return true;
    } catch (Exception ex) {
        MessageBox.Show(ex.ToString());
        return false;
    }
    

二、WriteSingleRegister 每次仅修改一位数据

原因

这不是代码问题,而是设备寄存器的特性:

  • 该寄存器可能被设计为位操作寄存器,WriteSingleRegister(功能码0x06)的行为是按位设置而非覆盖整个寄存器值;
  • 设备对单寄存器写入的逻辑是按位累加(比如每次写入的值与当前寄存器值做按位或操作)。

解决方案

  1. 查阅设备手册:确认该寄存器的写入方式,是否支持覆盖式单寄存器写入,或者是否必须使用 WriteMultipleRegisters(功能码0x10)来完整写入寄存器值;
  2. 继续使用 WriteMultipleRegisters:既然该方式能一次性写入目标值,只需解决上述的 IOException 问题即可;
  3. 若必须用单寄存器写入:先读取当前寄存器值,计算出需要修改的位掩码,再写入对应值(但这不符合你一次性写入目标值的需求,仅作为备选)。

内容的提问来源于stack exchange,提问作者jason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:44:51