zoukankan      html  css  js  c++  java
  • C#Modbus Rtu的实现

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

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

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

      1 using System;
      2 using System.Collections.Generic;
      3 using System.ComponentModel;
      4 using System.Data;
      5 using System.Drawing;
      6 using System.Linq;
      7 using System.Text;
      8 using System.Threading.Tasks;
      9 using System.Windows.Forms;
     10 using Modbus.Device;
     11 using System.Net.Sockets;
     12 using System.Threading;
     13 using System.IO.Ports;
     14 
     15 namespace ModbusRtu
     16 {
     17     public partial class Form1 : Form
     18     {
     19         private static IModbusMaster master;
     20         private static SerialPort port;
     21         //写线圈或写寄存器数组
     22         private bool[] coilsBuffer;
     23         private ushort[] registerBuffer;
     24         //功能码
     25         private string functionCode;
     26         //参数(分别为站号,起始地址,长度)
     27         private byte slaveAddress;
     28         private ushort startAddress;
     29         private ushort numberOfPoints;
     30         //串口参数
     31         private string portName;
     32         private int baudRate;
     33         private Parity parity;
     34         private int dataBits;
     35         private StopBits stopBits;
     36 
     37         public Form1()
     38         {
     39             InitializeComponent();
     40         }
     41         private void Form1_Load(object sender, EventArgs e)
     42         {
     43             cmb_portname.SelectedIndex = 0;
     44             cmb_baud.SelectedIndex = 5;
     45             cmb_parity.SelectedIndex = 2;
     46             cmb_databBits.SelectedIndex = 1;
     47             cmb_stopBits.SelectedIndex = 0;
     48         }
     49         private SerialPort InitSerialPortParameter()
     50         {
     51             if (cmb_portname.SelectedIndex < 0 || cmb_baud.SelectedIndex < 0 || cmb_parity.SelectedIndex < 0 || cmb_databBits.SelectedIndex < 0 || cmb_stopBits.SelectedIndex < 0)
     52             {
     53                 MessageBox.Show("请选择串口参数");
     54                 return null;
     55             }
     56             else
     57             {
     58 
     59                 portName = cmb_portname.SelectedItem.ToString();
     60                 baudRate = int.Parse(cmb_baud.SelectedItem.ToString());
     61                 switch (cmb_parity.SelectedItem.ToString())
     62                 {
     63                     case "":
     64                         parity = Parity.Odd;
     65                         break;
     66                     case "":
     67                         parity = Parity.Even;
     68                         break;
     69                     case "":
     70                         parity = Parity.None;
     71                         break;
     72                     default:
     73                         break;
     74                 }
     75                 dataBits = int.Parse(cmb_databBits.SelectedItem.ToString());
     76                 switch (cmb_stopBits.SelectedItem.ToString())
     77                 {
     78                     case "1":
     79                         stopBits = StopBits.One;
     80                         break;
     81                     case "2":
     82                         stopBits = StopBits.Two;
     83                         break;
     84                     default:
     85                         break;
     86                 }
     87                 port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
     88                 return port;
     89             }
     90         }
     91         /// <summary>
     92         /// 读/写
     93         /// </summary>
     94         /// <param name="sender"></param>
     95         /// <param name="e"></param>
     96         private void button1_Click(object sender, EventArgs e)
     97         {
     98             try
     99             {
    100                 //初始化串口参数
    101                 InitSerialPortParameter();
    102 
    103                 master = ModbusSerialMaster.CreateRtu(port);
    104 
    105                 ExecuteFunction();
    106             }
    107             catch (Exception)
    108             {
    109                 MessageBox.Show("初始化异常");
    110             }
    111         }
    112 
    113         private async void ExecuteFunction()
    114         {
    115             try
    116             {
    117                 //每次操作是要开启串口 操作完成后需要关闭串口
    118                 //目的是为了slave更换连接是不报错
    119                 if (port.IsOpen == false)
    120                 {
    121                     port.Open();
    122                 }
    123                 if (functionCode != null)
    124                 {
    125                     switch (functionCode)
    126                     {
    127                         case "01 Read Coils"://读取单个线圈
    128                             SetReadParameters();
    129                             coilsBuffer = master.ReadCoils(slaveAddress, startAddress, numberOfPoints);
    130 
    131                             for (int i = 0; i < coilsBuffer.Length; i++)
    132                             {
    133                                 SetMsg(coilsBuffer[i] + " ");
    134                             }
    135                             SetMsg("
    ");
    136                             break;
    137                         case "02 Read DisCrete Inputs"://读取输入线圈/离散量线圈
    138                             SetReadParameters();
    139 
    140                             coilsBuffer = master.ReadInputs(slaveAddress, startAddress, numberOfPoints);
    141                             for (int i = 0; i < coilsBuffer.Length; i++)
    142                             {
    143                                 SetMsg(coilsBuffer[i] + " ");
    144                             }
    145                             SetMsg("
    ");
    146                             break;
    147                         case "03 Read Holding Registers"://读取保持寄存器
    148                             SetReadParameters();
    149                             registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
    150                             for (int i = 0; i < registerBuffer.Length; i++)
    151                             {
    152                                 SetMsg(registerBuffer[i] + " ");
    153                             }
    154                             SetMsg("
    ");
    155                             break;
    156                         case "04 Read Input Registers"://读取输入寄存器
    157                             SetReadParameters();
    158                             registerBuffer = master.ReadInputRegisters(slaveAddress, startAddress, numberOfPoints);
    159                             for (int i = 0; i < registerBuffer.Length; i++)
    160                             {
    161                                 SetMsg(registerBuffer[i] + " ");
    162                             }
    163                             SetMsg("
    ");
    164                             break;
    165                         case "05 Write Single Coil"://写单个线圈
    166                             SetWriteParametes();
    167                             await master.WriteSingleCoilAsync(slaveAddress, startAddress, coilsBuffer[0]);
    168                             break;
    169                         case "06 Write Single Registers"://写单个输入线圈/离散量线圈
    170                             SetWriteParametes();
    171                             await master.WriteSingleRegisterAsync(slaveAddress, startAddress, registerBuffer[0]);
    172                             break;
    173                         case "0F Write Multiple Coils"://写一组线圈
    174                             SetWriteParametes();
    175                             await master.WriteMultipleCoilsAsync(slaveAddress, startAddress, coilsBuffer);
    176                             break;
    177                         case "10 Write Multiple Registers"://写一组保持寄存器
    178                             SetWriteParametes();
    179                             await master.WriteMultipleRegistersAsync(slaveAddress, startAddress, registerBuffer);
    180                             break;
    181                         default:
    182                             break;
    183                     }
    184 
    185                 }
    186                 else
    187                 {
    188                     MessageBox.Show("请选择功能码!");
    189                 }
    190                 port.Close();
    191             }
    192             catch (Exception ex)
    193             {
    194 
    195                 MessageBox.Show(ex.Message);
    196             }
    197         }
    198         private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    199         {
    200             if (comboBox1.SelectedIndex >= 4)
    201             {
    202                 groupBox2.Enabled = true;
    203                 groupBox1.Enabled = false;
    204             }
    205             else
    206             {
    207                 groupBox1.Enabled = true;
    208                 groupBox2.Enabled = false;
    209             }
    210             comboBox1.Invoke(new Action(() => { functionCode = comboBox1.SelectedItem.ToString(); }));
    211         }
    212 
    213         /// <summary>
    214         /// 初始化读参数
    215         /// </summary>
    216         private void SetReadParameters()
    217         {
    218             if (txt_startAddr1.Text == "" || txt_slave1.Text == "" || txt_length.Text == "")
    219             {
    220                 MessageBox.Show("请填写读参数!");
    221             }
    222             else
    223             {
    224                 slaveAddress = byte.Parse(txt_slave1.Text);
    225                 startAddress = ushort.Parse(txt_startAddr1.Text);
    226                 numberOfPoints = ushort.Parse(txt_length.Text);
    227             }
    228         }
    229         /// <summary>
    230         /// 初始化写参数
    231         /// </summary>
    232         private void SetWriteParametes()
    233         {
    234             if (txt_startAddr2.Text == "" || txt_slave2.Text == "" || txt_data.Text == "")
    235             {
    236                 MessageBox.Show("请填写写参数!");
    237             }
    238             else
    239             {
    240                 slaveAddress = byte.Parse(txt_slave2.Text);
    241                 startAddress = ushort.Parse(txt_startAddr2.Text);
    242                 //判断是否写线圈
    243                 if (comboBox1.SelectedIndex == 4 || comboBox1.SelectedIndex == 6)
    244                 {
    245                     string[] strarr = txt_data.Text.Split(' ');
    246                     coilsBuffer = new bool[strarr.Length];
    247                     //转化为bool数组
    248                     for (int i = 0; i < strarr.Length; i++)
    249                     {
    250                         // strarr[i] == "0" ? coilsBuffer[i] = true : coilsBuffer[i] = false;
    251                         if (strarr[i] == "0")
    252                         {
    253                             coilsBuffer[i] = false;
    254                         }
    255                         else
    256                         {
    257                             coilsBuffer[i] = true;
    258                         }
    259                     }
    260                 }
    261                 else
    262                 {
    263                     //转化ushort数组
    264                     string[] strarr = txt_data.Text.Split(' ');
    265                     registerBuffer = new ushort[strarr.Length];
    266                     for (int i = 0; i < strarr.Length; i++)
    267                     {
    268                         registerBuffer[i] = ushort.Parse(strarr[i]);
    269                     }
    270                 }
    271             }
    272         }
    273 
    274         /// <summary>
    275         /// 清除文本
    276         /// </summary>
    277         /// <param name="sender"></param>
    278         /// <param name="e"></param>
    279         private void button2_Click(object sender, EventArgs e)
    280         {
    281             richTextBox1.Clear();
    282         }
    283         /// <summary>
    284         /// SetMessage
    285         /// </summary>
    286         /// <param name="msg"></param>
    287         public void SetMsg(string msg)
    288         {
    289             richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(msg); }));
    290         }
    291 
    292     }
    293 }
    View Code

    接下来开始测试

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

    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

  • 相关阅读:
    hbase-15-如何查看HFile
    Hbase-14-MemStore Flush的触发时机
    Hbase-13-MemStore
    【c++】C++中erase的用法
    Redis五种数据结构(转载)
    redis的三种集群方式 (转载)
    hbase和hive的差别是什么,各自适用在什么场景中?(转载)
    vue 数据已经更新了但是页面未更新
    uni-app配置跨域
    覆盖 web-view (uni-app)
  • 原文地址:https://www.cnblogs.com/pandefu/p/10849823.html
Copyright © 2011-2022 走看看