当前位置:   article > 正文

c# 与modbus_c# modbus

c# modbus

Modbus Slave从站模拟器

从站模拟器使用
在这里插入图片描述
在这里插入图片描述

NModbus4 库

用的都是这个库
在这里插入图片描述
在这里插入图片描述

using System.IO.Ports;//串口
using Modbus.Device;
  • 1
  • 2

串口通信

通过使用虚拟串口进行仿真
在这里插入图片描述

using System.IO.Ports;//串口
using Modbus.Device;
  • 1
  • 2
public static SerialPort serialPort1;
private static IModbusMaster master;//也可以后面通过var的方式做一个创建一个
  • 1
  • 2

设置串口

load

            try
            {
                Updata_Serialport_Name(ComComboBox1);  //调用更新可用串口函数,comboBox1为 端口 组合框名字
                BaudComboBox2.Items.Add(115200);
                BaudComboBox2.Items.Add(9600);
                BaudComboBox2.Text = "115200";


                StopComboBox3.Items.Add(System.IO.Ports.StopBits.One);
                StopComboBox3.Items.Add(System.IO.Ports.StopBits.OnePointFive);
                StopComboBox3.Items.Add(System.IO.Ports.StopBits.Two);
                StopComboBox3.Text = System.IO.Ports.StopBits.One.ToString();

                DataComboBox4.Items.Add(8);
                DataComboBox4.Text = "8";

                CheckComboBox5.Items.Add(System.IO.Ports.Parity.None);//在表单中显示的就是enum的名字 而不是一串数
                CheckComboBox5.Items.Add(System.IO.Ports.Parity.Odd);
                CheckComboBox5.Items.Add(System.IO.Ports.Parity.Even);
                CheckComboBox5.Text = System.IO.Ports.Parity.None.ToString();

                CollectuiComboBox1.Items.Add("单次");
                CollectuiComboBox1.Items.Add("连续");
                CollectuiComboBox1.Text = "单次";



            }
            catch (Exception ex)
            {

                MessageBox.Show("串口打开异常" + serialPort1.PortName);
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

Updata_Serialport_Name

        /*用户自定义更新可用串口函数*/
        private static void Updata_Serialport_Name(UIComboBox MycomboBox)
        {
            //System.IO.Ports.SerialPort.GetPortNames()函数功能为获取计算机所有可用串口,以字符串数组形式输出
            string[] ArryPort = System.IO.Ports.SerialPort.GetPortNames(); //定义字符串数组,数组名为 ArryPort,将可用的串口信息存放在字符串中
            MycomboBox.Items.Clear();       //清除当前组合框下拉菜单内容                  
            for (int i = 0; i < ArryPort.Length; i++)
            {
                MycomboBox.Items.Add(ArryPort[i]);   //将所有的可用串口号添加到端口对应的组合框中
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

打开串口

            try
            {
                //在打开串口之前获取串口号和波特率
                serialPort1.PortName = ComComboBox1.Text;
                //转换为10进制,10可省略
                serialPort1.BaudRate = Convert.ToInt32(BaudComboBox2.Text, 10);

                Parity NIParity = (Parity)Enum.Parse(typeof(Parity), CheckComboBox5.Text);//字符串转枚举
                serialPort1.Parity = NIParity;//这段再研究下 如何实现文本转enum中的某个值

                //MessageBox.Show(StopComboBox3.Text);这个是none
                //MessageBox.Show(StopComboBox3.SelectedText);这个打印出来是空白
                StopBits NIStopBits = (StopBits)Enum.Parse(typeof(StopBits), StopComboBox3.Text);//字符串转枚举
                                                                                                 //serialPort1.StopBits = System.IO.Ports.StopBits.One;
                serialPort1.StopBits = NIStopBits;

                serialPort1.DataBits = Convert.ToInt32(DataComboBox4.Text, 10);

                //serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(serialPort1_DataReceived);

                serialPort1.ReceivedBytesThreshold = 1;

                //打开串口
                serialPort1.Open();
                //打开串口按钮不可用,变成灰色
                OpenuiButton2.Enabled = false;
                //关闭串口按钮可用。
                CloseuiButton3.Enabled = true;

                master = ModbusSerialMaster.CreateRtu(serialPort1);//这里传入的就是我们创建的串口对象
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

关闭串口

            try
            {
                //关闭串口
                serialPort1.Close();
                //打开串口按钮可用
                OpenuiButton2.Enabled = true;
                //关闭串口按钮不可用,变成灰色
                CloseuiButton3.Enabled = false;
            }
            catch
            {
                //一般关闭串口不出错,此处对程序不进行处理
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

写数据

            //var master = ModbusSerialMaster.CreateRtu(serialPort1);//这里传入的就是我们创建的串口对象
            byte slaveid = byte.Parse(SlaveIDuiTextBox1.Text);//将int32转换为字节数组
            
            ushort value = 1;
            if (CollectuiComboBox1.Text == "单次")
            {               
                value = 1;
            }
            else value = 2;

            //写寄存器值  这个函数就是对应 2号 功能码
            // 2号寄存器  
            master.WriteSingleRegister(slaveid, 2, value);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

读数据

            //将串口对象添加到modbus中
            //var master = ModbusSerialMaster.CreateRtu(serialPort1);//这里传入的就是我们创建的串口对象

            byte slaveid = byte.Parse(SlaveIDuiTextBox1.Text);//将int32转换为字节数组
            ushort[] value1 = master.ReadHoldingRegisters(slaveid, 0x0, 2);
            string value = value1[0].ToString() + value1[1].ToString();
            illuminanceuiTextBox1.Text = value;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

线圈状态

相当于控制设备上的一些开关量
读对应功能码01 写对应功能码05
就是true或者false具体用到再详细了解 暂时也用不到
在这里插入图片描述
结果
在这里插入图片描述

在这里插入图片描述

设置连续的读

用到一个多线程,就能一直监控这数据了

            //设置连续的读 一直拿数据
            Task.Run(() => 
            { 
                //需要加上while 这样就能一直在这个循环中了 不然执行一遍就结束
                while(true)
                {
                    //读寄存器值
                    //就是对应03功能码  slave地址1 访问10号寄存器 访问两个
                    ushort[] values = master.ReadHoldingRegisters(1, 10, 2);
                    //打印访问的结果 访问结果就是存放在values[0]和[1]中的
                    Console.WriteLine(values[0] + "" + values[1]);
                }

            });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这里插入图片描述

网口通信

在这里插入图片描述

using System.Net.Sockets;
  • 1

获取温度

        private void button1_Click_1(object sender, EventArgs e)
        {
            //点一下获取一下
            //1、创建连接TcpClient
            TcpClient tcpClient = new TcpClient();//需要 using System.Net.Sockets;
            tcpClient.Connect("127.0.0.1", 502);
           
            //2、创建主站访问对象 将创建的tcp客户端添加到modbus中
            Modbus.Device.ModbusIpMaster master = Modbus.Device.ModbusIpMaster.CreateIp(tcpClient);//需要system.IO.Port库 和NModbus4一样安装就行
            //3、读取寄存器数据 并写入NitextBox1中
            ushort[] values = master.ReadHoldingRegisters(1, 0, 1);//光标放在函数上面会显示要填的参数的含义。slaveID 0号寄存器 读1个 这个函数返回的是一个uchort数组
            NitextBox1.Text = values[0].ToString();//NitextBox1就是第一个textBox的name
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

写入转速

        private void button1_Click(object sender, EventArgs e) //点击查看所有引用的时候,就可以发现这些个点击函数也是在InitializeComponent()函数中被注册进去的
        {
            ushort value = ushort.Parse(speedtextBox.Text);// 取页面数据

             //1、创建连接
            TcpClient tcpClient = new TcpClient();//需要 using System.Net.Sockets;
            tcpClient.Connect("127.0.0.1", 502);
            //2、创建主站访问对象
            Modbus.Device.ModbusIpMaster master = Modbus.Device.ModbusIpMaster.CreateIp(tcpClient);//需要system.IO.Port库 和NModbus4一样安装就行    
           
            master.WriteSingleRegister(1, 1, value);// 写入设备寄存器

        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

持续不断的读

这块是持续不断地读取 类似做监控这样

      
          
                        Control.CheckForIllegalCrossThreadCalls = false;//不检查非法的跨线程操作

                        //1、创建连接
                        TcpClient tcpClient = new TcpClient();//需要 using System.Net.Sockets;
                        tcpClient.Connect("127.0.0.1", 502);
                        //2、创建主站访问对象
                        Modbus.Device.ModbusIpMaster master = Modbus.Device.ModbusIpMaster.CreateIp(tcpClient);//需要system.IO.Port库 和NModbus4一样安装就行

                        //如果要持续读取的话,就要新开一个线程
                        Task.Run(async () => 
                        {
                            while (true )
                            {
                                await Task.Delay(1000);
                                //3、读取寄存器数据 并写入NitextBox1中
                                ushort[] values = master.ReadHoldingRegisters(1, 0, 1);//光标放在函数上面会显示要填的参数的含义。slaveID 0号寄存器 读1个 这个函数返回的是一个uchort数组
                                try //通过断点调试 发现了卡在了这里。通过try和catch的方式,就将出现的异常捕获了
                                {
                                    NitextBox1.Text = values[0].ToString();//NitextBox1就是第一个textBox的name
                                }
                                catch (Exception ex) 
                                { 
                                    MessageBox.Show(ex.Message);//错误的原因是进程间操作无效 使用一个简单的操作 就是关闭检测进程间的合法性
                                }

                            }       
                        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

c#接收flaot

在这里插入图片描述
接受到的是两个字节ushort

//直接调用ReadDate函数,接收到的数据会自动保存入 ushort[] value1 中
//一个ushort占用两个字节,一共接收到2个ushort,共四个字节
//调用GetFloat即可实现转换
        public static void ReadDate()
        {
                ushort startAddress = 0x0066;
                ushort numberOfPoints = 2;
                ushort[] value1 = master.ReadHoldingRegisters(1, startAddress, numberOfPoints);
                log.SaveLog("value1字节数:"+value1.Length.ToString());

                float valuefloat;
                valuefloat = GetFloat(value1[0], value1[1]);

                log.SaveLog("流量" + valuefloat);
            
        }
        
        public static float GetFloat(ushort P1, ushort P2)
        {
            int intSign, intSignRest, intExponent, intExponentRest;
            float faResult, faDigit;
            intSign = P1 / 32768;
            intSignRest = P1 % 32768;
            intExponent = intSignRest / 128;
            intExponentRest = intSignRest % 128;
            faDigit = (float)(intExponentRest * 65536 + P2) / 8388608;
            faResult = (float)Math.Pow(-1, intSign) * (float)Math.Pow(2, intExponent - 127) * (faDigit + 1);
            return faResult;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

在这里插入图片描述

try catch捕获异常

在这里插入图片描述

虚拟串口

使用详解
在这里插入图片描述
在这里插入图片描述
一个使用COM1一个使用COM2 就可以进行通信了
在这里插入图片描述
在这里插入图片描述

参考资料

视频 这个讲的都是串口的
网口的视频讲解

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/566198
推荐阅读
相关标签
  

闽ICP备14008679号