开发者

modbus rtu通讯发送数据优化方式

目录
  • 前言
  • 一、IO操作中止可能原因分析
    • 1.物理连接问题(传输线问题)
    • 2.串口配置不一致
    • 3.收发方向控制(RS485特有)
    • 4.超时或数据冲突
  • 二、具体实现
    • 1.使用NModbus4库实现串口连接(使用NModbus2.1.0版本)
    • 2.控制台Main函数实现
  • 总结

    前言

    最近,编程遇到一个情况,使用NModbus4库实现通讯并发送数据给别一个设备,报IO操作已中止

    具体情况:使用Modbus Poll发送,在另一个设备的Modbus Poll可以接收到。使用NModbus4库的通讯程序发送,在同一个设备上能接收,在不同的设备上的Modbus Poll不可以接收到。

    一、IO操作中止可能原因分析

    IO操作已中止,可能原因有如下几点:

    1.物理连接问题(传输线问题)

    • 因为使用调试工具能够成功连接并发送数据,排除其原因。

    2.串口配置不一致

    (两台电脑的串口参数(波特率、数据位、停止位、校验位)必须完全一致。)

    • 检查两台电脑串口参数是否一致。

    3.收发方向控制(RS485特有)

    • 1)问题根源:

    RS485是半双工,需通过RTS或DE/RE引脚控制收发切换。若未正确切换,会导致冲突或数据丢失。

    • 2)解决方案:
    // 启用RTS控制(部分USB转485芯片需要)
    serialPort.RtsEnable = true;
    // 或手动控制(根据转换器文档)
    serialPort.Handshake = Handshake.RequestToSend;
    

    添加上述代码的其中一条。

    4.超时或数据冲突

    1)调整超时时间(避免无限等待):

    serialPort.ReadTimeout = 1000; // 毫秒(1秒超时)
    serialPort.WriteTimeout = 1000;
    

    目的:确保两台设备不会同时发送数据(RS485同一时刻只能一个发送方)。

    2)单独设置Modbus超时

    master = ModbusSerialMaster.CreateRtu(serialPort);
    master.Transport.ReadTimeout = 1000; // 单独设置 Modbus 超时 1秒
    

    二、具体实现

    1.使用NModbus4库实现串口连接(使用NModbus2.1.0版本)

    使用NModbus4库,创建RS485通讯类,代码如下:

    using Modbus.Device;
    using System;
    using System.Collections.Generic;
    using System.IO.Ports;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace TestConsole.Serivces
    {
        class RS485Service
        {
            //从站地址
            byte slaveAddress = 1;
    
            public IModbusMaster master;
            public SerialPort serialPort = null;
    
            public RS485Serviceandroid()
            {
    
            }
    
            public void Connect()
            {
                if (serialPort == null)
                {
                    try
                    {
                        //Serial port
                        string portName = "COM6";
                        int baudRahttp://www.devze.comte = 9600;
                        Parity parity = Parity.None;
                        int dataBits = 8;
                        StopBits stopBits = StopBits.One;
                        serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
                        //serialPort.DataReceived += SerialPort_DataRecei编程客栈ved;
    
                        serialPort.RepythonadTimeout = 1000; // 1秒超时
                        serialPort.WriteTimeout = 1000;
                        // 启用RTS控制(部分USB转485芯片需要)
                        serialPort.RtsEnable = true;
    
                        serialPort.Open();
    
                        if (serialPort.IsOpen)
                        {
                            master = ModbusSerialMaster.CreateRtu(serialPort);
                            master.Transport.ReadTimeout = 1000; // 单独设置 Modbus 超时
    
                            Console.WriteLine("串口通讯连接成功!");
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("串口通讯未连接!" + ex.Message);
                    }
                }
            }
    
            #region 地址写值
    
            //写单个线圈(功能码 0x05)
            //如果需要控制单个 IO 点(例如一个继电器),可以使用 WriteSingleCoil 方法
            public void WriteCoil(ushort coilAddress, bool value)
            {
                master.WriteSingleCoil(slaveAddress, coilAddress, value);
            }
    
            //写多个线圈(功能码 0x0F)
            //如果需要同时控制多个 IO 点,可以使用 WriteMultipleCoils 方法
            public void WriteMultCoils(ushort startAddress, bool[] values)
            {
                master.WriteMultipleCoils(slaveAddress, startAddress, values);
            }
    
            //写单个保持寄存器(功能码 0x06)
            //如果需要写入单个寄存器(例如一个数字量输出),可以使用 WriteSingleRegister 方法
            public void WriteRegister(ushort registerAddress, ushort value)
            {
                master.WriteSingleRegister(slaveAddress, registerAddress, value);
            }
    
            //写多个保持寄存器(功能码 0x10)
            //如果需要写入多个寄存器,可以使用 WriteMultipleRegisters 方法
            public void WriteMultRegisters(ushort startAddress, ushort[] values)
            {
                master.WriteMultipleRegisters(slaveAddress, startAddress, values);
            }
    
            #endregion
        }
    }
    
    

    2.控制台Main函数实现

    在Main函数中实现通讯并发送数据,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using TestConsole.Serivces;
    
    namespace TestConsole
    {
      javascript  class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    RS485Service rs485Trans = new RS485Service();
                    rs485Trans.Connect();
    
                    ushort[] tempList = {1,2,3,4};
                    // 写入操作
                    rs485Trans.WriteMultRegisters(0, tempList);
                    Console.WriteLine("写入成功");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("发生错误" + ex.Message);
                }
        
                Console.ReadLine();
            }
        }
    }
    
    

    总结

    IO操作已中止问题,大概率就是IO超时,如上述方法数据传输没有完全过来,可以调整上述超时时间(调大一点)。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