C# Modbus Rtu实现

2023-11-09

Modbus Rtu的实现与Modbus Tcp的实现类似 C#ModBus Tcp的学习及Master的实现

我们还是需要借用一个开源库NModbus4,在vs中.打开NuGet管理器.安装NModbus4

具体实现,具体实现与之前的Modbus Tcp的实现类似 ,只是在实例化master时将TCPClient换为串行端口资源SerialPort,并在实例化时设置好端口所需参数(端口名,波特率,校验位,停止位,数据位)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Modbus.Device;
using System.Net.Sockets;
using System.Threading;
using System.IO.Ports;

namespace ModbusRtu
{
    public partial class Form1 : Form
    {
        private static IModbusMaster master;
        private static SerialPort port;
        //写线圈或写寄存器数组
        private bool[] coilsBuffer;
        private ushort[] registerBuffer;
        //功能码
        private string functionCode;
        //参数(分别为站号,起始地址,长度)
        private byte slaveAddress;
        private ushort startAddress;
        private ushort numberOfPoints;
        //串口参数
        private string portName;
        private int baudRate;
        private Parity parity;
        private int dataBits;
        private StopBits stopBits;

        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            cmb_portname.SelectedIndex = 0;
            cmb_baud.SelectedIndex = 5;
            cmb_parity.SelectedIndex = 2;
            cmb_databBits.SelectedIndex = 1;
            cmb_stopBits.SelectedIndex = 0;
        }
        private SerialPort InitSerialPortParameter()
        {
            if (cmb_portname.SelectedIndex < 0 || cmb_baud.SelectedIndex < 0 || cmb_parity.SelectedIndex < 0 || cmb_databBits.SelectedIndex < 0 || cmb_stopBits.SelectedIndex < 0)
            {
                MessageBox.Show("请选择串口参数");
                return null;
            }
            else
            {

                portName = cmb_portname.SelectedItem.ToString();
                baudRate = int.Parse(cmb_baud.SelectedItem.ToString());
                switch (cmb_parity.SelectedItem.ToString())
                {
                    case "奇":
                        parity = Parity.Odd;
                        break;
                    case "偶":
                        parity = Parity.Even;
                        break;
                    case "无":
                        parity = Parity.None;
                        break;
                    default:
                        break;
                }
                dataBits = int.Parse(cmb_databBits.SelectedItem.ToString());
                switch (cmb_stopBits.SelectedItem.ToString())
                {
                    case "1":
                        stopBits = StopBits.One;
                        break;
                    case "2":
                        stopBits = StopBits.Two;
                        break;
                    default:
                        break;
                }
                port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
                return port;
            }
        }
        /// <summary>
        /// 读/写
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                //初始化串口参数
                InitSerialPortParameter();

                master = ModbusSerialMaster.CreateRtu(port);

