C#使用NModbus4库创建Modbus TCP Slave(服务器)简单示例

原来你也___ 2024-06-18 11:05:06 阅读 78

本文续上篇Codesys—标准库ModbusTCP Master(客户端)配合C#的NModbus4库的通讯示例

链接:https://blog.csdn.net/wushangwei2019/article/details/136375234?spm=1001.2014.3001.5501

上篇描述在Codesys端的Modbus TCP Master(客户端)的设备添加、IO映射、通讯简单展示等方面,本文记录PC端C#利用NModbus4通讯库创建Modbus TCP Slave(服务器)的方法。

注:本文只记录如何使用NModbus4的部分功能,程序结构较为简单,并不适用于项目工程。

本文分以下几个步骤分享NModbus4的使用:

1.添加NModbus4库

2.ModbusTcpSlave从站的创建

3.事件订阅

4.通讯示例

界面附加显示功能:

1.在收到客户端报文的事件后,将会在信息提示框中显示报文内容,报文内容不包含CRC;在服务器写入完成后,将会在信息提示框中显示写入完成的报文内容。

2.在服务器线程中,获取已连接的客户端的IP地址以及端口号信息,并在最底下显示出来。

软件界面如下,本文针对左侧服务器(从站)端:

1.添加NModbus4库 

菜单栏点击【工具】-》【NuGet包管理器】-》【管理解决方案的NuGet程序包】

弹出以下画面,搜索【NModbus4】 ,选择需要安装的项目,并点击右下角的【安装】即可。

在程序中添加如下代码:

using Modbus.Data;using Modbus.Device;using Modbus.Extensions.Enron;

 2.使用TcpListener创建服务器

核心代码:

listener = new TcpListener(IPAddress.Parse(textBox2.Text), Convert.ToInt32(textBox3.Text));

listener.Start();

slave = ModbusTcpSlave.CreateTcp(1, listener);

slave.DataStore = DataStoreFactory.CreateDefaultDataStore(); 

slave.Listen();

解析:

1.TcpListener,用于创建服务器,需要输入参数待创建服务器的【IP地址】和【端口号】。

2.ModbusTcpSlave.CreateTcp方法,用于创建ModbusTCP Slave从站,创建后的从站对象为slave。

3.DataStoreFactory.CreateDefaultDataStore()方法,用于清除Modbus TCP Slave的数据存储区,寄存器区值全部写0。

4.slave.Listen()方法,Modbus TCP Slave开始监听请求,我的理解是有客户端连接后,Slave开始响应客户端的报文,此方法应该放在有客户端连接后再使用较好,但在此处调用也能正常运行。

