Communicating with Mitsubishi PLCs via Serial Port in C# for M-Register Access

Implementing M-Register Read/Write for Mitsubishi PLCs Using C# Serial Communication

This guide outlines a method for accessing the M-register (auxiliary relay area) of a Mitsubishi PLC from a C# application using the MELSEC Communication (MC) protocol over a serial connection.

Hardware Setup and Protocol Configuration

Required Hardware

  • RS-485 to USB converter module for PC connection.
  • PLC must be equipped with an RS-485 communication interface (e.g., FX2N-485BD).
  • Wiring: Connect A+ and B- to the converter's RDA+ and RDB- lines respective. A 120Ω terminating resistor is typically required.

Protocol Parameters

The MC protocol requires specific serial port settings:

Baud Rate: 9600 bps
Data Bits: 7
Stop Bits: 2
Parity: Even
Handshake: None

Establishing Serial Communication in C#

Initializing the Serial Port

using System.IO.Ports;

SerialPort mitsubishiPort = new SerialPort("COM3", 9600, Parity.Even, 7, StopBits.Two);
mitsubishiPort.Handshake = Handshake.None;
mitsubishiPort.ReadTimeout = 5000;
mitsubishiPort.WriteTimeout = 5000;

try
{
    mitsubishiPort.Open();
}
catch (Exception ex)
{
    Console.WriteLine($"Port open failed: {ex.Message}");
}

Constructing MC Protocol Frames

The following helper class demonstrates building read and write commands for the M-register.

public class MelsecFrameBuilder
{
    public byte[] BuildReadCommand(int startIndex, int bitCount)
    {
        // STX + device code (ASCII '7','0','7','0','5')
        byte[] baseFrame = { 0x02, 0x37, 0x30, 0x37, 0x30, 0x35, 0x03 };
        // Station number (ASCII '6','0','0','0','0','0','0','0') for station 0
        byte[] station = { 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 };
        // Convert start address to ASCII hex representation
        string addrHex = startIndex.ToString("X4");
        byte[] address = Encoding.ASCII.GetBytes(addrHex);
        // Convert read length (in bytes) to ASCII hex
        int byteLength = (bitCount + 7) / 8;
        string lenHex = byteLength.ToString("X4");
        byte[] length = Encoding.ASCII.GetBytes(lenHex);

        // Combine all parts
        List<byte> command = new List<byte>();
        command.AddRange(baseFrame);
        command.AddRange(station);
        command.AddRange(address);
        command.AddRange(length);

        // Append checksum
        byte checksum = ComputeChecksum(command.ToArray());
        command.Add(checksum);
        return command.ToArray();
    }

    private byte ComputeChecksum(byte[] frameData)
    {
        int sum = 0;
        foreach (byte b in frameData) sum += b;
        return (byte)((~sum + 1) & 0xFF); // Two's complement low byte
    }
}

Performing Read and Write Operations

// Instantiate the frame builder
MelsecFrameBuilder frameBuilder = new MelsecFrameBuilder();

// Reading M0-M15 (16 bits)
byte[] readFrame = frameBuilder.BuildReadCommand(0, 16);
mitsubishiPort.Write(readFrame, 0, readFrame.Length);

// Read response (adjust size based on expected data)
byte[] responseBuffer = new byte[mitsubishiPort.BytesToRead];
mitsubishiPort.Read(responseBuffer, 0, responseBuffer.Length);

// Process response: status bits start after header (e.g., at index 6)
if (responseBuffer.Length >= 6 + 2) // Header + at least 2 data bytes
{
    // Extract data bytes and convert to bits
    byte dataByte1 = responseBuffer[6];
    byte dataByte2 = responseBuffer[7];
    bool m0Status = (dataByte1 & 0x01) != 0;
    bool m15Status = (dataByte2 & 0x80) != 0; // Assuming bits in second byte
}

// Writing to a single M-register (e.g., set M0 ON)
// Frame construction for write is similar but includes data bytes.

Critical Implementation Details

  • Frame Structure: Commands start with STX (0x02) and end with ETX (0x03). Addresses and lengths are sent as ASCII characters.
  • Address Mapping: M-register addresses are converted to thier hexadeciaml ASCII representation.
  • Error Handling: Always implement try-catch blocks for timeouts and I/O exceptions.
  • Data Size: Limit single read/write operations for reliability. Process data in chunks if necessary.

Testing and Troubleshooting

  • Use Mitsubishi's GX Works2 software to verify PLC communication parameters.
  • Employ a serial port monitor (e.g., PuTTY, Tera Term) to capture and inspect raw data frames.
  • Common issues include incorrect station number, missing terminating resistor, or parity mismatch.

Structuring the Application

For production code, encapsulate the communication logic within a dedicated class.

public class MitsubishiPlcCommunicator
{
    private SerialPort _serialPort;
    private MelsecFrameBuilder _frameBuilder;

    public bool EstablishConnection(string comPort)
    {
        _serialPort = new SerialPort(comPort, 9600, Parity.Even, 7, StopBits.Two);
        _serialPort.Open();
        _frameBuilder = new MelsecFrameBuilder();
        return _serialPort.IsOpen;
    }

    public bool[] ReadMRegisters(int startIndex, int count)
    {
        byte[] command = _frameBuilder.BuildReadCommand(startIndex, count);
        _serialPort.Write(command, 0, command.Length);
        // ... read and parse response into a boolean array ...
        return new bool[count]; // placeholder
    }
    // Implement WriteMRegister method similarly.
}

Tags: C# serial communication Mitsubishi PLC MC Protocol M-Register

Posted on Sun, 02 Aug 2026 16:43:54 +0000 by garrisonian14