Panasonic PLC Modbus RTU Communication via NModbus4 in C#
Hardware Wiring & PLC Settings
RS-485 Connection
- Connect the PLC’s RS-485 terminals:
+to converter+,–to converter–. - On some Panasonic models, jumper terminal
Eto–.
DIP-Switch Baud Rate
| Switch 1-4 | Baud | Data bits | Stop bits | Parity |
|---|---|---|---|---|
| 1=ON | 9600 | 8 | 1 | None |
| 2=ON | 19200 | 8 | 1 | Even |
| 3=ON | 38400 | 8 | 1 | Odd |
| 4=ON | 115200 | 8 | 1 | Mark |
PLC Data Regisetrs for Modbus RTU
D1000 = 1 ; Mode = Modbus RTU
D1001 = 1 ; Slave address
D1002 = 9600 ; Baud rate
D1003 = 0 ; 8 data bits
D1004 = 0 ; 1 stop bit
D1005 = 0 ; No parity
C# Implementation with NModbus4
Core Communication Class
using System;
using System.IO.Ports;
using Modbus.Device;
public sealed class PanasonicRtuClient : IDisposable
{
private readonly SerialPort _port;
private IModbusMaster _master;
public PanasonicRtuClient(string com, int baud = 9600,
Parity parity = Parity.None,
int dataBits = 8,
StopBits stopBits = StopBits.One)
{
_port = new SerialPort(com, baud, parity, dataBits, stopBits);
}
public void Open()
{
_port.Open();
_master = ModbusSerialMaster.CreateRtu(_port);
_master.Transport.ReadTimeout = 1000;
_master.Transport.WriteTimeout = 1000;
}
public ushort[] ReadWords(byte slave, ushort start, ushort length)
=> _master.ReadHoldingRegisters(slave, start, length);
public void WriteCoil(byte slave, ushort coil, bool value)
=> _master.WriteSingleCoil(slave, coil, value);
public void WriteWords(byte slave, ushort start, ushort[] data)
=> _master.WriteMultipleRegisters(slave, start, data);
public void Dispose()
{
_master?.Dispose();
_port?.Close();
}
}
Console Sample
class Demo
{
static void Main()
{
using var plc = new PanasonicRtuClient("COM3");
plc.Open();
// Read 10 holding registers starting at 40001 (index 0)
var regs = plc.ReadWords(1, 0, 10);
Console.WriteLine($"Values: {string.Join(", ", regs)}");
// Turn on coil 00001
plc.WriteCoil(1, 0, true);
}
}
| Modbus Address | Zero-based Index | Type | PLC Register | |---|---|---|---| | 40001 | 0 | UInt16 | D1000 | | 40002 | 1 | UInt16 | D1001 | | 30001 | 0 | UInt16 | A1000 | | 10001 | 0 | Bool | C1000 |
Diagnostics & Troubleshoooting
- InvalidOperationException: parameter mismatch.
- TimeoutException: check wiring and baud rate.
- IOException: COM port already in use.
Tools: Modbus Poll for register testing, Wireshark with serial tap, Panasonic FPWIN to live monitoring.
Advanced Patterns
Async Batch Operations
public async Task<ushort[]> ReadWordsAsync(byte slave, ushort start, ushort len)
{
return await Task.Run(() => _master.ReadHoldingRegisters(slave, start, len));
}
Coil Array Write
bool[] coils = Enumerable.Repeat(true, 16).ToArray();
plc.WriteMultipleCoils(1, 0, coils);
Performance Tips
- Reuse the
SerialPortinstance; avoid repeated open/close. - Cache frequently read registers in memory.
- Aggregate multiple writes into a single request.
- Use hardware CRC acceleration when the PLC supports it.
Project Layout Example
PanasonicModbus/
├── src/
│ ├── PanasonicModbus.Core/ # RTU logic
│ ├── PanasonicModbus.UI/ # WPF dashboard
│ └── PanasonicModbus.Tests/
├── config/
│ └── PLC_Settings.xlsx
└── docs/
└── AddressMap.pdf