基于NModbus4库与松下PLC进行Modbus通信

基于NModbus4库与松下PLC进行Modbus通信


一、硬件连接配置(参考)

  1. RS485接线规范

    • PLC RS485端子:+→ 驱动器+-→ 驱动器-
    • 短接PLC的E-端子(部分型号需要)
  2. 波特率拨码开关

    拨码位 1 2 3 4
    波特率 9600 19200 38400 115200
    数据位 8 8 8 8
    停止位 1 1 1 1
    校验位 None Even Odd Mark

二、松下PLC参数设置(参考)

  1. 系统寄存器配置

    地址    | 内容      | 说明
    ----------------------------------
    D1000   | 1         | 通信模式=Modbus RTU
    D1001   | 1         | 站号=1
    D1002   | 9600      | 波特率
    D1003   | 0         | 数据位=8
    D1004   | 0         | 停止位=1
    D1005   | 0         | 校验位=None
    
  2. 通信指令配置

    |--[F145 SEND]--(DT10)  // 从DT10发送数据到Modbus从站
    |--[F146 RECV]--(DT20)  // 接收Modbus从站数据到DT20
    

三、C#通信代码实现(基于NModbus4)

1. 基础通信类(ModbusPLC.cs)

using Modbus.Device;
using System;
using System.IO.Ports;

public class ModbusPLC
{
    private IModbusMaster _master;
    private SerialPort _serialPort;

    public void Connect(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
    {
        _serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
        _serialPort.Open();

        _master = ModbusSerialMaster.CreateRtu(_serialPort);
        _master.Transport.ReadTimeout = 1000;  // 1秒超时
        _master.Transport.WriteTimeout = 1000;
    }

    public ushort[] ReadHoldingRegisters(byte slaveId, ushort startAddress, ushort numRegisters)
    {
        return _master.ReadHoldingRegisters(slaveId, startAddress, numRegisters);
    }

    public void WriteSingleCoil(byte slaveId, ushort coilAddress, bool value)
    {
        _master.WriteSingleCoil(slaveId, coilAddress, value);
    }

    public void Disconnect()
    {
        _master?.Dispose();
        _serialPort?.Close();
    }
}

2. 使用示例(Program.cs)

class Program
{
    static void Main(string[] args)
    {
        var plc = new ModbusPLC();
        try
        {
            plc.Connect("COM3", 9600, Parity.None, 8, StopBits.One);
            
            // 读取保持寄存器(地址40001对应索引0)
            ushort[] data = plc.ReadHoldingRegisters(1, 0, 10);
            Console.WriteLine("读取数据: " + string.Join(", ", data));

            // 写入单个线圈(地址0对应线圈1)
            plc.WriteSingleCoil(1, 0, true);
        }
        finally
        {
            plc.Disconnect();
        }
    }
}

四、关键参数对照表

Modbus地址 NModbus索引 数据类型 松下PLC寄存器
40001 0 UInt16 D1000
40002 1 UInt16 D1001
030001 0 UInt16 A1000
110001 0 Bool C1000

五、异常处理与调试

  1. 常见错误代码

    • InvalidOperationException:通信参数不匹配
    • TimeoutException:超时(检查波特率/接线)
    • IOException:端口被占用
  2. 调试工具推荐

    • Modbus Poll:测试寄存器读写
    • WireShark:抓包分析通信流量
    • PLC监控软件:查看实时寄存器状态

六、高级功能实现

1. 批量读写(示例)

// 读多个保持寄存器
ushort[] readData = plc.ReadHoldingRegisters(1, 0, 100);

// 写多个线圈
bool[] coilValues = Enumerable.Repeat(true, 16).ToArray();
plc.WriteMultipleCoils(1, 0, coilValues);

2. 异步通信

public async Task<ushort[]> AsyncReadHoldingRegisters(byte slaveId, ushort startAddr, ushort count)
{
    return await Task.Run(() => 
        _master.ReadHoldingRegisters(slaveId, startAddr, count));
}

参考代码 使用NMODBUS4开发的与松下PLC进行MODBUS通讯 www.youwenfan.com/contentcnr/112363.html

七、性能优化建议

  1. 连接池管理:复用SerialPort对象减少重连开销
  2. 数据缓存:对频繁读取的寄存器建立内存缓存
  3. 批量操作:合并多个写操作为单次请求
  4. CRC校验:启用硬件CRC加速(需支持CRC指令的PLC)

八、完整项目结构

├── ModbusPLC.sln
├── src/
│   ├── ModbusPLC.Core/          // 核心通信逻辑
│   ├── ModbusPLC.UI/            // 监控界面(WPF)
│   └── ModbusPLC.Tests/         // 单元测试
├── hardware/
│   └── PLC_Config.xlsm          // PLC参数配置模板
└── docs/
    └── Modbus地址对照表.xlsx

 

专注于matlab/simulink,电子电路,编程