델타 PLC 와의 Modbus 통신을 위한 C # 기반 호스트 인스턴스

Paid ¥8.99Paid ¥8.99

该内容已接入现有会員/有料系统,解锁后可完全な情報を見る或添付ファイルのダウンロード。

表示解锁方式
델타 PLC 와의 Modbus 통신을 위한 C # 기반 호스트 인스턴스

台達(Delta)PLC是国内工业自動化领域应用最广泛的PLCブランド之一,サポートModbus RTU和Modbus TCP通信プロトコル。C#作为Windowsプラットフォームトップマシン开发的主流语言,与台達PLC的Modbus通讯是工业自動化项目中的常见需求。本記事提供完全的C#トップマシン与台達PLC Modbus通信实例,包括连接管理、レジスタ読み書き、データの解析、断线再接続、多デバイス管理以及Windows Forms界面サンプル。

一、台達PLC Modbus通讯概述

1.1 台達PLCサポート的ModbusFunction

function codeFunction台達PLC对应エリア
0x01リードコイルを読むM(辅助继电器)、Y(出力继电器)
0x02read discrete inputsX(入力继电器)
0x03read holding registersD(データ·レジスタ)
0x05write single coilM、Y
0x06write single registerD
0x0Fwrite multiple coilsM、Y
0x10write multiple registersD

1.2 台達PLCアドレスマッピング

台達PLC的Modbusアドレス与内部软元件的对应关系(以DVP系列为例):

软元件Modbusaddress(decimal)説明
D0-D99990-9999データ·レジスタ,レジスタを保持する。
M0-M99990-9999辅助继电器,コイル
Y0-Y2550-255(偏移2048)出力继电器,コイル
X0-X2550-255(偏移2048)入力继电器,ショップ型入力
S0-S9990-999(偏移4096)ステータス继电器,コイル
T0-T255触点1024-1279タイマータイマー。触点ステータス,コイル(function code01/05)
C0-C255触点1536-1791カウンター·カウンター触点ステータス,コイル(function code01/05)
T/Ccurrent value视型号而定部分型号サポート経由Dレジスタマップ読み取り,需查阅对应手册

1.3 通信パラメータの設定

  • Modbus TCP:PLC IPaddress + ポート502,駅からの住所デフォルト1
  • Modbus RTU(COM1):9600bps,8データ·ビット,検証なし。,1ストップ·ビット(デフォルト)
  • Modbus RTU(COM2):9600bps,8データ·ビット,検証なし。,1ストップ·ビット(デフォルト)
  • slave address:可在PLC中に設置。,デフォルト1
  • 通信プロトコル:需在PLCプログラミング软件中に設置。为Modbus RTU Slave或Modbus TCP

二、C# Modbus通讯类実装

2.1 Modbus TCPクライアント側は类

using System;
using System.Net.Sockets;
using System.Threading;

namespace DeltaPlcModbus
{
    public class ModbusTcpClient : IDisposable
    {
        private TcpClient _client;
        private NetworkStream _stream;
        private ushort _transactionId = 0;
        private readonly object _lock = new object();

        public string IpAddress { get; }
        public int Port { get; }
        public byte SlaveId { get; set; } = 1;
        public int Timeout { get; set; } = 3000;
        public bool IsConnected => _client?.Connected ?? false;

        public ModbusTcpClient(string ip, int port = 502)
        {
            IpAddress = ip;
            Port = port;
        }

        /// <summary>
        /// connectPLC(带重试)
        /// </summary>
        public bool Connect(int retryCount = 3)
        {
            for (int i = 0; i < retryCount; i++)
            {
                try
                {
                    _client = new TcpClient();
                    _client.ReceiveTimeout = Timeout;
                    _client.SendTimeout = Timeout;
                    _client.Connect(IpAddress, Port);
                    _stream = _client.GetStream();
                    Console.WriteLine($"接続しましたPLC:{IpAddress}:{Port}");
                    return true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"接続の失敗(No.{i + 1}次):{ex.Message}");
                    Thread.Sleep(1000);
                }
            }
            return false;
        }