                ExecuteFunction();
            }
            catch (Exception)
            {
                MessageBox.Show("初始化异常");
            }
        }

        private async void ExecuteFunction()
        {
            try
            {
                //每次操作是要开启串口 操作完成后需要关闭串口
                //目的是为了slave更换连接是不报错
                if (port.IsOpen == false)
                {
                    port.Open();
                }
                if (functionCode != null)
                {
                    switch (functionCode)
                    {
                        case "01 Read Coils"://读取单个线圈
                            SetReadParameters();
                            coilsBuffer = master.ReadCoils(slaveAddress, startAddress, numberOfPoints);

                            for (int i = 0; i < coilsBuffer.Length; i++)
                            {
                                SetMsg(coilsBuffer[i] + " ");
                            }
                            SetMsg("\r\n");
                            break;
                        case "02 Read DisCrete Inputs"://读取输入线圈/离散量线圈
                            SetReadParameters();

                            coilsBuffer = master.ReadInputs(slaveAddress, startAddress, numberOfPoints);
                            for (int i = 0; i < coilsBuffer.Length; i++)
                            {
                                SetMsg(coilsBuffer[i] + " ");
                            }
                            SetMsg("\r\n");
                            break;
                        case "03 Read Holding Registers"://读取保持寄存器
                            SetReadParameters();
                            registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
                            for (int i = 0; i < registerBuffer.Length; i++)
                            {
                                SetMsg(registerBuffer[i] + " ");
                            }
                            SetMsg("\r\n");
                            break;
                        case "04 Read Input Registers"://读取输入寄存器
                            SetReadParameters();
                            registerBuffer = master.ReadInputRegisters(slaveAddress, startAddress, numberOfPoints);
                            for (int i = 0; i < registerBuffer.Length; i++)
                            {
                                SetMsg(registerBuffer[i] + " ");
                            }
                            SetMsg("\r\n");
                            break;
                        case "05 Write Single Coil"://写单个线圈
                            SetWriteParametes();
                            await master.WriteSingleCoilAsync(slaveAddress, startAddress, coilsBuffer[0]);
                            break;
                        case "06 Write Single Registers"://写单个输入线圈/离散量线圈
                            SetWriteParametes();
                            await master.WriteSingleRegisterAsync(slaveAddress, startAddress, registerBuffer[0]);
                            break;
                        case "0F Write Multiple Coils"://写一组线圈
                            SetWriteParametes();
                            await master.WriteMultipleCoilsAsync(slaveAddress, startAddress, coilsBuffer);
                            break;
                        case "10 Write Multiple Registers"://写一组保持寄存器
                            SetWriteParametes();
                            await master.WriteMultipleRegistersAsync(slaveAddress, startAddress, registerBuffer);
                            break;
                        default:
                            break;
                    }

                }
                else
                {
                    MessageBox.Show("请选择功能码!");
                }
                port.Close();
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox1.SelectedIndex >= 4)
            {
                groupBox2.Enabled = true;
                groupBox1.Enabled = false;
            }
            else
            {
                groupBox1.Enabled = true;
                groupBox2.Enabled = false;
            }
            comboBox1.Invoke(new Action(() => { functionCode = comboBox1.SelectedItem.ToString(); }));
        }

        /// <summary>
        /// 初始化读参数
        /// </summary>
        private void SetReadParameters()
        {
            if (txt_startAddr1.Text == "" || txt_slave1.Text == "" || txt_length.Text == "")
            {
                MessageBox.Show("请填写读参数!");
            }
            else
            {
                slaveAddress = byte.Parse(txt_slave1.Text);
                startAddress = ushort.Parse(txt_startAddr1.Text);
                numberOfPoints = ushort.Parse(txt_length.Text);
            }
        }
        /// <summary>
        /// 初始化写参数
        /// </summary>
        private void SetWriteParametes()
        {
            if (txt_startAddr2.Text == "" || txt_slave2.Text == "" || txt_data.Text == "")
            {
                MessageBox.Show("请填写写参数!");
            }
            else
            {
                slaveAddress = byte.Parse(txt_slave2.Text);
                startAddress = ushort.Parse(txt_startAddr2.Text);
                //判断是否写线圈
                if (comboBox1.SelectedIndex == 4 || comboBox1.SelectedIndex == 6)
                {
                    string[] strarr = txt_data.Text.Split(' ');
                    coilsBuffer = new bool[strarr.Length];
                    //转化为bool数组
                    for (int i = 0; i < strarr.Length; i++)
                    {
                        // strarr[i] == "0" ? coilsBuffer[i] = true : coilsBuffer[i] = false;
                        if (strarr[i] == "0")
                        {
                            coilsBuffer[i] = false;
                        }
                        else
                        {
                            coilsBuffer[i] = true;
                        }
                    }
                }
                else
                {
                    //转化ushort数组
                    string[] strarr = txt_data.Text.Split(' ');
                    registerBuffer = new ushort[strarr.Length];
                    for (int i = 0; i < strarr.Length; i++)
                    {
                        registerBuffer[i] = ushort.Parse(strarr[i]);
                    }
                }
            }
        }

        /// <summary>
        /// 清除文本
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            richTextBox1.Clear();
        }
        /// <summary>
        /// SetMessage
        /// </summary>
        /// <param name="msg"></param>
        public void SetMsg(string msg)
        {
            richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(msg); }));
        }

    }
}

接下来开始测试

在这里 因为要用到串口,而我的笔记本没有串口,所以需要借助一个工具

Virtual Serial Port Dirver 虚拟串口工具

链接:https://pan.baidu.com/s/1opGre3GS-HWFoA_dP9qYYg

提取码:2afu 

借用这个工具我们添加两个虚拟串口 COM1和COM2 点击Add Virtual Pair 添加

设置Modbus Slave,选择连接方式为串口,选择对应端口,模式选择RTU,建立连接

 

