C#轻松创建ModbusTCP服务器Slave,实现工业数据交换接口。

1、依赖库:NModbus4

https://github.com/NModbus4/NModbus4

2、添加引用

1
2
3
4
5
6
7
using Modbus.Data;
using Modbus.Device;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;

3、全局变量声明:

1
2
3
4
5
6
7
8
9
/// <summary>
/// 服务器提供的数据区
/// </summary>
public static DataStore Data;

/// <summary>
/// Modbus服务器
/// </summary>
public static ModbusSlave modbus_tcp_server;

4、创建ModbusTCP服务:

1
2
3
4
Data = DataStoreFactory.CreateDefaultDataStore(); //初始化服务数据区
modbus_tcp_server = ModbusTcpSlave.CreateTcp(1, new TcpListener(IPAddress.Parse("0.0.0.0"), 502)); //创建ModbusTcp服务器
modbus_tcp_server.DataStore = Data;//数据区赋值
modbus_tcp_server.ModbusSlaveRequestReceived += _modbusSlave_ModbusSlaveRequestReceived; //接收到查询的事件(供调试显示,非必须)

5、启动服务:(非阻塞方式)

1
2
3
4
5
6
7
8
9
Thread th_0 = new Thread(() =>
{
       modbus_tcp_server.Listen();//异步 非阻塞 启动服务
})
{
       IsBackground = true,
};
th_0.SetApartmentState(ApartmentState.STA);
th_0.Start();

6、接收到客户端数据查询的事件(供界面信息显示非必须)

1
2
3
4
5
6
7
8
9
10
11
12
        /// <summary>
        /// 接收事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _modbusSlave_ModbusSlaveRequestReceived(object sender, ModbusSlaveRequestEventArgs e)
        {
            BeginInvoke(new MethodInvoker(() =>
            {
                label1.Text = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss:fff") + ":" + e.Message.ToString();
            }));
        }

7、服务器的数据区赋值(此处仅测试,实际生产环境根据需求做赋值)

1
2
3
4
5
6
7
8
9
            Thread th_1 = new Thread(() =>
            {
                SetData(); //数据区数据赋值
            })
            {
                IsBackground = true,
            };
            th_1.SetApartmentState(ApartmentState.STA);
            th_1.Start();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
        /// <summary>
        /// 设置数据
        /// </summary>
        private void SetData()
        {
            while (true)
            {
                Data.InputRegisters[1] = (ushort)DateTime.Now.Year;         //年
                Data.InputRegisters[2] = (ushort)DateTime.Now.Month;        //月
                Data.InputRegisters[3] = (ushort)DateTime.Now.Day;          //日
                Data.InputRegisters[4] = (ushort)DateTime.Now.Hour;         //时
                Data.InputRegisters[5] = (ushort)DateTime.Now.Minute;       //分
                Data.InputRegisters[6] = (ushort)DateTime.Now.Second;       //秒
                Data.InputRegisters[7] = (ushort)DateTime.Now.Millisecond;  //毫秒
                Random ran = new Random();
                Data.InputRegisters[8] = (ushort)ran.Next(0, 32767);        //产生的随机数

                ///界面显示
                BeginInvoke(new MethodInvoker(() =>
                {
                    richTextBox1.Clear();
                    richTextBox1.AppendText($@"30001={Data.InputRegisters[1]}" + "\r\n");
                    richTextBox1.AppendText($@"30002={Data.InputRegisters[2]}" + "\r\n");
                    richTextBox1.AppendText($@"30003={Data.InputRegisters[3]}" + "\r\n");
                    richTextBox1.AppendText($@"30004={Data.InputRegisters[4]}" + "\r\n");
                    richTextBox1.AppendText($@"30005={Data.InputRegisters[5]}" + "\r\n");
                    richTextBox1.AppendText($@"30006={Data.InputRegisters[6]}" + "\r\n");
                    richTextBox1.AppendText($@"30007={Data.InputRegisters[7]}" + "\r\n");
                    richTextBox1.AppendText($@"30008={Data.InputRegisters[8]}" + "\r\n");

                }));
                Thread.Sleep(1000);
            }

8、运行测试:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述