        /// <summary>
        /// 切断する
        /// </summary>
        public void Disconnect()
        {
            _stream?.Close();
            _client?.Close();
            _client = null;
            _stream = null;
        }

        /// <summary>
        /// read holding registers(function code03)- readDregister
        /// </summary>
        public ushort[] ReadHoldingRegisters(ushort startAddr, ushort count)
        {
            lock (_lock)
            {
                byte[] request = BuildReadRequest(0x03, startAddr, count);
                byte[] response = SendAndReceive(request);

                if (response[7] != 0x03)
                    throw new ModbusException(response[7], response[8]);

                byte byteCount = response[8];
                ushort[] result = new ushort[byteCount / 2];
                for (int i = 0; i < result.Length; i++)
                {
                    result[i] = (ushort)((response[9 + i * 2] << 8) | response[9 + i * 2 + 1]);
                }
                return result;
            }
        }

        /// <summary>
        /// リードコイルを読む(function code01)- readM/YRelay
        /// </summary>
        public bool[] ReadCoils(ushort startAddr, ushort count)
        {
            lock (_lock)
            {
                byte[] request = BuildReadRequest(0x01, startAddr, count);
                byte[] response = SendAndReceive(request);

                if (response[7] != 0x01)
                    throw new ModbusException(response[7], response[8]);

                byte byteCount = response[8];
                bool[] result = new bool[count];
                for (int i = 0; i < count; i++)
                {
                    result[i] = (response[9 + i / 8] & (1 << (i % 8))) != 0;
                }
                return result;
            }
        }

        /// <summary>
        /// read discrete inputs(function code02)- readX入力
        /// </summary>
        public bool[] ReadDiscreteInputs(ushort startAddr, ushort count)
        {
            lock (_lock)
            {
                byte[] request = BuildReadRequest(0x02, startAddr, count);
                byte[] response = SendAndReceive(request);

                if (response[7] != 0x02)
                    throw new ModbusException(response[7], response[8]);

                byte byteCount = response[8];
                bool[] result = new bool[count];
                for (int i = 0; i < count; i++)
                {
                    result[i] = (response[9 + i / 8] & (1 << (i % 8))) != 0;
                }
                return result;
            }
        }

        /// <summary>
        /// write single register(function code06)- 写Dregister
        /// </summary>
        public void WriteSingleRegister(ushort addr, ushort value)
        {
            lock (_lock)
            {
                byte[] request = new byte[12];
                BuildMBAPHeader(request, 6);
                request[7] = 0x06;
                request[8] = (byte)(addr >> 8);
                request[9] = (byte)(addr & 0xFF);
                request[10] = (byte)(value >> 8);
                request[11] = (byte)(value & 0xFF);

                byte[] response = SendAndReceive(request);
                if (response[7] != 0x06)
                    throw new ModbusException(response[7], response[8]);
            }
        }

        /// <summary>
        /// write single coil(function code05)- 写M/YRelay
        /// </summary>
        public void WriteSingleCoil(ushort addr, bool value)
        {
            lock (_lock)
            {
                byte[] request = new byte[12];
                BuildMBAPHeader(request, 6);
                request[7] = 0x05;
                request[8] = (byte)(addr >> 8);
                request[9] = (byte)(addr & 0xFF);
                request[10] = (byte)(value ? 0xFF : 0x00);
                request[11] = 0x00;

                byte[] response = SendAndReceive(request);
                if (response[7] != 0x05)
                    throw new Mod bus Ex ception (res ponse [7 ], response [8]);
            }
        }

