C# 開發Modbus Rtu用戶端 modbus測試Demo,Modbus 串口通訊 , 虛擬MODBUS-RTU測試

來源:互聯網
上載者:User

標籤:basic   定義   ref   show   接下來   private   字串   複雜   長度   

前言

 本文將使用一個NuGet公開的組件技術來實現一個ModBus RTU的用戶端,方便的對Modbus rtu的伺服器進行讀寫,這個伺服器可以是電腦端C#設計的,也可以是PLC實現的,也可以是其他任何支援這個通訊協定的伺服器。

github地址:https://github.com/dathlin/HslCommunication 如果喜歡可以star或是fork,還可以打賞支援。

 

在Visual Studio 中的NuGet管理器中可以下載安裝,也可以直接在NuGet控制台輸入下面的指令安裝:

Install-Package HslCommunication

NuGet安裝教程  http://www.cnblogs.com/dathlin/p/7705014.html

支援人員QQ群:592132877  (組件的版本更新細節也將第一時間在群裡發布)組件API地址:http://www.cnblogs.com/dathlin/p/7703805.html

 

 

特別感謝
  • 網友:陳恩富                  對float,int資料的讀取測試,才修複了權重位顛倒的BUG。
  • 網友:U4幸福的蝸牛      發現了部落格上錯誤的一個方法名稱,已於2018年1月8日13:34:39更新。並反饋了一些特殊裝置(modbus tcp伺服器)的讀取資料的BUG。已修複。

 

隨便聊聊

此處的設計模式是用戶端主動請求伺服器資料,然後接收伺服器的反饋資料,支援原生的指令收發,支援其他一些方便的API收發。特殊功能碼需要使用原生收發的API,本組件支援如下的功能操作:

  • 0x01    讀取線圈的操作,
  • 0x02    讀取離散的操作,
  • 0x03    讀取寄存器的值,
  • 0x05    寫一個線圈操作,
  • 0x06    寫一個寄存器值,
  • 0x0F    批量寫線圈操作,
  • 0x10    批量寫寄存器值,

 如果你的裝置需要這些功能之外的資料,可以使用原生API方法,但是這個方法的前提就是你對MODBUS 協議非常清晰才可以,如果你不瞭解這個協議,可以參照下面的部落格說明:

 http://blog.csdn.net/thebestleo/article/details/52269999

 如果你需要搭建自己的ModBus伺服器,可以參照這邊文章:http://www.cnblogs.com/dathlin/p/7782315.html

 訪問測試專案

需要下載一個串口虛擬軟體

Virtual Serial Port Driver

:https://virtual-serial-port-driver.en.softonic.com/

然後虛擬化兩個串口出來,COM4 ,COM5 預設是串連在一起的。這樣我們就可以進行本地的測試了

 

 在你開發自己的用戶端程式之前,可以先用MODBUS測試載入器進行測試,以下地址的一個開源項目就是基於這個組件開發的Modbus rtu測試載入器,可直接用於讀寫測試。

 ModbusTcpServer.zip   先啟動服務,然後啟動串口

  

 

下面的一個項目是這個組件的訪問測試專案,您可以進行初步的訪問的測試,免去了您寫測試程式的麻煩,這個項目是和三菱,西門子PLC的訪問寫在一起的。可以同時參考。

為:HslCommunicationDemo.zip

 

 

Reference

 

ModBus組件所有的功能類都在 HslCommunication.ModBus命名空間,所以再使用之前先添加

using HslCommunication.ModBus;using HslCommunication;

  

How to Use

 

執行個體化:

在使用讀寫功能之前必須先進行執行個體化:

private ModbusRtu busRtuClient = new ModbusRtu( station );

 

注意:在Modbus伺服器的裝置裡,大部分的裝置都是從地址0開始的,有些特殊的裝置是從地址1開始的,所以本組件裡面,預設從地址0開始,如果想要從地址1開始,那麼就需要如下的配置:

busRtuClient.AddressStartWithZero = False;

 

 

