小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

C#讀寫三菱PLC和西門子PLC數(shù)據(jù) 使用TCP/IP 協(xié)議

 有趣的永 2019-03-08

本文將使用一個Github開源的組件庫技術(shù)來讀寫三菱PLC和西門子plc數(shù)據(jù),使用的是基于以太網(wǎng)的TCP/IP實現(xiàn),不需要額外的組件,讀取操作只要放到后臺線程就不會卡死線程,本組件支持超級方便的高性能讀寫操作

 github地址:https://github.com/dathlin/HslCommunication 如果喜歡可以star或是fork,還可以打賞支持,打賞請認(rèn)準(zhǔn)源代碼項目。

 

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

1
Install-Package HslCommunication

 如果需要教程:Nuget安裝教程:http://www.cnblogs.com/dathlin/p/7705014.html

 

技術(shù)支持QQ群:群1:592132877(滿)  群2:948305931 (組件的版本更新細(xì)節(jié)也將第一時間在群里發(fā)布)最后編輯日期:2018年4月9日 11:35:43

里面各種小伙伴,為您解答數(shù)據(jù)交互,編程技巧,如果對本界面提供的API有任何疑問,都可以加群咨詢,如果有更好的建議,歡迎提出。

 

組件的完整信息和API介紹參照:http://www.cnblogs.com/dathlin/p/7703805.html   組件的使用限制,更新日志,都在該頁面里面。

 

如果你需要在讀取PLC數(shù)據(jù)之后,還要群發(fā)客戶端來實現(xiàn)遠(yuǎn)程辦公室同步監(jiān)視,可以參考如下的項目(基于該組件擴展起來的,帶有賬戶驗證,版本控制,數(shù)據(jù)群發(fā),公告管理等等功能)

https://github.com/dathlin/ClientServerProject

 

本文將展示如何配置網(wǎng)絡(luò)參數(shù)及怎樣使用代碼來訪問PLC數(shù)據(jù),希望給有需要的人解決一些實際問題。主要對三菱Q系列PLC的X,Y,M,L,B,V,F(xiàn),S,D,W,R區(qū)域的數(shù)據(jù)讀寫,對西門子PLC的M,Q,I,DB塊的數(shù)據(jù)讀寫,親測有效。

此處使用了網(wǎng)線直接的方式,如果PLC接進了局域網(wǎng),就可以進行遠(yuǎn)程讀寫了^_^

此處使用到了2個命名空間:

1
2
using HslCommunication;
using HslCommunication.Profinet;

 

隨便聊聊


當(dāng)我們一個上位機需要讀取100臺西門子PLC設(shè)備(此處只是舉個例子,凡是都是使用Modbus tcp的都是一樣的)的時候,你采用服務(wù)器主動去請求100臺設(shè)備的機制對性能來說是個極大的考驗,如果開100個線程去輪詢100臺設(shè)備,那么性能損失將是非常大的,更不用說再增加設(shè)備,如果搭建Modbus tcp服務(wù)器,就可以完美的解決性能問題,因為連接的壓力將會平均分?jǐn)偨o每一臺PLC,服務(wù)器端只要新增一個時間戳就可以知道客戶端有沒有連接上。

我們在100臺PLC里都增加發(fā)送Modbus tcp方法,將數(shù)據(jù)發(fā)送到服務(wù)器的ip和端口上去,服務(wù)器根據(jù)站號來區(qū)分設(shè)備。這樣就可以搭建一個高性能總站。 本組件支持快速搭建一個高性能的Modbus tcp總站。

http://www.cnblogs.com/dathlin/p/7782315.html

 

關(guān)于兩種模式


在PLC端,包括三菱,西門子,歐姆龍以及Modbus Tcp客戶端的訪問器上,都支持兩種模式,短連接模式和長連接模式,現(xiàn)在就來解釋下什么原理。

