Modbus TCP

csharp 复制代码
using EasyModbus;
using System;
using System.Net;
using System.Threading;
/**
                0x01 读取线圈的操作,
                0x02 读取离散的操作,
                0x03 读取寄存器的值,
                0x05 写一个线圈操作,
                0x06 写一个寄存器值,
                0x0F 批量写线圈操作,
                0x10 批量写寄存器值,
                // 1. 保持寄存器 (功能码03读、06写单个、16写多个) → 最常用 ✅
                // 类型:ushort[] ,取值范围 0~65535 ,地址 0~n
                modbusServer.HoldingRegisters[0] = 100; // 赋值
                ushort val = modbusServer.HoldingRegisters[0]; // 取值

                // 2. 线圈寄存器 (功能码01读、05写单个、15写多个) → 开关量 ✅
                // 类型:bool[] ,true=通/1 ,false=断/0 ,地址 0~n
                modbusServer.Coils[1] = true; // 赋值
                bool coilVal = modbusServer.Coils[1]; // 取值

                // 3. 输入寄存器 (功能码04读) → 只读,通常存传感器输入数据
                modbusServer.InputRegisters[5] = 250;

                // 4. 离散输入寄存器 (功能码02读) → 只读,通常存开关量输入数据
                modbusServer.DiscreteInputs[3] = true;

                角色分为主站(Mater)、从站(Slave);
                数据类型分为线圈(Coil)、离散输入(Input)、
                保持寄存器(HoldingRegister)、输入寄存器(InputRegister)
                线圈(Coils):1 位布尔值,可读写。
                离散输入(Discrete Inputs):1 位布尔值,只读。
                保持寄存器(Holding Registers):16 位寄存器,可读写。
                输入寄存器(Input Registers):16 位寄存器,只读。

                每个数据类型都有它自己的地址范围:
                线圈地址范围:000001~065536
                离散量输入地址范围:100001~165536
                输入寄存器地址范围:300001~365536
                保持寄存器地址范围:400001~465536

                但别被这些数字吓到,实际应用中,我们通常只用到10000以内的地址。比如:
                线圈地址范围:00001~09999
                离散量输入地址范围:10001~19999
                输入寄存器地址范围:30001~39999
                保持寄存器地址范围:40001~49999
                如何解读Modbus地址? 🔍

                当你看到地址40001或30004时,怎么判断它是什么类型的寄存器呢?其实很简单:
                40001 / 400001:最前面的4表明它是一个保持寄存器,后面的0001或00001都指第一个保持存储器,地址是0。
                30004:表明它是输入寄存器,地址是3。
                10008:表明它是离散量输入,地址是7。
                */
namespace ConsoleApp12
{
    /// <summary>
    /// EasyModbus 客户端
    /// string clientIp = client.Client.RemoteEndPoint.ToString().Split(':')[0];
    /// </summary>
    internal class Program
    {
        static void Main(string[] args)
        {
            ModbusClient modbusClient = new ModbusClient("127.0.0.1", 502);

            try
            {
                Console.WriteLine("正在连接Modbus服务器...");
                modbusClient.Connect();

                // 读取保持寄存器
                Console.WriteLine("读取保持寄存器...");


                int[] registers = modbusClient.ReadHoldingRegisters(0, 5);
                for (int i = 0; i < registers.Length; i++)
                {
                    Console.WriteLine($"寄存器 {i}: {registers[i]}");
                }

                // 写入寄存器
                Console.WriteLine("写入寄存器...");
                int ii = 1;
                /*while (true)
                {
                    ii++;
                    modbusClient.WriteSingleRegister(1, ii);
                    Thread.Sleep(500);
                }*/
                while (true)
                {
                    registers = modbusClient.ReadHoldingRegisters(0, 5);
                    for (int i = 0; i < registers.Length; i++)
                    {
                        Console.WriteLine($"寄存器 {i}: {registers[i]}");
                    }
                    Thread.Sleep(1000);
                }

                

                // 1、线圈------读写,布尔类型,主要用于设置某个值。
                // 读取多个输出线圈
                // 读取线圈状态 (功能码01)
                // 从地址0开始读取5个线圈
                // bool[] coilStatus = modbusClient.ReadCoils(0, 5); 

                // 写入单个线圈 (功能码05)
                // 向地址0写入true
                //modbusClient.WriteSingleCoil(0, true); 

                //2、离散量输入------只读,布尔类型,获取某个IO状态(1bit)。


                //3、输入寄存器------只读,无符号2字节整型,获取某个16bit数据的值。
                // 读取输入寄存器
                //int[] inputRegisters = modbusClient.ReadInputRegisters(0, 5);

                //4、保持寄存器------读写,无符号2字节整型,设置某个16bit数据的值。
                // 读取保持寄存器 (功能码03)
                // 从地址0开始读取10个寄存器
                //int[] holdingRegisters = modbusClient.ReadHoldingRegisters(0, 10); 

                // 写入单个保持寄存器
                //modbusClient.WriteSingleRegister(0, 1234);

                // 写入多个保持寄存器
                // 写入多个寄存器 (功能码16)
                //int[] valuesToWrite = { 100, 200, 300 };
                // 从地址0开始写入
                //modbusClient.WriteMultipleRegisters(0, valuesToWrite); 

                // 验证写入
                //int value = modbusClient.ReadHoldingRegisters(10, 1)[0];
                //Console.WriteLine($"寄存器10的新值: {value}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"错误: {ex.Message}");
            }
            finally
            {
                modbusClient.Disconnect();
                Console.WriteLine("连接已关闭");
            }
        }

        
    }
}

要安装这个包

相关推荐
程序设计实验室8 小时前
Spark.NET:一个试图把 Django / Rails 式开发体验带回 .NET 世界的全栈 Web 框架。
c#
byoass9 小时前
智巢AI知识库深度解析:企业文档管理从大海捞针到精准狙击的进化之路
开发语言·网络·人工智能·安全·c#·云计算
njsgcs13 小时前
solidworks自动标注折弯4 无向图 c#
开发语言·c#·solidworks
我是唐青枫14 小时前
C#.NET ThreadLocal 深入解析:线程独享数据、性能收益与实战边界
c#·.net
JQLvopkk16 小时前
C# 工业级上位机:交互实战
开发语言·c#·交互
kingwebo'sZone17 小时前
PdfiumViewer使用权限控制期操作按钮(PdfViewer其实也可以完整兼容)
c#
张小俊_17 小时前
WPF 跨线程 UI 更新与硬编码赋值引发的 Bug 排查
c#·bug·wpf
無斜18 小时前
【CAPL实用开发】--- CAPL调用 .NET DLL
开发语言·c#·capl·canoe
puamac18 小时前
UcTabWindow 布局多tab,加载编辑器和资源管理器等自定义控件
c#·编辑器·datagridview
唐青枫18 小时前
别再把增删改查写成一锅粥!C#.NET CQRS 从原理到实战
c#·.net