try { listener = new TcpListener(IPAddress.Parse(textBox2.Text), Convert.ToInt32(textBox3.Text)); listener.Start(); slave = ModbusTcpSlave.CreateTcp(1, listener); slave.DataStore = DataStoreFactory.CreateDefaultDataStore(); WriteInfo("创建服务器成功!" + "线程ID:" + Thread.CurrentThread.ManagedThreadId + "\r\n"); //订阅数据到达事件,不能获取具体接收到的报文 //slave.DataStore.DataStoreWrittenTo += DataStoreWrittenToHandle; //订阅接收到报文请求事件,可以打印接收到的报文 slave.ModbusSlaveRequestReceived += ModbusSlaveRequestReceivedHandle; //订阅接收到写入完成事件,可以打印写入完成响应 slave.WriteComplete += WriteCompleteHandle; slave.Listen(); isServerCreated = true; WriteInfo("服务器创建成功!" + "\r\n"); count2 = 0; } catch(Exception ex) { count2++; WriteInfo("创建服务器失败!" + "失败次数:"+count2.ToString()+ "\r\n"); isServerCreated = false; creatServer= false; return; }

3.事件订阅

分别说明以下三个事件的功能。

//订阅数据到达事件,不能获取具体接收到的报文

//slave.DataStore.DataStoreWrittenTo += DataStoreWrittenToHandle;

//订阅接收到报文请求事件,可以打印接收到的报文

slave.ModbusSlaveRequestReceived += ModbusSlaveRequestReceivedHandle;

 //订阅接收到写入完成事件,可以打印写入完成响应

slave.WriteComplete += WriteCompleteHandle;

1.DataStore.DataStoreWrittenTo事件:当DataStore通过Modbus命令被写入数据时触发。

2.ModbusSlaveRequestReceived事件:当Slave收到主站报文时触发。

3.WriteComplete事件:当Slave接收到主站报文,并写入完成后触发。

本例主要使用后面【ModbusSlaveRequestReceived事件】和【WriteComplete事件】。

ModbusSlaveRequestReceived事件触发时,调用函数在提示框中打印报文信息,报文信息转换成16进制显示。

private void ModbusSlaveRequestReceivedHandle(object obj, ModbusSlaveRequestEventArgs e) { string str = ""; foreach (var item in e.Message.MessageFrame) { str += item.ToString("x2").PadLeft(2, '0').ToUpper() + " "; } WriteInfo("服务器收到报文: " + str + "\r\n"); }

WriteComplete事件,调用函数在提示框中打印报文信息,报文信息转换成16进制显示。

private void WriteCompleteHandle(object sender, ModbusSlaveRequestEventArgs e) { string str = ""; foreach (var item in e.Message.MessageFrame) { str += item.ToString("x2").PadLeft(2, '0').ToUpper() + " "; } WriteInfo("服务器写入完成: " + str + "\r\n"); }

4.通讯示例

在服务器侧画面上,输入【IP】:127.0.0.1,【Port】:502,点击【创建服务器】,可观察到下方提示框中显示【创建服务器成功】。

打开Modbus Poll软件,在连接设置在远端服务器侧输入【IP地址】和【端口号】,点击确认连接。

连接成功后,PC端软件提示服务器收到报文,报文信息没有包含CRC字节信息;Modbus Poll端软件显示Tx=11,不断增加,这是由于默认使用了03功能读保持寄存器,数量长度为20个字,并循环读取。

Modbus Poll的配置如下: 

根据PC端软件已有功能,进行测试。

从站(服务器)写入,Modbus Poll(主站/客户端)读取:

【Value】输入2,点击【写1~10】,将向保持寄存器地址【1~10】写入值为Value*地址值,如:地址1=2;

地址2=4;

地址3=6;

地址4=8;

依次类推...如下图所示。

Modbus Poll(主站/客户端)写入,从站(服务器)读取:

Modbus Poll使用03功能码往保持寄存器地址11,写入123。 左侧软件提示框显示“服务器收到报文+收到报文”,此提示是由【ModbusSlaveRequestReceived事件】触发后发出;然后显示“服务器写入完成+收到报文”,此提示是由【WriteComplete事件】触发后发出。

Modbus Poll使用16功能码往保持寄存器地址11开始写10个寄存器,命令配置如下:

观察左侧软件提示框信息:

报文数据中的  00  0B  00  0C  00  0D  00  0E  00  0F  00  10  00  11  00  12  00  13  00  14

转换成10进制为11(00 0B),12(00 0C),13,14,15,16,17,18,19,20。

至此,基本通讯测试完成。

下面补充服务器端,如何对保持寄存器进行读写,其实很简单,就是直接访问slave.DataStore.HoldingRegisters[i]中的数据即可。

如下为写入代码:

if (listener != null && slave!=null) { for (int i = 1;i<11;i++) { slave.DataStore.HoldingRegisters[i] = (ushort)(numericUpDown2 .Value* i); } WriteInfo("服务器写入1~10完成" + "\r\n"); }

以下为读取代码:

if(slave!=null) { string str = ""; for(int i=10;i<20;i++) { str += slave.DataStore.HoldingRegisters[i+1].ToString() + " "; } WriteInfo("读取寄存器(地址为10~20):"+str +"\r\n"); }



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。