短連接:每次讀寫都是一個單獨的請求,請求完畢也就關(guān)閉了,如果服務(wù)器的端口僅僅支持單連接,那么關(guān)閉后這個端口可以被其他連接復(fù)用,但是在頻繁的網(wǎng)絡(luò)請求下,容易發(fā)生異常,會有其他的請求不成功,尤其是多線程的情況下。

長連接:創(chuàng)建一個公用的連接通道,所有的讀寫請求都利用這個通道來完成,這樣的話,讀寫性能更快速,即時多線程調(diào)用也不會影響,內(nèi)部有同步機制。如果服務(wù)器的端口僅僅支持單連接,那么這個端口就被占用了,比如三菱的端口機制,西門子的Modbus tcp端口機制也是這樣的。以下代碼默認(rèn)使用長連接,性能更高,還支持多線程同步。

在短連接的模式下,每次請求都是單獨的訪問,所以沒有重連的困擾,在長連接的模式下,如果本次請求失敗了,在下次請求的時候,會自動重新連接服務(wù)器,直到請求成功為止。另外,盡量所有的讀寫都對結(jié)果的成功進行判斷。

 

關(guān)于日志記錄


不管是三菱的數(shù)據(jù)訪問類,還是西門子的,還是Modbus tcp訪問類,都有一個LogNet屬性用來記錄日志,該屬性是一個接口類,ILogNet,凡事繼承該接口的都可以用來記錄日志,該日志會在訪問失敗時,尤其是因為網(wǎng)絡(luò)的原因?qū)е略L問失敗時會進行日志記錄(如果你為這個 LogNet 屬性配置了真實的日志記錄器的話):如果你想使用該記錄日志的功能,請參照如下的博客進行實例化:

http://www.cnblogs.com/dathlin/p/7691693.html

 

訪問測試項目


下面的一個項目是這個組件的訪問測試項目,您可以進行初步的訪問的測試,免去了您寫測試程序的麻煩,三菱的界面和西門子的界面幾乎是一致的。可以同時參考。該項目位于本篇文章開始處的Gitbub源代碼里面的

下載地址為:HslCommunicationDemo.zip 

 

演示項目


下面的三篇演示了具體如何去訪問PLC的數(shù)據(jù),我們在訪問完成后,通常需要進行處理,以下的示例項目就演示了后臺從PLC讀取數(shù)據(jù)后,前臺顯示并推送給所有在線客戶端的功能,客戶端并進行圖形化顯示,具有一定的參考意義,并且推送給網(wǎng)頁前端,項目地址為:

https://github.com/dathlin/RemoteMonitor

下面的圖片示例中的左邊程序就是服務(wù)器程序,它應(yīng)該和PLC直接連接并接入局域網(wǎng),然后把數(shù)據(jù)推送給客戶端顯示。注意:一個復(fù)雜高級的程序就應(yīng)該把處理邏輯程序和界面程序分開,比如這里的服務(wù)器程序?qū)崿F(xiàn)數(shù)據(jù)采集,推送,存儲。讓客戶端程序去實現(xiàn)數(shù)據(jù)的整理,分析,顯示,這樣即使客戶端程序因為BUG奔潰,服務(wù)器端仍然可以正常的工作。

測試圖片

 

 

 

三菱PLC篇(下面列舉了三種配置方法,本組件支持二進制和ASCII通訊,支持1E幀兼容協(xié)議訪問)

 


 

Q06UDV Plc的訪問測試感謝:hwdq0012

fx5u plc的訪問測試感謝:山楂

Q02CPU, L02CPU-CM : 本人測試

感謝:小懶豬雨中人  的測試,VB程序也可以調(diào)用本通訊庫

 

環(huán)境1:此處以GX Works3為示例,fx5u的配置如下:(感謝 山楂 提供的圖片)

 

環(huán)境2:此處以GX Works2為示例,測試PLC為L02CPU,內(nèi)置了以太網(wǎng)協(xié)議

 


