首页/文章列表/文章详情

C#实现ModbusTCP从站(三)

编程知识702025-05-07评论
C#实现ModbusTCP从站(三)

前言

  • 【作者】:编程笔记in
  • 【原文】:mp.weixin.qq.com/s/EerOuTF2HK72ykNHJS1duQ
  • 本文描述如何使用C#原生的Socket类实现ModbusTCP从站功能。
  • ModbusTCP从站是作为响应设备(服务器端)被动接收并处理主站(客户端)的请求,通过使用Socket创建从站服务,用于侦听主站(客户端)连接,获取请求及数据响应。

项目介绍

  • 项目实现了线圈(Coils)和保持寄存器(Holding Registers)的数据临时缓存功能,其中线圈是2进制数据,寄存器是16位整形数据。所以可以创建bool数组(boo[])和ushort数组(ushort[])存储数据。
  • 使用Socket接收发送,在接收数据后,按照Modbus的协议格式转换数据,再将转换后的数据发送回去,达到通讯效果。
  • 下面是实现的数据处理功能。

1、处理客户端功能码:

  • ① 处理线圈读取(功能码0x01)。
  • ② 处理保持寄存器读取(功能码0x03)。
  • ③ 处理线圈写入(功能码0x05)。
  • ④ 处理寄存器写入(功能码0x06)。
  • ⑤ 处理多线圈写入(功能码0x0F)。
  • ⑥ 处理多寄存器写入(功能码0x10)。

2、实现功能:

  • 创建设置和获取线圈和寄存器数据的方法,基本功能如(①②③④),方法是直接设置或获取数组的值,没有使用Modbus协议。属于测试功能,仅限测试时使用(正常情况不建议直接修改值)。

  • ① 获取单个或多个线圈的值。

  • ② 获取单个或多个寄存器的值。

  • ③ 设置单个或多个线圈。

  • ④ 设置单个或多个寄存器。

  • ⑤ 支持多客户端连接。

  • ⑥ 显示或隐藏请求报文。

  • ⑦ 显示或隐藏相应报文。

  • ⑧ 定时读取功能。

运行环境

  • 操作系统:Windows11
  • 编程软件:Visual Studio 2022
  • Net版本:.Net Framework 4.8.0

预览

(一)运行效果

 

代码

(一)MainForm代码

  • 界面代码大概如下,实现了基本的连接、读取、写入、是否显示报文功能(下面仅是基本的字段和方法 方法签名,完整内容文末自行下载)。
public partial class MainForm : Form
{
ModbusTcpSlave modbusTcpSlave;
ushort startAddress = 0;
ushort dataLength = 1;
Timer timerRead;

public MainForm(){ InitializeComponent(); }
private void MainForm_Load(object sender, EventArgs e){}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e){}
private void Initialize(){}
private void TimerRead_Tick(object sender, EventArgs e){}

#region 事件方法
#region 按钮事件
private void btn_Connect_Click(object sender, EventArgs e){}
private void btn_ReadData_Click(object sender, EventArgs e){}
private void btn_SendData_Click(object sender, EventArgs e){}
private void btn_ClearMessage_Click(object sender, EventArgs e){}
private void btn_ClearSendData_Click(object sender, EventArgs e){}
#endregion
private void ModbusTcpSlave_MessageCallabck(object sender, ModbusMessageEvents message){}
private void ModbusTcpSlave_RequestCallabck(object sender, ModbusMessageEvents message){}
private void ModbusTcpSlave_ResponseCallback(object sender, ModbusMessageEvents message){}
#endregion

#region 控件状态更新
private void ControlStateUpdate(){}
private void checkBox_TimedRead_CheckedChanged(object sender, EventArgs e){}
#endregion

#region 操作消息更新
private void MessageUpdate(string data, Color color, string appendText = null, int maxLineNum = 1000, bool isAppendTime = true){}
private void SetTextColor(RichTextBox rtb, int startIndex, int length, Color color){}
#endregion

#region 参数变更
private void nudx_StartAddress_ValueChanged(object sender, EventArgs e){}
private void nudx_DataLength_ValueChanged(object sender, EventArgs e){}
private void cbx_FuncCode_SelectedIndexChanged(object sender, EventArgs e){}
#endregion
}

 