接下来运行我们自己的Modbus RTU Master

设置串口参数(波特率,数据位,奇偶校验,停止位)要与Slave的串口参数一致

我们测试 功能码 0x01 读一组线圈

 

测试完成,数据正常,其他的功能码经测试数据正常,有兴趣的可以自行测试

到此为止,Modbus的学习到此告一段落

以上都为我自行学习并实现,如有错误之处,望大家不吝赐教,感谢(抱拳~)

 

程序源代码:

链接:https://pan.baidu.com/s/1mPAhRixLbsDb7h2ePENTRA
提取码:b5w6

作者: Peter.Pan

出处: https://www.cnblogs.com/pandefu/>

邮箱: defu_pan@163.com

关于作者:.Net,WindowsForm,工控软件,Modbus,OPC/Tcp/Ip,串口通讯

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接,否则保留追究法律责任的权利。 如有问题, 可邮件咨询。

https://www.cnblogs.com/pandefu/p/10849823.html 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# Modbus Rtu实现 的相关文章

  • RS485通讯---Modbus数据链路层与应用层(二)

    前言 RS485通讯 Modbus物理层 xff1a https blog csdn net qq 36883460 article details 105630712 Modbus RTU通讯协议中OSI模型 xff0c 数据链路层和应用
  • Modbus超时时间设置

    很多同学在做Modbus通讯时 xff0c 需要连续读取多个现场设备的数据 xff0c 虽然也编写了Modbus轮询的程序 xff0c 但是有时还是无法正常通讯 有时虽然能够保证通讯 xff0c 但是所有现场设备的轮询周期很长 本文将从MB
  • Modbus Poll/Slave 模拟器使用教程

    一 Modbus协议 ModBus官网是Modicon xff08 Modicon被施耐德收购 xff09 公司为其PLC通讯而开发的一种通讯协议 Q1 什么是PLC xff1f A1 在工业生产过程中 xff0c 大量的开关量顺序控制 x
  • 详解 Modbus 通信协议(清晰易懂)

    文章目录 已剪辑自 https mp weixin qq com s dvo1l1GgJ2DtIHnPK5E1tA 本文总结关于 Modbus 相关的知识 xff0c 浅显易懂 xff0c 旨在对 Modbus 有一个很直观的了解 如有错误
  • AM2322温湿度传感器(地址0XB8)---I2C总结(I2C_ModBus协议)

  • 西门子PLC S7-200SMART Modbus TCP通讯的步骤和要点

    Modbus TCP是一个非常传统 xff0c 应用广泛的通讯协议 xff0c 很多智能设备都支持该协议 西门子S7 200SMART及1200 1500系列都免费支持 xff08 300和400还是要高昂收费 xff09 xff0c 并且
  • ESP32+485(MODBUS RTU)

    1 背景 需要采集功率表的功率及电量数据 xff0c 考虑采用ESP32采集数据后发送给服务器 所需硬件 xff1a ESP32开发板 485从机 232转485芯片 图1 连接示意图 2 实现 数字功率表采用Modbus RTU模式进行数
  • CRC-16 / MODBUS 校验计算方法

    CRC 16 MODBUS xff1a 1 xff09 CRC寄存器初始值为 FFFF xff1b 即16个字节全为1 xff1b 2 xff09 CRC 16 MODBUS的多项式A001H 1010 0000 0000 0001B H
  • C# Modbus CRC校验

    Modbus CRC校验 直接输入byte 输出bool public static bool CRC Check byte byteData bool Flag false byte CRC new byte 2 UInt16 wCrc
  • STM32读取RS485传感器数据,但接收到的数据开头总是多一个字节或少一个一字节,有人能告诉我哪里出问题了吗

    STM32读取RS485传感器数据 但接收到的数据开头总是多一个字节或少一个一字节 有人能告诉我哪里出问题了吗
  • QtModbus Serial 简单示例

    来自QQ群 Linux 技术分享 311078264 打开链接加入QQ群 https jq qq com wv 1027 k 5Gr3bAx 此文档由elikang整理 为了文章简单直接 许多细节未能在文章中体现 如有疑问请进群讨论 Qt
  • modbus之crc16计算代码

    这边提供两种方式 第1种是查表法方式 速度会快一点 但是需要多占用一些空间 第二种是纯计算方式 速度相对第一种会慢一点 但是比较省空间 代码如下 static const uint16 t crc table 0X0000 0XC0C1 0
  • Modbus常用功能码协议详解

    Modbus常用功能码协议详解 01H 读线圈状态 1 描述 读从机线圈寄存器 位操作 可读单个或者多个 2 发送指令 假设从机地址位0x01 寄存器开始地址0x0023 寄存器结束抵制0x0038 总共读取21个线圈 协议图如下 3 响应
  • Modbus驱动库—libmodbus驱动库的使用

    文章目录 为什么要使用驱动库 libmodbus简介 libmodbus常用函数 Windows平台libmodbus 使用 1 获取源代码 2 生成config h配置文件 3 编写测试代码 4 编译测试代码 Linux平台下libmod
  • STM32F429 HAL库移植FreeModbus_RTU详细步骤

    STM32F429 HAL库移FreeModbus RTU详细步骤 开发环境说明 完整工程文件下载地址 移植前提 修改 RS485 c 文件 修改 portserial c 文件 修改 porttimer c 文件 修改 stm32f4xx
  • modbus总线协议(一)modbus rtu

    一 介绍 Modbus协议由Modicon公司开发出来 现在Modbus是工业领域全球最流行的协议 硬件支持RS 232 RS 422 RS 485和以太网设备 应用在PLC DCS 智能仪表等工控领域 图片来源于网络 二 modbus协议
  • CRC-CCITT 到 CRC16 Modbus 实施

    我在使用 PHP 生成 modbus CRC16 代码时遇到很多麻烦 我在互联网上找到了很多不同的代码 但我尝试过它们 但由于某种原因我没有得到正确的结果 我找到了用于生成 CRC16 CCITT 的 PHP 代码 我已经将查找表更改为mo
  • 需要 modbus Java 库 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我需要带有源代码的简单 modbus Java 库 我在谷歌上找到了 但有 jar 文件 并且没有强大的
  • J2Mod 基本主从问题

    我正在尝试使用 Modbus 从站和主站j2mod 它的版本是 1 0 6 所以与另一个程序兼容 对于我在网上找到的代码 我确实有一些一般性问题 我几乎没有找到任何有用的文档 所以我有点无能为力 TCP主控器 this addr InetA
  • 从 Android 向 PLC 发送布尔值

    我能够与 PLC 建立连接以从中读取数据 现在有一个问题 那就是我必须编写一种方法来修改PLC中的数据 为了实现这一点 我必须向 PLC 发送两个值 一个 int 值和一个 boolean 值 我通过 net wimpi modbus 包中

