首页 > 编程语言 >C#Modbus Rtu的实现

C#Modbus Rtu的实现

时间:2023-11-06 18:47:58浏览次数:34  
标签:case break C# Text cmb private Modbus coilsBuffer Rtu

C#Modbus Rtu的实现

在次记录一下自己的学习资料,只为对网上的数据收集,方便以后查找,如若侵犯版权请联系删除

Modbus Rtu的实现与Modbus Tcp的实现类似https://www.cnblogs.com/pandefu/p/10824331.html

我们还是需要借用一个开源库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 读一组线圈

 

标签:case,break,C#,Text,cmb,private,Modbus,coilsBuffer,Rtu
From: https://www.cnblogs.com/hezq/p/17813405.html

相关文章

  • BUUCTF_Crypto_WriteUp | RSA
    题目(原题的拼写错误)在一次RSA密钥对生成中,假设p=473398607161,q=4511491,e=17求解出d作为flga提交分析回顾一下RSA算法描述:RSA算法的具体描述如下:(1)任意选取两个不同的大素数p和q计算乘积\(n=pq,\varphi(n)=(p-1)(q-1)\);(2)任意选取一个大整数e,满足\(gcd(e,\varphi(n......
  • conda环境导入到新的windows 10遇到的问题
    执行condaenvcreate-ffilename.yaml报错Nopackagesfoundincurrentwin-64channelsmatching:ca-certificates2023.01.10haa95532_0删除掉这行,执行还是会报错找不到下一行的包然后执行ca-certificates2023.01.10haa95532_0ca-certificates2023.01.10haa95532......
  • Amazon EC2 Hpc7g 实例现已在更多区域推出
    即日起,AmazonElasticComputeCloud(AmazonEC2)Hpc7g实例将在亚太地区(东京)、欧洲地区(爱尔兰)和AmazonGovCloud(美国西部)区域推出。AmazonEC2Hpc7g实例由 AmazonGraviton处理器提供支持,这些处理器是由亚马逊云科技设计的基于Arm的自定义处理器。亚马逊云科技开发者社......
  • Oracledb_exporter 获取表大小信息的简单方法
    Oracledb_exporter获取表大小信息的简单方法背景用我儿子的现状作为背景:我爱学习,学习让我妈快乐.下载exporterexporter可以在github上面下载最新版本是0.5.1https://github.com/iamseth/oracledb_exporter可以直接下载release好的二进制,也可以dockerpull......
  • Groceries in Meteor Town 题解
    GroceriesinMeteorTown题目大意维护一颗带权树,支持以下操作:将\([l,r]\)内的点变为白色。将\([l,r]\)内的点变为黑色。查询点\(x\)到任意一个白色节点的简单路径上的最大值。思路分析没事干了把以前的题拿出来写题解。看到『简单路径上的最大值』的字样首......
  • Debug - MySQL - Err 1062 duplicate entry xxxx for key xxx
    可能原因1脏数据存在 可能原因2当你手动刷sql修改表结构时,可能这张表正有写库操作。一边写库一边修改表结构,就会出现这种错误。。。原因未知,猜测和锁表有关系 两次错误提示:详细的数据是不一样的....而且日期是今天的,说明不是脏数据  等待写库程序结束,再刷表就没......
  • BUUCTF_Crypto_WriteUp | Rabbit
    题目U2FsdGVkX1/+ydnDPowGbjjJXhZxm2MP2AgI分析字符串中除了大小写字母和零星数字外有俩很可疑的符号“/”和“+”,猜测是Base系列编码。用Base64解码得到一串可疑的字符Salted__þÉÙÃ>Œn8É^q›cØ。不对劲。打开浏览器......
  • mysql 使用ON DUPLICATE KEY update实现插入或更新操作
    创建一个表CREATETABLE`userinfo`(`UserID`int(11)NOTNULL,`UserName`varchar(45)CHARACTERSETutf8COLLATEutf8_general_ciDEFAULTNULL,PRIMARYKEY(`UserID`))ENGINE=InnoDBDEFAULTCHARSET=utf8;想要实现,没有数据插入新数据,有数据更新数据首先......
  • 海外短剧cps分销系统短剧小程序软件开发
      移动端的用户在不断的增加,移动端的内容也在不断的扩大,其中海外短剧的作为一种新的独特表现形式,正在逐渐的受到全球观众的青睐。为了解决这些用户市场,开发一款高效的短剧小程序软件,方便海外的短剧CPS分销系统的实现,这就是短剧系统小程序软件的重要性。  移动端海外短剧CP......
  • 文心一言 VS 讯飞星火 VS chatgpt (129)-- 算法导论11.1 4题
    四、用go语言,我们希望在一个非常大的数组上,通过利用直接寻址的方式来实现一个字典。开始时该数组中可能包含一些无用信息,但要对整个数组进行初始化是不太实际的,因为该数组的规模太大。请给出在大数组上实现直接寻址字典的方案。每个存储对象占用O(1)空间;SEARCH、INSERT和DELETE操......