(二)ModbusTcpSlave代码

  • 在这里声明创建从站用到的字段、属性、事件、及相关的方法,相关方法声明如下(下面仅是类的字段和方法,方法签名,完整内容文末自行下载)。
publicclassModbusTcpSlave{#region字段|属性|事件publiceventEventHandler<ModbusMessageEvents>MessageCallback;publiceventEventHandler<ModbusMessageEvents>RequestCallabck;publiceventEventHandler<ModbusMessageEvents>ResponseCallback;privateint _port = 502;privatestring_address;privateint unitId = 1;privatebool_isRunning;privateushort[] _holdingRegisters; privatereadonlyint MaxDataCount = 65536;privatebool[] _coils; privateconstint MaxConnections = 5;publicint ReceiveTimeout { get;privateset; } = 3000;private Thread listenerThread = null;private Socket slaveSocket; privateDictionary<string, Thread>clientThreadList;publicbool IsRunning { get=> _isRunning; } publicstring FuncCode { get;set; } = "01";#endregion#region构造函数|对象参数初始化publicModbusTcpSlave(string ipAddress = "127.0.0.1",int port = 502,byte unitId = 1){}privatevoidInitialize(){}#endregion#region启动|停止publicvoidStart(){}publicvoidStop(){}privatevoidListenClient(){}privatevoidHandleClientConnect(objectsocket){}#endregion#region数据转换publicstaticstring ArrayToString<T>(T[] values, string sep = ""){}publicstaticstring ArrayToHex<T>(T[] values, string sep = "")where T : struct, IConvertible{} publicstatic T[] StringToArray<T>(stringinput,char sep = ','){}publicstatic T[] TryStringToArray<T>(stringinput,char sep = ','){}privateushort[] ConvertRequestMessage(byte[] request){} #endregion#region数据变更处理privatebyte[] ProcessRequest(byte[] request, intlength){}privatebyte[] HandleReadCoils(byte[] request, ushortstartAddress,ushortnumberOfPoint){}privatebyte[] HandleReadHoldingRegisters(byte[] request, ushortstartAddress,ushortnumberOfPoint){}privatebyte[] HandleWriteSingleCoil(byte[] request, ushortaddress,ushortvalue){}privatebyte[] HandleWriteSingleRegister(byte[] request, ushortaddress,ushortvalue){}privatebyte[] HandleWriteMultipleCoils(byte[] request, ushortstartAddress,ushortnumberOfPoint){}privatebyte[] HandleWriteMultipleRegisters(byte[] request, ushortstartAddress,ushortnumberOfPoint){}privatebyte[] CreateErrorResponse(byte[] request, byteerrorCode){}#endregion#region数据变更处理-强制处理publicboolSetSingleCoils(ushortaddress,boolvalue){}publicboolSetSingleRegister(ushortaddress,ushortvalue){}publicboolSetMultipleCoils(ushortstartAddress,bool[] data){} publicboolSetMultipleRegister(ushortstartAddress,ushort[] data){} publicbool[] GetCoils(ushortaddress,ushortnumberOfPoint){}publicushort[] GetRegisters(ushortaddress,ushortnumberOfPoint){}#endregion#region回调触发方法privatevoid OnMessageCallabck(ModbusMessageEvents message){} privatevoid OnRequestCallabck(ModbusMessageEvents message){} privatevoid OnResponseCallabck(ModbusMessageEvents message){} #endregion}

 

结语

  • 通过该项目学习如何使用C# 实现ModbuTCP通讯的从站功能,之前写过使用Socket实现TCP通讯,个人理解从站是在此基础上做了数据保存处理、在发送接收数据时遵从Modbus协议,最后根据情况将数据格式转换,更多功能会在后续添加,写文章是用于记录和分享、在写的过程中加深印象。

  • 项目源码gitee.com/incodenotes/csharp-modbus
    在这里插入图片描述

  • 如果你觉得这篇文章对你有帮助,不妨点个赞再走呗!

  • 如有其他疑问,欢迎评论区留言讨论!

  • 也可以加入微信公众号 [编程笔记in] ,一起交流学习!

编程笔记in

这个人很懒...

用户评论 (0)

发表评论

captcha