環(huán)境3:此處以GX Works2為示例,添加以太網(wǎng)模塊,型號為QJ71E71-100,組態(tài)里添加完成后進行以太網(wǎng)的參數(shù)配置,此處需要注意的是:參數(shù)的配置對接下來的代碼中配置參數(shù)要一一對應(yīng)




注意在PLC的以太網(wǎng)模塊的配置中,無法設(shè)置網(wǎng)絡(luò)號為0,也無法設(shè)置站號為0, 所以此處均設(shè)置為1,在C#程序中也使用上述的配置,在代碼中均配置為0,如果您自定義設(shè)置為網(wǎng)絡(luò)2, 站號8,那么在代碼中就要寫對應(yīng)的數(shù)據(jù)。如果仍然通信失敗,重新測試0,0。

打開設(shè)置:在上圖中的打開設(shè)置選項,進行其他參數(shù)的配置,下圖只是舉了一個例子,開通了4個端口來支持讀寫操作:


端口號設(shè)置規(guī)則:

  • 為了不與原先存在的系統(tǒng)發(fā)生沖突,您在添加自己的端口時盡量使用您自己的端口。
  • 如果讀寫都需要,盡可能的將讀取端口和寫入端口區(qū)分開來,這樣做比較高性能。
  • 如果您的網(wǎng)絡(luò)狀態(tài)不是特別穩(wěn)定,讀取端口使用2個,一個受阻切換另一個讀取可以提升系統(tǒng)的穩(wěn)定性。


本文檔僅作組件的測試,所以只用了一個端口作為讀寫。如果你的程序也使用了一個端口,那么你在讀取數(shù)據(jù)時候, 剛好也在寫入(異步操作可能發(fā)生這樣的情況),那么寫入會失??!)(在長連接模式下沒有這個問題)

三菱PLC的數(shù)據(jù)主要由兩類數(shù)據(jù)組成,位數(shù)據(jù)和字?jǐn)?shù)據(jù),在位數(shù)據(jù)中,例如X,Y,M,L都是位數(shù)據(jù),字?jǐn)?shù)據(jù)例如D,W。 兩類的數(shù)據(jù)在讀取解碼上存在一點小差別。(事實上也可以先將16個M先賦值給一個D,讀取D數(shù)據(jù)再進行解析, 在讀取M的數(shù)量比較多的時候,這樣操作效率更高)

初始化訪問PLC對象

注意:如果你想采用ASCII來讀寫數(shù)據(jù),請使用MelsecMcAsciiNet類,如果想采用1E幀協(xié)議,使用MelsecA1ENet類,除了實例化,其他的數(shù)據(jù)交互都是一樣的。
如果想使用本組件的數(shù)據(jù)讀取功能,必須先初始化數(shù)據(jù)訪問對象,根據(jù)實際情況進行數(shù)據(jù)的填入。 下面僅僅是測試中的數(shù)據(jù):

1
private MelsecMcNet melsec_net = new MelsecMcNet( "192.168.0.1", 6000 );

 如上圖所示,只要指定了IP地址和端口號就完成了初始化的搭建了,當(dāng)然還支持一些額外的信息配置

1
2
3
melsec_net.ConnectTimeOut = 2000; // 網(wǎng)絡(luò)連接的超時時間
melsec_net.NetworkNumber = 0x00;  // 網(wǎng)絡(luò)號
melsec_net.NetworkStationNumber = 0x00; // 網(wǎng)絡(luò)站號

打開連接,并可以判斷是否連接上

1
melsec_net.ConnectClose( );

如果需要判斷,那么按照如下的操作

1
2
3
4
5
6
7
8
9
OperateResult connect = melsec_net.ConnectServer( );
if (connect.IsSuccess)
{
    MessageBox.Show( "連接成功!" );
}
else
{
    MessageBox.Show( "連接失敗!" );
}

 

 
說明:對象應(yīng)該放在窗體類下面,此處僅僅針對讀取一臺設(shè)備的plc,也可以在訪問的方法中實例化局部對象, 初始化數(shù)據(jù),然后讀取,該對象幾乎不損耗內(nèi)存,內(nèi)存垃圾由CLR進行自動回收。此處測試方便,窗體的多個按鈕均連接同一臺PLC 設(shè)備,所以本窗體實例化一個對象即可。

 