然後接下來需要初始化參數,對串口來說,通常的參數有串口名稱,傳輸速率,資料位元,停止位,校正位,提供了一個委託設定的方式

            try            {                busRtuClient.SerialPortInni( sp =>                 {                     sp.PortName = "COM5";                     sp.BaudRate = 9600;                     sp.DataBits = 8;                     sp.StopBits = System.IO.Ports.StopBits.One;                     sp.Parity = System.IO.Ports.Parity.None;                 } );                busRtuClient.Open( ); // 開啟            }            catch (Exception ex)            {                MessageBox.Show( ex.Message );            }

 

 關閉的話,調用如下的方法

busRtuClient.Close( );

 

 

 

 

以下代碼示範常用的讀寫操作,為了方便起見,不再對IsSuccess判斷,一般都是成功的:

        private void userButton30_Click(object sender, EventArgs e)        {            // 讀取操作            bool coil100 = busRtuClient.ReadCoil("100").Content;   // 讀取線圈100的通斷            short short100 = busRtuClient.ReadInt16("100").Content; // 讀取寄存器100的short值            ushort ushort100 = busRtuClient.ReadUInt16("100").Content; // 讀取寄存器100的ushort值            int int100 = busRtuClient.ReadInt32("100").Content;      // 讀取寄存器100-101的int值            uint uint100 = busRtuClient.ReadUInt32("100").Content;   // 讀取寄存器100-101的uint值            float float100 = busRtuClient.ReadFloat("100").Content; // 讀取寄存器100-101的float值            long long100 = busRtuClient.ReadInt64("100").Content;    // 讀取寄存器100-103的long值            ulong ulong100 = busRtuClient.ReadUInt64("100").Content; // 讀取寄存器100-103的ulong值            double double100 = busRtuClient.ReadDouble("100").Content; // 讀取寄存器100-103的double值            string str100 = busRtuClient.ReadString("100", 5).Content;// 讀取100到104共10個字元的字串            // 寫入操作            busRtuClient.WriteCoil("100", true);// 寫入線圈100為通            busRtuClient.Write("100", (short)12345);// 寫入寄存器100為12345            busRtuClient.Write("100", (ushort)45678);// 寫入寄存器100為45678            busRtuClient.Write("100", 123456789);// 寫入寄存器100-101為123456789            busRtuClient.Write("100", (uint)123456778);// 寫入寄存器100-101為123456778            busRtuClient.Write("100", 123.456);// 寫入寄存器100-101為123.456            busRtuClient.Write("100", 12312312312414L);//寫入寄存器100-103為一個大資料            busRtuClient.Write("100", 12634534534543656UL);// 寫入寄存器100-103為一個大資料            busRtuClient.Write("100", 123.456d);// 寫入寄存器100-103為一個雙精確度的資料            busRtuClient.Write("100", "K123456789");                    }

 

下面再分別講解嚴格的操作,以及批量化的複雜的讀寫操作,假設你要讀取1000個M,迴圈讀取1千次可能要3秒鐘,如果用了下面的批量化讀取,只需要50ms,但是需要你對位元組的原理比較熟悉才能得心應手的處理

 

 

讀取線圈API:

 在此處舉例讀取地址為0,長度為10的線圈數量,讀取出來的資料已經自動轉化成了bool數組,方便的進行二次處理:

        private void userButton8_Click(object sender,EventArgs e)        {            HslCommunication.OperateResult<bool[]> read = busRtuClient.ReadCoil("0", 10);            if(read.IsSuccess)            {                bool coil_0 = read.Content[0];                bool coil_1 = read.Content[1];                bool coil_2 = read.Content[2];                bool coil_3 = read.Content[3];                bool coil_4 = read.Content[4];                bool coil_5 = read.Content[5];                bool coil_6 = read.Content[6];                bool coil_7 = read.Content[7];                bool coil_8 = read.Content[8];                bool coil_9 = read.Content[9];            }            else            {                MessageBox.Show(read.ToMessageShowString());            }        }

  當然也可以用組件提供的資料轉換API實現資料提取:

讀取離散資料:

讀取離散資料和讀取線圈的代碼幾乎是一致的,處理方式也是一致的,只是方法名稱改成了:

        private void userButton8_Click(object sender,EventArgs e)        {            HslCommunication.OperateResult<bool[]> read = busRtuClient.ReadDiscrete("0", 10);            if(read.IsSuccess)            {                bool coil_0 = read.Content[0];                bool coil_1 = read.Content[1];                bool coil_2 = read.Content[2];                bool coil_3 = read.Content[3];                bool coil_4 = read.Content[4];                bool coil_5 = read.Content[5];                bool coil_6 = read.Content[6];                bool coil_7 = read.Content[7];                bool coil_8 = read.Content[8];                bool coil_9 = read.Content[9];            }            else            {                MessageBox.Show(read.ToMessageShowString());            }        }

讀取寄存器資料:

 假設我們需要讀取地址為0,長度為10的資料,也即是10個資料,每個資料2個位元組,總計20個位元組的資料。下面解析資料前,先進行了假設,你在解析自己的資料前可以參照下面的解析

        private void userButton10_Click(object sender, EventArgs e)        {            HslCommunication.OperateResult<byte[]> read = busRtuClient.Read("0", 10);            if (read.IsSuccess)            {                // 共返回20個位元組,每個資料2個位元組,高位在前,低位在後                // 在資料解析前需要知道裡面到底存了什麼類型的資料,所以需要進行一些假設:                // 前兩個位元組是short資料類型                short value1 = busTcpClient.ByteTransform.TransInt16(read.Content, 0);                 // 接下來的2個位元組是ushort類型                ushort value2 = busTcpClient.ByteTransform.TransUInt16(read.Content, 2);                 // 接下來的4個位元組是int類型                int value3 = busTcpClient.ByteTransform.TransInt32(read.Content, 4);                 // 接下來的4個位元組是float類型                float value4 = busTcpClient.ByteTransform.TransFloat(read.Content, 8);                 // 接下來的全部位元組,共8個位元組是規格資訊                string speci = Encoding.ASCII.GetString(read.Content, 12, 8);                // 已經提取完所有的資料            }            else            {                MessageBox.Show(read.ToMessageShowString());            }        }

寫一個線圈:

寫一個線圈,這個相對比較簡單,假設我們需要寫入線圈0,為通

        private void userButton11_Click(object sender, EventArgs e)        {            HslCommunication.OperateResult write = busRtuClient.WriteCoil("0", true);            if (write.IsSuccess)            {                // 寫入成功                textBox1.Text = "寫入成功";            }            else            {                MessageBox.Show(write.ToMessageShowString());            }        }

寫一個寄存器:

寫一個寄存器的操作也是非常的方便,在這裡提供了三個重載的方法,允許使用三種方式寫入:分別寫入,short,ushort,byte三種:

        private void userButton12_Click(object sender, EventArgs e)        {            short value = -1234;            HslCommunication.OperateResult write = busRtuClient.WriteOneRegister("0", value);            if (write.IsSuccess)            {                // 寫入成功                textBox1.Text = "寫入成功";            }            else            {                MessageBox.Show(write.ToMessageShowString());            }        }

  

        private void userButton12_Click(object sender, EventArgs e)        {            ushort value = 56713;            HslCommunication.OperateResult write = busRtuClient.WriteOneRegister("0", value);            if (write.IsSuccess)            {                // 寫入成功                textBox1.Text = "寫入成功";            }            else            {                MessageBox.Show(write.ToMessageShowString());            }        }

  

        private void userButton12_Click(object sender, EventArgs e)        {            // 0x00為高位,0x10為低位            HslCommunication.OperateResult write = busRtuClient.WriteOneRegister("0", 0x00, 0x10);            if (write.IsSuccess)            {                // 寫入成功                textBox1.Text = "寫入成功";            }            else            {                MessageBox.Show(write.ToMessageShowString());            }        }

 

批量寫入線圈:

private void userButton13_Click(object sender, EventArgs e)        {            // 線圈0為True,線圈1為false,線圈2為true.....等等,以此類推,數組長度多少,就寫入多少線圈            bool[] value = new bool[] { true, false, true, true, false, false };            HslCommunication.OperateResult write = busRtuClient.WriteCoil("0", value);            if (write.IsSuccess)            {                // 寫入成功                textBox1.Text = "寫入成功";            }            else            {                MessageBox.Show(write.ToMessageShowString());            }        }

  

批量寫入寄存器:

第一種情況寫入一串short數組,這種情況比較簡單:

        private void userButton14_Click(object sender, EventArgs e)        {            short[] value = new short[] { -1234, 467, 12345 };            HslCommunication.OperateResult write = busRtuClient.Write("0", value);            if (write.IsSuccess)            {                // 寫入成功                textBox1.Text = "寫入成功";            }            else            {                MessageBox.Show(write.ToMessageShowString());            }        }

第二情況寫入一串ushort數組,也是比較簡單:

        private void userButton14_Click(object sender, EventArgs e)        {            ushort[] value = new ushort[] { 46789, 467, 12345 };            HslCommunication.OperateResult write = busRtuClient.Write("0", value);            if (write.IsSuccess)            {                // 寫入成功                textBox1.Text = "寫入成功";            }            else            {                MessageBox.Show(write.ToMessageShowString());            }        }

比較複雜的是寫入自訂的資料,按照上述讀取寄存器,比如我需要寫入寄存器0,寄存器1共同組成的一個int資料,那麼我們這麼寫:

        private void userButton15_Click(object sender, EventArgs e)        {            int value = 12345678;// 等待寫入的一個資料            HslCommunication.OperateResult write = busRtuClient.Write("0", value);            if (write.IsSuccess)            {                // 寫入成功                textBox1.Text = "寫入成功";            }            else            {                MessageBox.Show(write.ToMessageShowString());            }        }

其他資料參考這個就行,如果有不明白的,可以聯絡上面的QQ群。

 

究極資料操作,使用原生的報文來操作資料:

傳入一個位元組數組,資料內容和原生的資料一致,比如我要通過原生API讀取寄存器地址為0,長度為3的資料,那麼位元組的HEX標識形式為 01 03 00 00 00 03 不包括CRC校正碼

        private void button26_Click( object sender, EventArgs e )        {            try            {                OperateResult<byte[]> read = busRtuClient.ReadBase( HslCommunication.Serial.SoftCRC16.CRC16(HslCommunication.BasicFramework.SoftBasic.HexStringToBytes( "01 03 00 00 00 03" )) );                if (read.IsSuccess)                {                    textBox11.Text = "結果:" + HslCommunication.BasicFramework.SoftBasic.ByteToHexString( read.Content,‘ ‘ );                }                else                {                    MessageBox.Show( "讀取失敗:" + read.ToMessageShowString( ) );                }            }            catch (Exception ex)            {                MessageBox.Show( "讀取失敗:" + ex.Message );            }        }

 

 

  上述代碼在操作時用了一個轉化機制,輸入為十六進位的文本,轉化為byte[]資料,中間的分割符可以為空白格,可以為‘-‘,也可以為‘,‘,‘_‘等等等等,調用了組件基礎的資料轉化功能。

C# 開發Modbus Rtu用戶端 modbus測試Demo,Modbus 串口通訊 , 虛擬MODBUS-RTU測試

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.