C#Modbus Rtu的實現

Modbus Rtu的實現與Modbus Tcp的實現相似 C#ModBus Tcp的學習及Master的實現html

咱們仍是須要借用一個開源庫NModbus4,在vs中.打開NuGet管理器.安裝NModbus4數組

 

具體實現,具體實現與以前的Modbus Tcp的實現相似 ,只是在實例化master時將TCPClient換爲串行端口資源SerialPort,並在實例化是設置好端口所需參數(端口名,波特率,校驗位,中止位,數據位)async

 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("\r\n"); 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("\r\n"); 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("\r\n"); 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("\r\n"); 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

接下來開始測試ide

在這裏 由於要用到串口,而個人筆記本沒有串口,因此須要藉助一個工具工具

Virtual Serial Port Dirver 虛擬串口工具 學習

連接:https://pan.baidu.com/s/1opGre3GS-HWFoA_dP9qYYg 測試

提取碼:2afu spa

借用這個工具咱們添加兩個虛擬串口 COM1和COM2 點擊Add Virtual Pair 添加code

設置Modbus Slave,選擇鏈接方式爲串口,選擇對應端口,模式選擇RTU,創建鏈接orm

 

接下來運行咱們本身的Modbus RTU Master

設置串口參數(波特率,數據位,奇偶校驗,中止位)要與Slave的串口參數一致

咱們測試 功能碼 0x01 讀一組線圈

測試完成,數據正常,其餘的功能碼經測試數據正常,有興趣的能夠自行測試

到此爲止,Modbus的學習到此告一段落

以上都爲我自行學習並實現,若有錯誤之處,望你們不吝賜教,感謝(抱拳~)

 

程序源代碼:

連接:https://pan.baidu.com/s/1mPAhRixLbsDb7h2ePENTRA
提取碼:b5w6

 

原文出處:https://www.cnblogs.com/pandefu/p/10849823.html

相關文章
相關標籤/搜索