關(guān)于兩種地址的表示方式

第一種,使用系統(tǒng)的類來標(biāo)識,比如M200,寫成(MelsecDataType.M, 200)的表示形式,這樣也可以去MelsecDataType里面找到所有支持的數(shù)據(jù)類型。

第二種,使用字符串表示,這個組件里所有的讀寫操作提供字符串表示的重載方法,所有的支持訪問的類型對應(yīng)如下,字符串的表示方式存在十進制和十六進制的區(qū)別:

  • 輸入繼電器:"X100","X1A0"            // 字符串為十六進制機制
  • 輸出繼電器:"Y100" ,"Y1A0"           // 字符串為十六進制機制
  • 內(nèi)部繼電器:"M100","M200"           // 字符串為十進制
  • 鎖存繼電器:"L100"  ,"L200"           // 字符串為十進制
  • 報警器:       "F100", "F200"            // 字符串為十進制
  • 邊沿繼電器:"V100" , "V200"          // 字符串為十進制
  • 鏈接繼電器:"B100" , "B1A0"          // 字符串為十六進制
  • 步進繼電器:"S100" , "S200"          // 字符串為十進制
  • 數(shù)據(jù)寄存器:"D100", "D200"           // 字符串為十進制
  • 鏈接寄存器:"W100" ,"W1A0"         // 字符串為十六進制
  • 文件寄存器:"R100","R200"            // 字符串為十進制

 

展示一些簡單實用基礎(chǔ)數(shù)據(jù)讀寫,這些數(shù)據(jù)的讀寫沒有進行嚴(yán)格的是否成功判斷(判斷方法參照后面的代碼),一般網(wǎng)絡(luò)良好的情況下都會成功,但不排除失敗,以下代碼僅作測試,所有沒有嚴(yán)格判斷是否成功:

 

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
bool[] M100 = melsec_net.ReadBool("M100",1).Content;            // 讀取M100是否通,十進制地址
bool[] X1A0 = melsec_net.ReadBool("X1A0",1).Content;            // 讀取X1A0是否通,十六進制地址
bool[] Y1A0 = melsec_net.ReadBool("Y1A0",1).Content;            // 讀取Y1A0是否通,十六進制地址
bool[] B1A0 = melsec_net.ReadBool("B1A0",1).Content;            // 讀取B1A0是否通,十六進制地址
short short_D1000 = melsec_net.ReadInt16("D1000").Content;   // 讀取D1000的short值  ,W3C0,R3C0 效果是一樣的
ushort ushort_D1000 = melsec_net.ReadUInt16("D1000").Content; // 讀取D1000的ushort值
int int_D1000 = melsec_net.ReadInt32("D1000").Content;          // 讀取D1000-D1001組成的int數(shù)據(jù)
uint uint_D1000 = melsec_net.ReadUInt32("D1000").Content;       // 讀取D1000-D1001組成的uint數(shù)據(jù)
float float_D1000 = melsec_net.ReadFloat("D1000").Content;    // 讀取D1000-D1001組成的float數(shù)據(jù)
long long_D1000 = melsec_net.ReadInt64("D1000").Content;       // 讀取D1000-D1003組成的long數(shù)據(jù)
ulong ulong_D1000 = melsec_net.ReadUInt64( "D1000" ).Content;       // 讀取D1000-D1003組成的long數(shù)據(jù)
double double_D1000 = melsec_net.ReadDouble("D1000").Content; // 讀取D1000-D1003組成的double數(shù)據(jù)
string str_D1000 = melsec_net.ReadString("D1000", 10).Content; // 讀取D1000-D1009組成的條碼數(shù)據(jù)
melsec_net.Write("M100", new bool[] { true} );                        // 寫入M100為通
melsec_net.Write( "Y1A0", new bool[] { true } );                        // 寫入Y1A0為通
melsec_net.Write( "X1A0", new bool[] { true } );                        // 寫入X1A0為通
melsec_net.Write( "B1A0", new bool[] { true } );                        // 寫入B1A0為通
melsec_net.Write( "D1000", (short)1234);                // 寫入D1000  short值  ,W3C0,R3C0 效果是一樣的
melsec_net.Write( "D1000", (ushort)45678);              // 寫入D1000  ushort值
melsec_net.Write( "D1000", 1234566);                    // 寫入D1000  int值
melsec_net.Write( "D1000", (uint)1234566);               // 寫入D1000  uint值
melsec_net.Write( "D1000", 123.456f);                    // 寫入D1000  float值
melsec_net.Write( "D1000", 123.456d);                    // 寫入D1000  double值
melsec_net.Write( "D1000", 123456661235123534L);          // 寫入D1000  long值
melsec_net.Write( "D1000", "K123456789");                // 寫入D1000  string值

 

 

 

