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. 使用crewai创建属于你自己的AI团队

    crewai介绍 CrewAI 是一个用于协调自主 AI 代理的前沿框架. CrewAI 允许你创建 AI 团队,其中每个代理都有特定的角色.工具和目标,协同工作以完成复杂任务. 把它想象成组建你的梦 ...

  2. IGM机器人维修的关键环节

    在现代科技领域,机器人已经成为不可或缺的一部分,它们广泛应用于各个行业,包括制造业.服务业.医疗.科研等.对于任何机器人来说,定期的维护和修理都是必不可少的.这不仅可以确保机器人正常工作,还可以延长其 ...

  3. Arduino语法--数据类型

    Arduino与C语言类似,有多种数据类型.数据类型在数据结构中的定义是一个值的集合,以及定义在这个值集上的一组操作,各种数据类型需要在特定的地方使用.一般来说,变量的数据类型决定了如何将代表这些值的 ...

  4. mysql扫描全表更新状态部分失败

    1. mysql排序问题 一直以为mysql是按照主键排序的,实则排序和主键没有关系(不使用 order by 子句). 然后从 stackoverflow 上查了一下,找到了以下的回答: 没有默认的 ...

  5. 在 Intel Ultra AI PC 设备上使用 OpenVINO™ C# API本地部署YOLOv11与YOLOv12

    ​ 最新的英特尔 酷睿 Ultra 处理器(第二代)让我们能够在台式机.移动设备和边缘中实现大多数 AI 体验,将 AI 加速提升到新水平,在 AI 时代为边缘计算提供动力.英特尔 酷睿 Ultra ...

  6. Python装饰器:套层壳我变得更强了!

    Python装饰器:套层壳我变得更强了 Python装饰器:套层壳我变得更强了 关于作用域和闭包可以聊点什么? 什么是作用域 什么是闭包 装饰器:套层壳我变得更强了 参考资料 昨天阅读了<Pyt ...

  7. 分布式锁—2.Redisson的可重入锁

    大纲 1.Redisson可重入锁RedissonLock概述 2.可重入锁源码之创建RedissonClient实例 3.可重入锁源码之lua脚本加锁逻辑 4.可重入锁源码之WatchDog维持加锁 ...

  8. Manjora配置记录

    22/9/12 目前的启动项有3:Windows Boot Manager.Manjaro.UEFI OS.其中UEFI OS 和 Manjaro 进入后内容相同:Windows下检测不到Manjar ...

  9. 实现Windows之间(win10)的桌面连接的三步走方法

    实现Windows之间(win10)的远程桌面连接的三步走方法 ‍ 目录 ‍ 目录 实现Windows之间(win10)的远程桌面连接的三步走方法 目录 环境 step1:打开两台Windows电脑的 ...

  10. Flask快速入门1

    因为新换了一个工作,项目使用了Flask框架技术,需要快速学习下,学过Django这个重量级的框架基础后,再去学习Flask框架相对还是容易的. 当然入门基础容易,要深入理解还是要慢慢花时间深耕练习使 ...