        /// >
        /// 쓰 기 다 중 레 지 스터 (기 능 코드 16) - D 레 지 스터 를 대 량 쓰 기
        /// >
        public vo id Write M ulti ple Reg ister s (ush ort start Add r , ush ort [ ] values)
        {
            잠 금 (_ lock)
            {
                by te by te Co unt = (byte) (valu es . Leng th * 2) ;
                by te [ ] request = new by te [ 13 + by te Co unt ];
                Bu ild M BA P He ader (re quest , (ush ort) ( 7 + by te Co unt));
                요청 [7] = 0 x 10 ;
                request[8] = (byte)(startAddr 
                request[9] = (byte)(startAddr 
                request[10] = (byte)(values.Length 
                request[11] = (byte)(values.Length 
                request [11] = by te Co unt ;

                for (int i = 0; i 
                {
                    request[13 + i * 2] = (byte)(values[i] 
                    request[13 + i * 2 + 1] = (byte)(values[i] 
                }

                by te [ ] response = Send And Re ce ive (re quest);
                if (res ponse [7] ! =) 0 x 10)
                    throw new Mod bus Ex ception (res ponse [7 ], response [8]);
            }
        }

        /// >
        / / / 여러 코 일 쓰 기 (기 능 코드 15) - M / Y 릴 레이 대 량 쓰 기
        /// >
        public vo id Write M ulti ple Co ils (ush ort start Add r , bool [ ] values)
        {
            잠 금 (_ lock)
            {
                by te by te Co unt = (byte) (( values . Leng th + 7) / 8);
                by te [ ] request = new by te [ 13 + by te Co unt ];
                Bu ild M BA P He ader (re quest , (ush ort) ( 7 + by te Co unt));
                요청 [7] = 0 x 0 F ;
                request[8] = (byte)(startAddr 
                request[9] = (byte)(startAddr 
                request[10] = (byte)(values.Length 
                request[11] = (byte)(values.Length 
                request [11] = by te Co unt ;
                
                for (int i = 0; i 
                {
                    if (val ue [ i ])
                        요청 [ 13 + i / 8 ]|= (바 이트) ( 1 (i % 8));<<
                }
                
                by te [ ] response = Send And Re ce ive (re quest);
                if (res ponse [7] ! =) 0 x 0 F)
                    throw new Mod bus Ex ception (res ponse [7 ], response [8]);
            }
        }
        
        읽기 요청 만들기
        private by te [ ] Bu ild Read Re quest (byte fuk C ode , ush ort start Add r , ush ort count)
        {
            by te [ ] request = new by te [12] ;
            Bu ild M BA P He ader (re quest , 6) ;
            request [7] = function C ode ;
            request[8] = (byte)(startAddr 
            request[9] = (byte)(startAddr 
            request[10] = (byte)(count 
            request[11] = (byte)(count 
            반환 요청 ;
        }

        / / M BA P 헤 더 생성
        private vo id Bu ild M BA P He ader (byte [ ] bu ffer , ush ort length)
        {
            _ tr ansa ction Id ++ ;
            buffer[0] = (byte)(_transactionId 
            buffer[1] = (byte)(_transactionId 
            버 퍼 [2] = 0 x 00 ;
            bu ffer [3] = 0 x 00 ;
            buffer[4] = (byte)(length 
            buffer[5] = (byte)(length 
            bu ffer [6] = Sla ve Id ;
        }

        보내 기 및 수신 하기
        private by te [ ] Send And Re ce ive (byte [ ] request)
        {
            if (_ stream == null )||  !_클 라이언 트 . 접속 됨)
                throw new In valid O per ation Ex ception (" P LC 에 연결 되지 않 음 ")

            _ stream . Write (re quest , 0, request . Leng th);
            _ stream . fl ush () ;

            by te [ ] bu ffer = new by te [2 60 ];
            int by tes Read = _ stream . Read (bu ffer , 0, bu ffer . Leng th);

            by te [ ] response = new by te [ byt es Read ];
            Ar ray . Copy (bu ffer , response , by tes Read);
            응답 을 반환 합니다 ;
        }

        public vo id Dis pose ()
        {
            연결 끊 기 ();
        }
    }

    public 클래 스 ModbusException : Exception
    {
        public byte FunctionCode { get; }
        public byte ExceptionCode { get; }

        public ModbusException(byte funcCode, byte exceptionCode)
            : base($"Modbus異常:function code=0x{funcCode:X2},Exception Code=0x{exceptionCode:X2}")
        {
            FunctionCode = funcCode;
            ExceptionCode = exceptionCode;
        }
    }
}

2.2 台達PLC专用操作类

using System;

namespace DeltaPlcModbus
{
    /// <summary>
    /// 台達PLC专用操作类,封装D/M/X/Y软元件的読み書き
    /// </summary>
    public class DeltaPlcClient
    {
        private readonly ModbusTcpClient _modbus;

        public DeltaPlcClient(string ip, int port = 502, byte slaveId = 1)
        {
            _modbus = new ModbusTcpClient(ip, port);
            _modbus.SlaveId = slaveId;
        }

        public bool Connect() => _modbus.Connect();
        public void Disconnect() => _modbus.Disconnect();
        public bool IsConnected => _modbus.IsConnected;

        /// <summary>
        /// readDregister value
        /// </summary>
        public ushort ReadD(int address)
        {
            return _modbus.ReadHoldingRegisters((ushort)address, 1)[0];
        }

        /// <summary>
        /// バッチ読み取りDregister
        /// </summary>
        public ushort[] ReadD(int startAddress, int count)
        {
            return _modbus.ReadHoldingRegisters((ushort)startAddress, (ushort)count);
        }

        /// <summary>
        /// 写入Dregister value
        /// </summary>
        public void WriteD(int address, ushort value)
        {
            _modbus.WriteSingleRegister((ushort)address, value);
        }

        /// <summary>
        /// 一括書き込みき込み入Dregister
        /// </summary>
        public void WriteD(int startAddress, ushort[] values)
        {
            _modbus.WriteMultipleRegisters((ushort)startAddress, values);
        }

        /// <summary>
        /// read32ビット整数(占用2个Dregister)
        /// </summary>
        public int ReadD32(int startAddress)
        {
            ushort[] regs = _modbus.ReadHoldingRegisters((ushort)startAddress, 2);
            return (regs[0] << 16) | regs[1];
        }

        /// <summary>
        /// read32ビット浮動小数点数(占用2个Dregister,ABCDビッグエンディアン序)
        /// </summary>
        public float ReadDFloat(int startAddress)
        {
            ushort[] regs = _modbus.ReadHoldingRegisters((ushort)startAddress, 2);
            // ABCDビッグエンディアン序:前の単語。,前の高さ。
            uint bits = ((uint)regs[0] << 16) | regs[1];
            byte[] bytes = BitConverter.GetBytes(bits);
            // BitConverter.GetBytes戻る的是リトルエンディアン序配列,需要反转
            if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
            return BitConverter.ToSingle(bytes, 0);
        }
        
        /// <summary>
        /// read32ビット浮動小数点数(CDAB言葉の交換序)
        /// </summary>
        public float ReadDFloatCDAB(int startAddress)
        {
            ushort[] regs = _modbus.ReadHoldingRegisters((ushort)startAddress, 2);
            // CDAB:前に低い言葉。,前の高さ。
            uint bits = ((uint)regs[1] << 16) | regs[0];
            byte[] bytes = BitConverter.GetBytes(bits);
            if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
            return BitConverter.ToSingle(bytes, 0);
        }

        /// <summary>
        /// readM辅助继电器ステータス
        /// </summary>
        public bool ReadM(int address)
        {
            return _modbus.ReadCoils((ushort)address, 1)[0];
        }

        /// <summary>
        /// バッチ読み取りM辅助继电器
        /// </summary>
        public bool[] ReadM(int startAddress, int count)
        {
            return _modbus.ReadCoils((ushort)startAddress, (ushort)count);
        }

        /// <summary>
        /// 写入M辅助继电器
        /// </summary>
        public void WriteM(int address, bool value)
        {
            _modbus.WriteSingleCoil((ushort)address, value);
        }

        /// <summary>
        /// readX入力继电器ステータス
        /// 注意:X入力在台達PLC中Modbusアドレス偏移为2048
        /// </summary>
        public bool ReadX(int address)
        {
            return _modbus.ReadDiscreteInputs((ushort)(address + 2048), 1)[0];
        }

        /// <summary>
        /// readY出力继电器ステータス
        /// 注意:Y出力在台達PLC中Modbusアドレス偏移为2048
        /// </summary>
        public bool ReadY(int address)
        {
            return _modbus.ReadCoils((ushort)(address + 2048), 1)[0];
        }

        /// <summary>
        /// 写入Y出力继电器
        /// </summary>
        public void WriteY(int address, bool value)
        {
            _modbus.WriteSingleCoil((ushort)(address + 2048), value);
        }

        /// <summary>
        /// 読み取りタイマータイマー。当前值(Tregister,偏移1024)
        /// </summary>
        public ushort ReadT(int address)
        {
            return _modbus.ReadHoldingRegisters((ushort)(address + 1024), 1)[0];
        }

        /// <summary>
        /// 読み取りカウンター·カウンター当前值(Cregister,偏移1536)
        /// </summary>
        public ushort ReadC(int address)
        {
            return _modbus.ReadHoldingRegisters((ushort)(address + 1536), 1)[0];
        }
    }
}

三、完全使用例の例

using System;
using System.Threading;

namespace DeltaPlcModbus
{
    class Program
    {
        static void Main(string[] args)
        {
            // 作成台達PLCクライアント側は
            var plc = new DeltaPlcClient("192.168.1.10", 502, slaveId: 1);

            try
            {
                // connectPLC
                if (!plc.Connect())
                {
                    Console.WriteLine("无法连接到PLC");
                    return;
                }
                Console.WriteLine("PLC接続成功です。!\n");

                // 1. readDregister
                Console.WriteLine("=== readDregister ===");
                ushort d0 = plc.ReadD(0);
                ushort d1 = plc.ReadD(1);
                ushort d2 = plc.ReadD(2);
                Console.WriteLine($"D0 = {d0}");
                Console.WriteLine($"D1 = {d1}");
                Console.WriteLine($"D2 = {d2}");

                // バッチ読み取り
                ushort[] dValues = plc.ReadD(0, 10);
                Console.WriteLine("\nD0-D9:");
                for (int i = 0; i < dValues.Length; i++)
                {
                    Console.WriteLine($"  D{i} = {dValues[i]}");
                }

                // 2. 写入Dregister
                Console.WriteLine("\n=== 写入Dregister ===");
                plc.WriteD(10, 1234);
                Console.WriteLine("D10 写入 1234");
                ushort check = plc.ReadD(10);
                Console.WriteLine($"D10 回读 = {check}");

                // 一括書き込みき込み入
                plc.WriteD(20, new ushort[] { 100, 200, 300, 400, 500 });
                Console.WriteLine("D20-D24 一括書き込みき込み入完成");

                // 3. read32ビット·データ
                Console.WriteLine("\n=== read32ビット·データ ===");
                int d32 = plc.ReadD32(0);
                Console.WriteLine($"D0-D1(32ビット整数)= {d32}");

                // 4. readMRelay
                Console.WriteLine("\n=== readMRelay ===");
                bool m0 = plc.ReadM(0);
                bool m1 = plc.ReadM(1);
                Console.WriteLine($"M0 = {(m0 ? "ON" : "OFF")}");
                Console.WriteLine($"M1 = {(m1 ? "ON" : "OFF")}");

                // バッチ読み取り
                bool[] mValues = plc.ReadM(0, 8);
                Console.WriteLine("\nM0-M7:");
                for (int i = 0; i < mValues.Length; i++)
                {
                    Console.WriteLine($"  M{i} = {(mValues[i] ? "ON" : "OFF")}");
                }

                // 5. 写入MRelay
                Console.WriteLine("\n=== 写入MRelay ===");
                plc.WriteM(0, true);
                Console.WriteLine("M0 置为 ON");
                Thread.Sleep(500);
                plc.WriteM(0, false);
                Console.WriteLine("M0 置为 OFF");

                // 6. readX入力
                Console.WriteLine("\n=== readX入力 ===");
                bool x0 = plc.ReadX(0);
                bool x1 = plc.ReadX(1);
                Console.WriteLine($"X0 = {(x0 ? "ON" : "OFF")}");
                Console.WriteLine($"X1 = {(x1 ? "ON" : "OFF")}");

                // 7. readY出力
                Console.WriteLine("\n=== readY出力 ===");
                bool y0 = plc.ReadY(0);
                Console.WriteLine($"Y0 = {(y0 ? "ON" : "OFF")}");

                // 8. 控制Y出力
                Console.WriteLine("\n=== 控制Y出力 ===");
                plc.WriteY(0, true);
                Console.WriteLine("Y0 置为 ON");
                Thread.Sleep(1000);
                plc.WriteY(0, false);
                Console.WriteLine("Y0 置为 OFF");

                // 9. 読み取りタイマータイマー。/カウンター·カウンター触点ステータス
                Console.WriteLine("\n=== 読み取りタイマータイマー。/カウンター·カウンター触点 ===");
                bool t0 = plc.ReadTContact(0);
                bool c0 = plc.ReadCContact(0);
                Console.WriteLine($"T0 触点 = {(t0 ? "ON" : "OFF")}");
                Console.WriteLine($"C0 触点 = {(c0 ? "ON" : "OFF")}");
                Console.WriteLine("注:タイマータイマー。/カウンター·カウンター当前值请查阅对应型号手册的Modbusマッピング");

                // 10. 持续モニタリング(10秒)
                Console.WriteLine("\n=== 持续モニタリングD0-D3(10秒)===");
                for (int i = 0; i < 10; i++)
                {
                    ushort[] monitor = plc.ReadD(0, 4);
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] D0={monitor[0]}, D1={monitor[1]}, D2={monitor[2]}, D3={monitor[3]}");
                    Thread.Sleep(1000);
                }
            }
            catch (ModbusException ex)
            {
                Console.WriteLine($"Modbus異常:{ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"系统異常:{ex.Message}");
            }
            finally
            {
                plc.Disconnect();
                Console.WriteLine("\nPLC连接已关闭");
            }

            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();
        }
    }
}

四、Windows Formsトップマシン界面サンプル

using System;
using System.Windows.Forms;
using System.Threading;

namespace DeltaPlcModbus
{
    public partial class MainForm : Form
    {
        private DeltaPlcClient _plc;
        private Thread _monitorThread;
        private volatile bool _monitoring = false;

        public MainForm()
        {
            InitializeComponent();
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                _plc = new DeltaPlcClient(txtIp.Text, int.Parse(txtPort.Text), byte.Parse(txtSlaveId.Text));
                if (_plc.Connect())
                {
                    lblStatus.Text = "Connected";
                    lblStatus.ForeColor = System.Drawing.Color.Green;
                    btnConnect.Enabled = false;
                    btnDisconnect.Enabled = true;
                    _monitoring = true;
                    _monitorThread = new Thread(MonitorLoop);
                    _monitorThread.IsBackground = true;
                    _monitorThread.Start();
                }
                else
                {
                    MessageBox.Show("接続の失敗!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"连接異常:{ex.Message}");
            }
        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            _monitoring = false;
            _plc?.Disconnect();
            lblStatus.Text = "Not connected";
            lblStatus.ForeColor = System.Drawing.Color.Red;
            btnConnect.Enabled = true;
            btnDisconnect.Enabled = false;
        }

        private void MonitorLoop()
        {
            while (_monitoring && _plc.IsConnected)
            {
                try
                {
                    // readD0-D9
                    ushort[] values = _plc.ReadD(0, 10);
                    // readM0-M7
                    bool[] mValues = _plc.ReadM(0, 8);

                    // 更新UI(跨线程调用)
                    this.Invoke(new Action(() =>
                    {
                        txtD0.Text = values[0].ToString();
                        txtD1.Text = values[1].ToString();
                        txtD2.Text = values[2].ToString();
                        txtD3.Text = values[3].ToString();
                        lblM0.Text = mValues[0] ? "ON" : "OFF";
                        lblM1.Text = mValues[1] ? "ON" : "OFF";
                        lblM2.Text = mValues[2] ? "ON" : "OFF";
                        lblM3.Text = mValues[3] ? "ON" : "OFF";
                    }));
                }
                catch
                {
                    // Read failed,忽略
                }
                Thread.Sleep(500);
            }
        }

        private void btnWriteD_Click(object sender, EventArgs e)
        {
            try
            {
                int addr = int.Parse(txtWriteAddr.Text);
                ushort value = ushort.Parse(txtWriteValue.Text);
                _plc.WriteD(addr, value);
                MessageBox.Show($"D{addr} 写入 {value} 成功");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"写入失敗:{ex.Message}");
            }
        }

        private void btnM0On_Click(object sender, EventArgs e)
        {
            _plc.WriteM(0, true);
        }

        private void btnM0Off_Click(object sender, EventArgs e)
        {
            _plc.WriteM(0, false);
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            _monitoring = false;
            _plc?.Disconnect();
            base.OnFormClosing(e);
        }
    }
}

五、よくある質問与トラブルシューティング

5.1 接続の失敗

  • チェックIPaddress:ConfirmPLC的IPアドレス設定正确,与电脑在同一网段
  • チェック矶钓:台達PLC Modbus TCPデフォルト矶钓502,確認未被ファイアウォール拦截
  • チェックネットワークケーブル:確認ネットワークケーブル连接正常,PLC网口指示灯亮
  • チェックPLC設定:在ISPSoft中確認PLC已有効Modbus TCP通讯
  • Ping测试:在命令行中ping PLC的IPaddress,確認网络连通

5.2 読み取りデータ为0或異常

  • アドレスエラー:ConfirmModbusアドレス与PLC软元件アドレス的对应关系,注意オフセットの量
  • 駅からの住所エラー:ConfirmSlaveId与PLC中に設置。的一致
  • 機能コードサポートなし。:部分台達PLC型号可能サポートなし。某些機能コード
  • アドレス越界:確認読み取り的アドレス範囲在PLCサポート的範囲内
  • PLC未运行:ConfirmPLC处于RUNモード,STOPモード下部分アドレス不可读

5.3 写入不生效

  • レジスタ被程序カバー:PLC程序中可能正在写入该アドレス,导致写入被カバー
  • アドレス読み取り専用:部分レジスタ(如X入力)是読み取り専用的,書けない。入
  • 权限限制:部分PLC需要設定通讯写入权限
  • データ型エラー:確認写入的データ型与PLC中定义的一致

六、ベストプラクティス

  • バッチ読み取り:尽量一次読み取り多个连续レジスタ,减少通讯次数,提高效率
  • 合理ポーリング間隔:建议ポーリング間隔不未来100ms,避免过快ポーリング导致PLC通讯过载
  • 断线再接続:追加自動再接続。机制,网络恢复后自动恢复通讯
  • タイムアウトの設定:合理設定通信タイムアウト,建议2-3秒
  • 異常処理:捕获ModbusException,区分不同異常コード。进行処理
  • 线程セキュリティ:多线程アクセス使用するときlock保护,避免并发冲突
  • ジャーナル·レコード:记录通讯日志,便于トラブルシューティング問題
  • アドレス规划:提前规划D/Mレジスタ的使用,避免アドレス冲突

本記事提供的C#代码実装了台達PLC完全に。Modbus TCP通讯功能,包括Dregister、MRelay、X入力、Y出力、タイマータイマー。、カウンター·カウンター的读書き込み操作。,以及Windows Formsトップマシン界面サンプル。代码可直接使用する。于工业自動化项目开发,建议先使用台達ISPSoft软件モニタリングPLCdata,確認通信は正常后再集成到实际项目中。

Put this resource to use in a real project?

Go to the Tool Center for message parsing, CRC verification and device debugging, or submit your requirements for selection and integration advice.

Engineer Membership

Turn this article into actionable debugging resources

After activation, you can use advanced message parsing, resource pack downloads, code examples, engineering cases and priority technical support, suitable for real project delivery.

Unlimited Advanced Tools
Resource & Code Packs
Complete Engineering Case Library
Priority Technical Support

Leave a Reply

Your email address will not be published. Required fields are marked *.