下面再分別講解嚴(yán)格的操作,以及批量化的復(fù)雜的讀寫操作,假設(shè)你要讀取1000個M,循環(huán)讀取1千次可能要3秒鐘,如果用了下面的批量化讀取,只需要50ms,但是需要你對字節(jié)的原理比較熟悉才能得心應(yīng)手的處理

X,Y,M,L,F,V,B,S位數(shù)據(jù)的讀寫說明

  • X 輸入繼電器
  • Y 輸出繼電器
  • M 內(nèi)部繼電器
  • L 鎖存繼電器
  • F 報警器
  • V 邊沿繼電器
  • B 鏈接繼電器
  • S 步進繼電器

 

本小節(jié)將展示八種位數(shù)據(jù)的讀取,雖然更多的時候只是讀取D數(shù)據(jù)即可,或者是將位數(shù)據(jù)批量挪到D數(shù)據(jù)中, 但是在此處仍然進行介紹單獨的讀取X,Y,M,L,F,V,B,S,由于這八種讀取手法一致,故針對M數(shù)據(jù)進行介紹,其他的您可以自己測試。

如下方法演示讀取了M200-M209這10個M的值,注意:讀取長度必須為偶數(shù),即時寫了奇數(shù),也會補齊至偶數(shù),讀取和寫入的最大長度為7168,否則報錯。如需實際需求確實大于7168的,請分批次讀取。
返回值解析:如果讀取正常則共返回10個字節(jié)的數(shù)據(jù),以下示例數(shù)據(jù)進行批量化的讀取

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
private void userButton20_Click(object sender, EventArgs e)
{
    // M200-M209讀取顯示
    OperateResult<bool[]> read = melsec_net.ReadBool("M200", 10);
    if (read.IsSuccess)
    {
        // 成功讀取,True代表通,F(xiàn)alse代表不通
        bool M200 = read.Content[0];
        bool M201 = read.Content[1];
        bool M202 = read.Content[2];
        bool M203 = read.Content[3];
        bool M204 = read.Content[4];
        bool M205 = read.Content[5];
        bool M206 = read.Content[6];
        bool M207 = read.Content[7];
        bool M208 = read.Content[8];
        bool M209 = read.Content[9];
        // 顯示
    }
    else
    {
        //失敗讀取,顯示失敗信息
        MessageBox.Show(read.ToMessageShowString());
    }
}
private void userButton21_Click(object sender, EventArgs e)
{
    // X100-X10F讀取顯示
    OperateResult<bool[]> read = melsec_net.ReadBool("X200", 16);
    if (read.IsSuccess)
    {
        // 成功讀取,True代表通,F(xiàn)alse代表不通
        bool X200 = read.Content[0];
        bool X201 = read.Content[1];
        bool X202 = read.Content[2];
        bool X203 = read.Content[3];
        bool X204 = read.Content[4];
        bool X205 = read.Content[5];
        bool X206 = read.Content[6];
        bool X207 = read.Content[7];
        bool X208 = read.Content[8];
        bool X209 = read.Content[9];
        bool X20A = read.Content[10];
        bool X20B = read.Content[11];
        bool X20C = read.Content[12];
        bool X20D = read.Content[13];
        bool X20E = read.Content[14];
        bool X20F = read.Content[15];
        // 顯示
    }
    else
    {
        //失敗讀取,顯示失敗信息
        MessageBox.Show(read.ToMessageShowString());
    }
}
private void userButton3_Click(object sender, EventArgs e)
{
    // M100-M104 寫入測試 此處寫入后M100:通 M101:斷 M102:斷 M103:通 M104:通
    bool[] values = new bool[] { true, false, false, true, true };// 等同于 byte[] values = new byte[]{0x01,0x00,0x00,0x01,0x01}
    OperateResult write = melsec_net.Write("M100", values);
    if (write.IsSuccess)
    {
        TextBoxAppendStringLine("寫入成功");
    }
    else
    {
        MessageBox.Show(write.ToMessageShowString());
    }
}

 


