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代码

  • 在这里声明创建从站用到的字段、属性、事件、及相关的方法,相关方法声明如下(下面仅是类的字段和方法,方法签名,完整内容文末自行下载)。
public class ModbusTcpSlave
{
#region 字段|属性|事件
public event EventHandler<ModbusMessageEvents> MessageCallback;
public event EventHandler<ModbusMessageEvents> RequestCallabck;
public event EventHandler<ModbusMessageEvents> ResponseCallback;
private int _port = 502;
private string _address;
private int unitId = 1;
private bool _isRunning;
private ushort[] _holdingRegisters;
private readonly int MaxDataCount = 65536;
private bool[] _coils;
private const int MaxConnections = 5;
public int ReceiveTimeout { get; private set; } = 3000;
private Thread listenerThread = null;
private Socket slaveSocket;
private Dictionary<string, Thread> clientThreadList;
public bool IsRunning { get => _isRunning; }
public string FuncCode { get; set; } = "01";
#endregion
#region 构造函数|对象参数初始化
public ModbusTcpSlave(string ipAddress = "127.0.0.1", int port = 502, byte unitId = 1){}
private void Initialize(){}
#endregion
#region 启动|停止
public void Start(){}
public void Stop(){}
private void ListenClient(){}
private void HandleClientConnect(object socket){}
#endregion
#region 数据转换
public static string ArrayToString<T>(T[] values, string sep = " "){}
public static string ArrayToHex<T>(T[] values, string sep = " ") where T : struct, IConvertible{}
public static T[] StringToArray<T>(string input, char sep = ','){}
public static T[] TryStringToArray<T>(string input, char sep = ','){}
private ushort[] ConvertRequestMessage(byte[] request){}
#endregion
#region 数据变更处理
private byte[] ProcessRequest(byte[] request, int length){}
private byte[] HandleReadCoils(byte[] request, ushort startAddress, ushort numberOfPoint){}
private byte[] HandleReadHoldingRegisters(byte[] request, ushort startAddress, ushort numberOfPoint){}
private byte[] HandleWriteSingleCoil(byte[] request, ushort address, ushort value){}
private byte[] HandleWriteSingleRegister(byte[] request, ushort address, ushort value){}
private byte[] HandleWriteMultipleCoils(byte[] request, ushort startAddress, ushort numberOfPoint){}
private byte[] HandleWriteMultipleRegisters(byte[] request, ushort startAddress, ushort numberOfPoint){}
private byte[] CreateErrorResponse(byte[] request, byte errorCode){}
#endregion
#region 数据变更处理-强制处理
public bool SetSingleCoils(ushort address, bool value){}
public bool SetSingleRegister(ushort address, ushort value){}
public bool SetMultipleCoils(ushort startAddress, bool[] data){}
public bool SetMultipleRegister(ushort startAddress, ushort[] data){}
public bool[] GetCoils(ushort address, ushort numberOfPoint){}
public ushort[] GetRegisters(ushort address, ushort numberOfPoint){}
#endregion
#region 回调触发方法
private void OnMessageCallabck(ModbusMessageEvents message){}
private void OnRequestCallabck(ModbusMessageEvents message){}
private void OnResponseCallabck(ModbusMessageEvents message){}
#endregion
}

结语

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

  • 项目源码 gitee.com/incodenotes/csharp-modbus

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

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

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

