当前位置: 代码网 > it编程>编程语言>Java > modbus rtu通讯发送数据优化方式

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

2025年07月23日 Java 我要评论
前言最近,编程遇到一个情况,使用nmodbus4库实现通讯并发送数据给别一个设备,报io操作已中止。具体情况:使用modbus poll发送,在另一个设备的modbus poll可以接收到。使用nmo

前言

最近,编程遇到一个情况,使用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 rs485service()
        {

        }

        public void connect()
        {
            if (serialport == null)
            {
                try
                {
                    //serial port
                    string portname = "com6";
                    int baudrate = 9600;
                    parity parity = parity.none;
                    int databits = 8;
                    stopbits stopbits = stopbits.one;
                    serialport = new serialport(portname, baudrate, parity, databits, stopbits);
                    //serialport.datareceived += serialport_datareceived;

                    serialport.readtimeout = 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
{
    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超时,如上述方法数据传输没有完全过来,可以调整上述超时时间(调大一点)。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com