C#Modbus Rtu的實現

来源:https://www.cnblogs.com/pandefu/archive/2019/05/11/10849823.html
-Advertisement-
Play Games

Modbus Rtu的實現與Modbus Tcp的實現類似 C#ModBus Tcp的學習及Master的實現 我們還是需要借用一個開源庫NModbus4,在vs中.打開NuGet管理器.安裝NModbus4 具體實現,具體實現與之前的Modbus Tcp的實現類似 ,只是在實例化master時將T ...


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("\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

接下來開始測試

在這裡 因為要用到串口,而我的筆記本沒有串口,所以需要藉助一個工具

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

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • [學習筆記] 1.Eureca Server的Helloworld例子:做個普通的maven project,quickstart archetype。改成jdk.8。下麵Camden.SR1是版本名,springcloud的版本名稱很奇特,它是按照倫敦地鐵站的名稱命名的。馬 克-to-win@馬克 ...
  • 1.複習 2.匿名函數 3.作用域 4.函數式編程 4.map函數 5.filter函數 6.reduce函數 7.小結 8.內置函數 ...
  • 美食排行榜網站上線後,為了快速提升流量,需要製造一個引流機會。 我的想法是開闢一個專欄,按照菜品和地區,讓用戶自發投票給自己喜歡的餐館,最終形成一個年度/月度 等的美食排行榜 比如 成都川菜美食排行榜 這個頁面,目前是按照數據入庫的先後時間排序,並不是用戶真實的排行,怎麼才能做到真實排行呢? 這就需 ...
  • 基於flask的網頁聊天室(三) 前言 繼續上一次的內容,今天完成了csrf防禦的添加,用戶頭像的存儲以及用戶的登錄狀態 具體內容 首先是添加csrf的防禦,為整個app添加防禦: from flask_wtf.csrf import CSRFProtect CSRFProtect(app) 這個添 ...
  • 1.Equals 很多人對equals方法的用法有些模糊,這裡來為大家梳理下: 字元串中的equals方法,該方法用來判斷兩個字元串的內容是否相同。 例1: 從例1中我們可以看出,兩個字元串之間的比較,無論用”==”號還是equals來進行,只要內容相同,結果就為True,內容不同,結果就為Fals ...
  • [TOC] 手寫數字識別流程 MNIST手寫數字集7000 10張圖片 60k張圖片訓練,10k張圖片測試 每張圖片是28\ 28,如果是彩色圖片是28\ 28\ 3 0 255表示圖片的灰度值,0表示純白,255表示純黑 打平28 28的矩陣,得到28\ 28=784的向量 對於b張圖片得到[b, ...
  • 前置知識: 棧 隊列 單調棧 思考這樣一個問題:給定一個數列,詢問每一個數左邊的第一個比它小的數。 暴力的做法是:記錄下所有讀進來的數,然後,每次向前查找,預計時間複雜度O(n2),而且容易被卡。 仔細思考一下,可以發現,這個做法之所以效率低下,是因為每一次都重覆查找了許多肯定不是最優解的元素。很明 ...
  • 基於ASP.NET MVC 實現layui富文本編輯器圖片展示 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...