錯誤說明:有可能因為站號網(wǎng)絡(luò)號沒有配置正確返回有錯誤代號沒有錯誤信息, 也有可能因為網(wǎng)絡(luò)問題導(dǎo)致沒有連接上,此時會有連接不上的錯誤信息。


下面展示的是后臺線程循環(huán)讀取的情況,事實上在實際的使用過程中經(jīng)常會碰見的情況。下面的方法需要 放到單獨的線程中,同理,訪問D數(shù)據(jù)時也是按照下面循環(huán)就行,此處不再贅述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//后臺循環(huán)讀取PLC數(shù)據(jù) M200開始10個字 也即是M200-M209
while (true)
{
    OperateResult<bool[]> read = melsec_net.ReadFromPLC("M200", 10);
    if (read.IsSuccess)
    {
        //成功讀取,委托顯示
        textBox2.BeginInvoke(new Action(delegate
        {
            textBox2.Text = "M201:" + (read.Content[1] ? "通" : "斷");
        }));
    }
    else
    {
        //失敗讀取,應(yīng)該對失敗信息進行日志記錄,不應(yīng)該顯示,測試訪問時才適合顯示錯誤信息
        LogHelper.save(read.ToMessageShowString());
    }
    System.Threading.Thread.Sleep(1000);//決定了訪問的頻率
}

  

D,W,R字?jǐn)?shù)據(jù)的讀寫操作

此處讀取針對中間存在整數(shù)數(shù)據(jù)的情況,因為兩者讀取方式相同,故而只演示一種數(shù)據(jù)讀取, 使用該組件讀取數(shù)據(jù),一次最多讀取或?qū)懭?60個字,超出則失敗。 如果讀取的長度確實超過限制,請考慮分批讀取。

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
36
37
38
39
40
41
42
private void userButton2_Click(object sender, EventArgs e)
{
    // D100-D104讀取
    OperateResult<byte[]> read = melsec_net.Read("D100", 5);
    if (read.IsSuccess)
    {
        // 成功讀取,提取各自的值,此處的值有個前提假設(shè),假設(shè)PLC上的數(shù)據(jù)是有符號的數(shù)據(jù),表示-32768-32767
        short D100 = melsec_net.ByteTransform.TransInt16(read.Content, 0);
        short D101 = melsec_net.ByteTransform.TransInt16( read.Content, 2);
        short D102 = melsec_net.ByteTransform.TransInt16( read.Content, 4);
        short D103 = melsec_net.ByteTransform.TransInt16( read.Content, 6);
        short D104 = melsec_net.ByteTransform.TransInt16( read.Content, 8);
        TextBoxAppendStringLine("D100:" + D100);
        TextBoxAppendStringLine("D101:" + D101);
        TextBoxAppendStringLine("D102:" + D102);
        TextBoxAppendStringLine("D103:" + D103);
        TextBoxAppendStringLine("D104:" + D104);
    }
    else
    {
        //失敗讀取
        MessageBox.Show(read.ToMessageShowString());
    }
}
private void userButton4_Click( object sender, EventArgs e )
{
    short[] values = new short[5] { 1335, 8765, 1234, 4567, -2563 };
    // D100為1234,D101為8765,D102為1234,D103為4567,D104為-2563
    OperateResult write = melsec_net.Write( "D6000", values );
    if (write.IsSuccess)
    {
        //成功寫入
        TextBoxAppendStringLine( "寫入成功" );
    }
    else
    {
        MessageBox.Show( write.ToMessageShowString( ) );
    }
}

 

  