C#实现ModbusTCP从站(三)的更多相关文章

  1. S7-200和S7-300profibus-DP通信

    一.S7-200CN的cup可以通过EM277接入DP网络 二.CPU315-2DP做主站,S7-200CUP做从站 三. 通信题目 四.硬件组态 1.主站的DP组态,地址为2 2.EM277作为从站 ...

  2. Modbus 指令

    本节内容: 一.S7-1200 作为Modbus RTU 主站 二.S7-1200 作为Modbus RTU 从站 三.S7-1200 作为Modbus RTU 主站 S7-1200 作为Modbus ...

  3. ModbusTCP协议

    简介 Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准.1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP. Modbus协议是一项应用层 ...

  4. Java实现ModbusTCP通信

    一个项目,需要用Java实现使用ModbusTCP和硬件设备通信 资料 代码下载 本文的代码和仿真软件:蓝奏云下载 官网资料 Modbus官网 Modbus协议 Modbus技术资源 MODBUS T ...

  5. 基于Python的ModbusTCP客户端实现

    Modbus协议是由Modicon公司(现在的施耐德电气Schneider Electric)推出,主要建立在物理串口.以太网TCP/IP层之上,目前已经成为工业领域通信协议的业界标准,广泛应用在工业 ...

  6. 从MySQL到ORM(三):连接、存储过程和用户权限

    一.联结表 数据仍使用前文中的数据. 1.子查询 作为子查询的SELECT语句只能查询单个列.企图检索多个列将返回错误. -- 作为查询条件使用 -- 查看TNT2订单对应的客户ip(order表) ...

  7. IoTClient开发3 - ModBusTcp协议客户端实现

    前言 进过前面两章的介绍,今天开始正式的实战. 进制转换 很多朋友对于进制转换可能是在刚学计算机的时候有接触,后来做高级语言开发可能就慢慢忘记了.我们做工控开发的时候需要经常进行进制转换,这里和大家一 ...

  8. 组态DP主站与标准从站的步骤

    分为以下几个部分 第一:组态DP主站与标准从站 分为以下几个步骤 步骤1: 将标准从站ET200 ,ET200在硬件组态软件界面的最右边的PROFIBUS-DP界面里面, PROFIBUS-DP里面是 ...

  9. 【新阁教育】台达DVP-ES3 ModbusTCP通信案例

    本文主要针对台达DVP-ES3系列PLC,实现上位机与PLC之间的ModbusTCP通信. 一.硬件说明 DVP-ES3 系列为高阶应用可编程控制器, CPU 内置4 组高速计数器输入.4组轴输出(脉 ...

  10. 常用 Gulp 插件汇总 —— 基于 Gulp 的前端集成解决方案(三)

    前两篇文章讨论了 Gulp 的安装部署及基本概念,借助于 Gulp 强大的 插件生态 可以完成很多常见的和不常见的任务.本文主要汇总常用的 Gulp 插件及其基本使用,需要读者对 Gulp 有一个基本 ...

随机推荐

  1. Luogu P4588 数学运算 题解 [ 绿 ] [ 线段树 ]

    Luogu P4588 数学运算. 虽然是一个很典的题,但里面的思想还是比较值得记录的. 假做法 一开始看到此题还以为是乘法逆元的模板题,但看到 \(m\) 与 \(M\) 不互质,就知道这种做法是假 ...

  2. [虚拟化/Docker] Docker Desktop 安装与使用

    0 序:DeepSeek 等AI大模型在Windows的私有化部署 DeepSeek 等AI大模型在Windows的私有化部署,最流行的开源AI终端应用----Dify,依赖于 Docker 环境.由 ...

  3. 技术前瞻: ECMAScript 2025 已定稿特性解析:让 JavaScript 更优雅

    作为全球应用最广泛的编程语言之一,JavaScript 每年都在通过 ECMAScript 标准持续进化.2025 年,ECMAScript 再次带来多项重磅更新,本文将带你深入解读已正式定稿的核心特 ...

  4. 【忍者算法】从生活到代码:解密链表大数相加的美妙算法|LeetCode第2题"两数相加"

    从生活到代码:解密链表大数相加的美妙算法 从超市收银说起 想象你是一个超市收银员,正在计算两位顾客的购物总和.每位顾客的商品都按照从个位到高位的顺序摆放(比如54元就是先放4元商品,再放50元商品). ...

  5. ABC393C题解

    大概评级:橙. 送分题. 题意就是让你统计有多少条边是重边或自环. 设 \(u_i\) 表示第 \(i\) 条边的左端点,\(v_i\) 表示第 \(i\) 条边的右端点. 那么如果 \(u_i = ...

  6. EAR_v3 《浮声三》 智能化图书管理系统

    EAR_v3 <浮声三> 搭建于 Actix_Web 框架下的智能化图书管理系统 本项目的前身是 <Rusty_Borders 危墙> 的 在线控制系统 部分,经过大量开发工作 ...

  7. 值得推荐的IT公司名单(国企篇)

    大家好,今天我们来盘点一下值得推荐的国企,这些企业在行业内具有举足轻重的地位,不仅主营业务突出,福利待遇优厚,尤其是研发岗位的薪资区间,更是让人眼前一亮. 十大顶尖央企国企,待遇优厚如天花板级别!(排 ...

  8. Web前端入门第4问:HTML、CSS、JavaScript 的作用分别是什么?

    HTML.CSS.JavaScript 的核心作用 HTML:网页的骨架 功能:定义页面的内容结构(如按钮.表格.图片). 示例:<button>提交</button> 创建一 ...

  9. Kubernetes:根据进程 Pid 获取 Pod 名称

    前言 在管理 Kubernetes 集群的过程中,我们经常会遇到这样一种情况:在某台节点上发现某个进程资源占用量很高,却又不知道是哪个容器里的进程.有没有办法可以根据进程 PID 快速找到 Pod 名 ...

  10. Calico Kernel's RPF check is set to 'loose'

    前言 K8s 集群部署使用了 calico 网络插件,而calico node 节点发生如下报错: 2023-03-13 11:19:36.622 [FATAL][828] int_dataplane ...