通信协议_C#实现自定义ModbusRTU主站
背景知识:modbus协议介绍
相关工具
- mbslave:充当从站。
- 虚拟串口工具:虚拟出一对串口。
- VS2022。
实现过程以及Demo
- 打开虚拟串口工具:

- 打开mbslave:


此处从站连接COM1口。
Demo实现
- 创建DLL库,创建ModbusRTU类,进行实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Ports;
using System.Threading;namespace modBusDLL
{public class ModBusRTU{private SerialPort serialPort = null;public ModBusRTU(){serialPort = new SerialPort();}//连接方法//端口号,波特率,数据位,校验位,停止位public void Connect(string portName,int baudRate=9600,int dataBits=8,Parity parity=Parity.None,StopBits stopBits=StopBits.One){ if (serialPort.IsOpen) {serialPort.Close();}serialPort.BaudRate = baudRate;serialPort.PortName = portName;serialPort.Parity = parity;serialPort.StopBits = stopBits;serialPort.DataBits = dataBits;serialPort.Open();}//断开连接方法public void Disconnect(){if (serialPort.IsOpen){serialPort.Close();}}//读消息方法public byte[] ReadKeepRegisters(byte devAdd,ushort start,ushort length){ //拼接报文,发送报文,接受报文,校验报文,解析报文//创建一个字节集合List<byte> ret = new List<byte>();//协议格式:站地址+功能码+起始寄存器地址+寄存器数量+CRC//站地址ret.Add(devAdd);//功能码ret.Add(0x03);//起始寄存器地址//高位地址ret.Add((byte)(start / 256));//低位地址ret.Add((byte)(start % 256));//寄存器数量//高位地址ret.Add((byte)(length / 256));//低位地址ret.Add((byte)(length % 256));byte[] crc= CRCCalc(ret.ToArray());ret.AddRange(crc);//发送报文serialPort.Write(ret.ToArray(), 0, ret.Count);Thread.Sleep(50);//接受长度int byteCount = serialPort.BytesToRead;byte[] data = new byte[byteCount];//读入dataserialPort.Read(data, 0, data.Length);byte[] result = new byte[length*2]; Array.Copy(data,3,result, 0,length*2);return result;}#region 16位CRC校验/// <summary>/// CRC校验,参数data为byte数组/// </summary>/// <param name="data">校验数据,字节数组</param>/// <returns>字节0是高8位,字节1是低8位</returns>public static byte[] CRCCalc(byte[] data){//crc计算赋初始值int crc = 0xffff;for (int i = 0; i < data.Length; i++){crc = crc ^ data[i];for (int j = 0; j < 8; j++){int temp;temp = crc & 1;crc = crc >> 1;crc = crc & 0x7fff;if (temp == 1){crc = crc ^ 0xa001;}crc = crc & 0xffff;}}//CRC寄存器的高低位进行互换byte[] crc16 = new byte[2];//CRC寄存器的高8位变成低8位,crc16[1] = (byte)((crc >> 8) & 0xff);//CRC寄存器的低8位变成高8位crc16[0] = (byte)(crc & 0xff);return crc16;}/// <summary>/// CRC校验,参数为空格或逗号间隔的字符串/// </summary>/// <param name="data">校验数据,逗号或空格间隔的16进制字符串(带有0x或0X也可以),逗号与空格不能混用</param>/// <returns>字节0是高8位,字节1是低8位</returns>public static byte[] CRCCalc(string data){//分隔符是空格还是逗号进行分类,并去除输入字符串中的多余空格IEnumerable<string> datac = data.Contains(",") ? data.Replace(" ", "").Replace("0x", "").Replace("0X", "").Trim().Split(',') : data.Replace("0x", "").Replace("0X", "").Split(' ').ToList().Where(u => u != "");List<byte> bytedata = new List<byte>();foreach (string str in datac){bytedata.Add(byte.Parse(str, System.Globalization.NumberStyles.AllowHexSpecifier));}byte[] crcbuf = bytedata.ToArray();//crc计算赋初始值return CRCCalc(crcbuf);}/// <summary>/// CRC校验,截取data中的一段进行CRC16校验/// </summary>/// <param name="data">校验数据,字节数组</param>/// <param name="offset">从头开始偏移几个byte</param>/// <param name="length">偏移后取几个字节byte</param>/// <returns>字节0是高8位,字节1是低8位</returns>public static byte[] CRCCalc(byte[] data, int offset, int length){byte[] Tdata = data.Skip(offset).Take(length).ToArray();return CRCCalc(Tdata);}#endregion}
}
- 在窗体代码中进行调用:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using modBusDLL;namespace easyProjectPractice
{public partial class Form1 : Form{public Form1(){InitializeComponent();this.comboBox1.DataSource=SerialPort.GetPortNames();}private ModBusRTU modBusRTU = new ModBusRTU();private void label1_Click(object sender, EventArgs e){}private void Form1_Load(object sender, EventArgs e){}private void button1_Click(object sender, EventArgs e){modBusRTU.Connect(this.comboBox1.Text);MessageBox.Show("连接成功");}private void button2_Click(object sender, EventArgs e){modBusRTU.Disconnect();MessageBox.Show("断开连接");}private void button3_Click(object sender, EventArgs e){byte[] data = modBusRTU.ReadKeepRegisters(1, 2, 1);textBox1.Text = (data[0] * 256 + data[1]).ToString();}private void textBox1_TextChanged(object sender, EventArgs e){}}
}
- 最终可实现通过mdbusRTU协议进行主从站通信:


总结
简单的modbusRTU主从通信自定义。
接触过的所有通信协议Demo代码
相关文章:
通信协议_C#实现自定义ModbusRTU主站
背景知识:modbus协议介绍 相关工具 mbslave:充当从站。虚拟串口工具:虚拟出一对串口。VS2022。 实现过程以及Demo 打开虚拟串口工具: 打开mbslave: 此处从站连接COM1口。 Demo实现 创建DLL库,创建ModbusRTU类,进行实现: using Syste…...
【C语言】 —— 编译和链接
【C语言】 —— 编译和链接 一、编译环境和运行环境二、翻译环境2.1、 预处理2.2、 编译(1)词法分析(2)语法分析(3)语义分析 2.3、 汇编2.4、链接 三、运行环境 一、编译环境和运行环境 平时我们说写 C语言…...
DNS正向解析与反向解析实验
正向解析 安装bind软件 [rootlocalhost ~]# dnf install bind bind-utils -y修改主配置文件/etc/named.conf [rootlocalhost ~]# vim /etc/named.conf重启DNS服务(named) [rootlocalhost ~]# systemctl restart named编辑数据配置文件。在/var/named…...
机器学习简介--NLP(二)
机器学习简介 机器学习简介机器学习例子机器学习分类有监督学习有监督学习的应用 无监督学习 机器学习常见概念数据集k折交叉验证过拟合欠拟合评价指标 机器学习简介 机器学习例子 问题: 2,4,6,8,?&#…...
Winform中使用HttpClient实现调用http的post接口并设置传参content-type为application/json示例
场景 Winform中怎样使用HttpClient调用http的get和post接口并将接口返回json数据解析为实体类: Winform中怎样使用HttpClient调用http的get和post接口并将接口返回json数据解析为实体类_winform解析json-CSDN博客 上面使用HttpClient调用post接口时使用的HttpCon…...
【RAG探索第3讲】LlamaIndex的API调用与本地部署实战
原文链接:【RAG探索第3讲】LlamaIndex的API调用与本地部署实战 今天是2024年7月5日,星期五,天气晴,北京。 RAG的文章也看不少了,今天给大家带来一个llamaindex的实战。分为两个部分,调用ChatGLM的API来用l…...
C# —— 日期对象
DateTime 时间类 存储时间对象 可以获取当前时间 DateTime now DateTime.Now;// 获取当前时间 Console.WriteLine("年:" now.Year);//2023 Console.WriteLine("月:" now.Month);//9 Console.WriteLine("日:" now.Day);//12 Console.WriteLi…...
【MySQL04】【 redo 日志】
文章目录 一、前言二、redo 日志1. redo 日志格式2. Mini-Transaction2.1 以组的形式写入 redo 日志2.2 Mini-Transaction (MTR)概念 3. redo 日志写入过程3.1 redo 日志缓冲区3.3 redo 日志写入 log buffer 4. redo 日志文件4.1 redo 日志刷盘机制4.2 r…...
Android线性布局的概念与属性
线性布局(LinearLayout)是Android中最简单的布局方式,线性布局方式会使得所有在其内部的控件或子布局按一条水平或垂直的线排列。如图所示,图a是纵向线性布局示意图,图b是横向线性布局示意图。 a)纵向线性布局示意图 …...
java反射介绍
Java反射API允许你在运行时检查和修改程序的行为。这意味着你可以动态地创建对象、查看类的字段、方法和构造函数,甚至调用它们。这是一个强大的特性,但也应该谨慎使用,因为它可以破坏封装性。 以下是使用Java反射的一些常见用途:…...
Spring中@Transactional的实现和原理
这篇文章写的很详细了,引自脚本之家 Java中SpringBoot的Transactional原理_java_脚本之家...
华为仓颉可以取代 Java 吗?
大家好,我是君哥。 在最近的华为开发者大会上,华为亮相了仓颉编程语言,这是华为历经 5 年,投入大量研发成本沉淀的一门编程语言。 1 仓颉简介 按照官方报告,仓颉编程语言是一款面向全场景智能的新一代编程语言&#…...
性能测试相关理解(一)
根据学习全栈测试博主的课程做的笔记 一、说明 若未特别说明,涉及术语都是jmeter来说,线程数,就是jmeter线程组中的线程数 二、软件性能是什么 1、用户关注:响应时间 2、业务/产品关注:响应时间、支持多少并发数、…...
缓存-分布式锁-原理和基本使用
分布式锁原理和使用 自旋 public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {Boolean b redisTemplate.opsForValue().setIfAbsent(Lock, Lock, Duration.ofMinutes(1));if (!b) {int i 10;while (i > 0) {Object result redisTe…...
判断国内ip
php代码 //是否国内ip function isChinaIP($ip) {saveLog("---isChinaIP----------");$url "https://searchplugin.csdn.net/api/v1/ip/get?ip".$ip;// 发送HTTP请求$response file_get_contents($url);$utf8String mb_convert_encoding($response, &…...
linux修改内核实现禁止被ping(随手记)
概述 Linux默认允许被ping。其主要决定因素为: 内核参数防火墙(iptables/firewall) 以上的决定因素是与的关系,即需要均满足。 因此,修改linux禁被ping有以上两种方法可以实现。 修改内核文件使禁ping 1. 临时生…...
mac M1安装 VSCode
最近在学黑马程序员Java最新AI若依框架项目开发,里面前端用的是Visual Studio Code 所以我也就下载安装了一下,系统是M1芯片的,安装过程还是有点坑的写下来大家注意一下 1.在appstore中下载 2.在系统终端中输入 clang 显示如下图 那么在终端输…...
代码随想录算法训练营第二十七天 |56. 合并区间 738.单调递增的数字 968.监控二叉树 (可跳过)
56. 合并区间 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。 示例 1: 输入:in…...
网络基础:IS-IS协议
IS-IS(Intermediate System to Intermediate System)是一种链路状态路由协议,最初由 ISO(International Organization for Standardization)为 CLNS(Connectionless Network Service)网络设计。…...
Java面试八股之如何提高MySQL的insert性能
如何提高MySQL的insert性能 提高MySQL的INSERT性能可以通过多种策略实现,以下是一些常见的优化技巧: 批量插入: 而不是逐条插入,可以使用单个INSERT语句插入多行数据。例如: INSERT INTO table_name (col1, col2) V…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