随机推荐

  • eclipse JDT Plug-in Developer Guide

    文章目录 JDT Programmer s Guide JDT Programmer s Guide Eclipse平台是用一个全功能的Java集成开发环境 IDE 来传递的 Java开发工具 JDT 允许用户编写 编译 测试 调试和编辑用
  • Redis集合类型数据的统计模式

    Redis集合类型常见的四种统计模式 包括聚合统计 排序统计 二值状态统计和基数统计 聚合统计 所谓的聚合统计 就是指统计多个集合元素的聚合结果 包括 统计多个集合的共有元素 交集统计 把两个集合相比 统计其中一个集合独有的元素 差集统计
  • 【论文笔记】VLMO: Unified Vision-Language Pre-Training with Mixture-of-Modality-Experts

    1 介绍 1 1 视觉语言 VL 预训练的两种主流架构 1 dual encoder 分别对图像和文本进行编码 优点 检索任务 缺点 图像和文本之间的浅层交互不足以处理复杂的VL分类任务 2 单编码器 对模型图像 文本对进行跨模态关注的融合
  • 服务中找不mysql

    右键 计算机 点击 管理 然后点击 服务和应用程序 双击 服务 发现里面没有 MySql的服务 找到MySQL安装目录 我的是C Program Files MySQL MySQL Server 8 0 bin 打开cmd 进入MySQL的
  • java杨辉三角根据用户输入的行数n来显示杨辉三角的行数。

    import java util Scanner public class Main06 public static void main String args Scanner scanner new Scanner System in i
  • 高斯白噪声及Matlab常用实现方法

    http blog sina com cn s blog 4d7c97a00101cv5h html 一 概念 英文名称 white Gaussian noise WGN定义 均匀分布于给定频带上的高斯噪声 所谓高斯白噪声中的高斯是指概率分
  • 关于硬链接和软连接(符号链接)的区别

    linux系统下提供ln指令来进行文件链接 文件链接主要分为硬链接和软链接 硬链接 由于linux下的文件是通过索引节点 Inode 来识别文件 硬链接可以认为是一个指针 指向文件索引节点的指针 系统并不为它重新分配inode 每添加一个一
  • 计算机科学导论(5):计算机网络

    原文链接 计算机科学导论 5 计算机网络 远行的舟 参考 纪录片 互联网时代 计算机科学导论 TCP IP 入门经典 维基百科 阮一峰老师博客 哈尔滨工业大学阿里巴巴技术联盟互联网笔试面试整理 HTTP 权威指南 1776 年 3 月 瓦特
  • 几种负荷预测方法及其应用

    1 趋势分析法 趋势分析法称之趋势曲线分析 曲线拟合或曲线回归 它是迄今为止研究最多 也最为流行的定量预测方法 它是根据已知的历史资料来拟合一条曲线 使得这条曲线能反映负荷本身的增长趋势 然后按照这个增长趋势曲线 对要求的未来某一点估计出该
  • rust 学习笔记1

    RUST Rust 语言是一种高效 可靠的通用高级语言 其高效不仅限于开发效率 它的执行效率也是令人称赞的 是一种少有的兼顾开发效率和执行效率的语言 Rust的应用 Rust 语言可以用于开发 传统命令行程序 Rust 编译器可以直接生成目
  • MFC 单文档中添加OnPaint

    单文档中添加OnPaint 方法 1 在xxxView h里添加 生成的消息映射函数 protected DECLARE MESSAGE MAP public afx msg void OnPaint 2 实现OnPaint 3 在xxxV
  • 微信小程序渗透测试

    一 工具准备 burpsuite 夜神模拟器 把微信装好 node js wxappUnpacker 二 获取源码 1 配置Burp和模拟器 模拟器需导入ca证书 打开模拟器的WLAN gt 高级设置 gt 输入物理机的ip以及一个没被占用
  • Gof23设计模式之原型模式

    1 概述 用一个已经创建的实例作为原型 通过复制该原型对象来创建一个和原型对象相同的新对象 2 结构 原型模式包含一下角色 抽象原型类 规定了具体原型对象必须实现的clone 方法 具体原型类 实现了抽象圆形类的clone 方法 它是可被复
  • ASP.NET开发公众号时微信支付遇到签名错误

    请求返回来xml数据
  • 7-21 口罩发放(标准注释+测试点说明)

    为了抗击来势汹汹的 COVID19 新型冠状病毒 全国各地均启动了各项措施控制疫情发展 其中一个重要的环节是口罩的发放 某市出于给市民发放口罩的需要 推出了一款小程序让市民填写信息 方便工作的开展 小程序收集了各种信息 包括市民的姓名 身份
  • 事件流及事件处理程序总结

    事件流 事件捕获阶段 处于目标阶段 事件冒泡阶段 事件捕获与事件冒泡的区别 如何阻止事件的默认行为 以及如何阻止事件冒泡 事件捕获和事件冒泡的概念是相反的 事件捕获 不具体的节点更早接收到事件 而最具体的节点最后接收到事件 DOM2级事件
  • EndNote在Word中插入文献不能自动生成编号 - 解决方案

    本文出处 新浪博客 小数码植物摄影 之http blog sina com cn s blog 629be3eb0100sih3 html 新浪博客 小数码植物摄影 首页 http blog sina com cn u 1654383595
  • Android Studio中怎样引用图片资源

    随着不断接触Android Studio 越来越发现和Eclipse有着巨大的差别 不管是表面的目录结构 还是内在对各种资源的管理 本篇就来聊聊Android Studio中怎样来显示图片 以及与Eclipse中的差别 在Eclipse中依
  • requests爬虫遇到404怎么办_Python爬虫基础库和实践

    爬虫有三大基础库Requests BeautifulSoup和Lxml 这三大库对于初学者使用频率最高 现在大家一起来看看这基础三大库的使用 Requests库 Requests库的作用就是请求网站获取网页数据 Code res reque
  • C# Modbus Rtu实现

    Modbus Rtu的实现与Modbus Tcp的实现类似 C ModBus Tcp的学习及Master的实现 我们还是需要借用一个开源库NModbus4 在vs中 打开NuGet管理器 安装NModbus4 具体实现 具体实现与之前的Mo