ASCII字符串?dāng)?shù)據(jù)的讀寫

在實際項目中,有可能會碰到PLC存儲了規(guī)格數(shù)據(jù),或是條碼數(shù)據(jù),這些數(shù)據(jù)是以ASCII編碼形式存在, 我們需要把數(shù)據(jù)進行讀取出來用于顯示,保存等操作。下面演示讀取指定長度的條碼數(shù)據(jù),數(shù)據(jù)的數(shù)據(jù)存放在D2000-D2004中, 長度應(yīng)該為存儲條碼的最大長度,也即是占用了5個D,一個D可以存儲2個ASCII碼字符:

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
private void button7_Click(object sender, EventArgs e)
{
    //讀取字符串?dāng)?shù)據(jù),共計10個字節(jié)長度
    OperateResult<byte[]> read = melsec_net.Read("D2000", 5);
    if (read.IsSuccess)
    {
        //成功讀取
        textBox2.Text = Encoding.ASCII.GetString(read.Content);
    }
    else
    {
        //失敗讀取
        MessageBox.Show(read.ToMessageShowString());
    }
}
private void button8_Click(object sender, EventArgs e)
{
    //寫字符串,如果寫入K12345678這9個字符,讀取出來時末尾會補0
    OperateResult write = melsec_net.WriteAsciiString("D2000", "K123456789");
    if (write.IsSuccess)
    {
        textBox2.Text = "寫入成功";
    }
    else
    {
        MessageBox.Show(write.ToMessageShowString());
    }
}

  



需要注意的是,如果第一次在D2000-D2004中寫入了"K123456789",第二次寫入了"K6666",那么讀取D2000-D2004的條碼數(shù)據(jù)會讀取到 K666656789,如果要避免這種情況,則需要在寫入條碼的時候,指定總長度,該長度必須為偶數(shù), 不然也會自動補0,小于該長度時,自動補零,大于該長度時,自動截斷數(shù)據(jù),具體的使用方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
private void button8_Click(object sender, EventArgs e)
{
    //寫字符串,本次寫入指定了10個長度的字符,其余的D的數(shù)據(jù)將被清空,是一種安全的寫入方式
    OperateResult write = melsec_net.WriteAsciiString("D2000", "K6666", 10);
    if (write.IsSuccess)
    {
        textBox2.Text = "寫入成功";
    }
    else
    {
        MessageBox.Show(write.ToMessageShowString());
    }
}

  



中文及特殊字符的讀寫

在需要讀寫復(fù)雜的字符數(shù)據(jù)時,上述的ASCII編碼已經(jīng)不能滿足要求,雖然使用讀寫的基礎(chǔ)方法可以實現(xiàn)任意數(shù)據(jù)的讀寫, 但是此處為了方便,還是提供了一個方便的方法來讀寫中文數(shù)據(jù),采用Unicode編碼的字符, 該編碼下的一個字符占用一個D或W來存儲。如下將演示,讀寫方法,基本用途和上述 ASCII編碼的讀寫一致。

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
private void button9_Click(object sender, EventArgs e)
{
    //讀中文,存儲在D3000-D3009
    OperateResult<byte[]> read = melsec_net.Read("D3000", 10);
    if (read.IsSuccess)
    {
        //解析數(shù)據(jù)
        textBox2.Text = Encoding.Unicode.GetString(read.Content);
    }
    else
    {
        MessageBox.Show(read.ToMessageShowString());
    }
}
private void button10_Click(object sender, EventArgs e)
{
    //寫中文 D3000-D3009,該10含義為中文字符數(shù)
    OperateResult write = melsec_net.WriteUnicodeString("D3000", "測試數(shù)據(jù)test", 10);
    if (write.IsSuccess)
    {
        textBox2.Text = "寫入成功";
    }
    else
    {
        MessageBox.Show(write.ToMessageShowString());
    }
}

 

一個實際中復(fù)雜的例子演示

實際中可能碰到的情況會很復(fù)雜,一臺設(shè)備中需要上傳的數(shù)據(jù)包含了溫度,壓力,產(chǎn)量,規(guī)格等等信息,在一串?dāng)?shù)據(jù)中 會包含各種各樣的不同的數(shù)據(jù),上述的讀取D,讀取M,讀取條碼的方式不太好用,所以此處做一個完整示例的演示,假設(shè)我們需要讀取 D4000-D4009的數(shù)據(jù),假設(shè)D4000存放了溫度數(shù)據(jù),55.1℃在D中為551,D4001存放了壓力數(shù)據(jù),1.23MPa在D中存放為123,D4002存放了 設(shè)備狀態(tài),0為停止,1為運行,D4003存放了產(chǎn)量,1000就是指1000個,D4004備用,D4005-D4009存放了規(guī)格,以下代碼演示如何去解析數(shù)據(jù):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void button29_Click(object sender, EventArgs e)
{
    //解析復(fù)雜數(shù)據(jù)
    OperateResult<byte[]> read = melsec_net.Read("D4000", 10);
    if (read.IsSuccess)
    {
        double 溫度 = melsec_net.ByteTransform.TransInt16(read.Content, 0) / 10d;//索引很重要
        double 壓力 = melsec_net.ByteTransform.TransInt16(read.Content, 2) / 100d;
        bool IsRun = melsec_net.ByteTransform.TransInt16(read.Content, 4) == 1;
        int 產(chǎn)量 = BitConverter.ToInt16(read.Content, 6);
        string 規(guī)格 = Encoding.ASCII.GetString(read.Content, 10, 10);
    }
    else
    {
        MessageBox.Show(read.ToMessageShowString());
    }
}

 

究極數(shù)據(jù)讀取展示,用于測試你自己的報文以及擴展自己的更高級,更變態(tài)的API,以下演示,使用這個高級模式,寫入M100,True的操作:

我們要寫入的字節(jié)數(shù)組HEX表示形式為:50 00 00 FF FF 03 00 0D 00 0A 00 01 14 01 00 64 00 00 90 01 00 10

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void userButton23_Click(object sender, EventArgs e)
{
    byte[] buffer = HslCommunication.BasicFramework.SoftBasic.HexStringToBytes("50 00 00 FF FF 03 00 0D 00 0A 00 01 14 01 00 64 00 00 90 01 00 10");
    // 直接使用報文進行
    OperateResult<byte[]> operate = melsec_net.ReadFromCoreServer(buffer);
    if(operate.IsSuccess)
    {
        // 返回PLC的報文反饋,需要自己對報文進行結(jié)果分析
        MessageBox.Show(HslCommunication.BasicFramework.SoftBasic.ByteToHexString(operate.Content));
    }
    else
    {
        // 網(wǎng)絡(luò)原因?qū)е碌氖?/code>
        MessageBox.Show(operate.ToMessageShowString());
    }
}

 

更詳細(xì)的信息,可以參照源代碼里面的測試項目。

 

 

創(chuàng)作不易,感謝打賞


 

 

 

 

西門子篇參見另一篇博客:http://www.cnblogs.com/dathlin/p/8685855.html

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多