电竞比分网-中国电竞赛事及体育赛事平台

分享

工業(yè)通信的開(kāi)源項(xiàng)目 HslCommunication 介紹

 goodwangLib 2019-04-03

前言:


本項(xiàng)目的孵化說(shuō)來(lái)也是機(jī)緣巧合的事,本人于13年杭州某大學(xué)畢業(yè)后去了一家大型的國(guó)企工作,慢慢的走上了工業(yè)軟件,上位機(jī)軟件開(kāi)發(fā)的道路。于14年正式開(kāi)發(fā)基于windows的軟件,當(dāng)時(shí)可選的技術(shù)棧就是MFC和C#的winform,后來(lái)就發(fā)現(xiàn)C#的更為簡(jiǎn)單一些,那就直接干,先做再說(shuō)。需要做一些界面相關(guān)的軟件,就直接采用了C#的winform,基礎(chǔ)不夠,百度來(lái)湊。后來(lái)領(lǐng)導(dǎo)就下達(dá)了一個(gè)任務(wù),開(kāi)發(fā)一個(gè)硫化機(jī)系統(tǒng)的上位機(jī),對(duì)某個(gè)車(chē)間共計(jì)五六十臺(tái)硫化機(jī)進(jìn)行監(jiān)控和曲線查看。由于沒(méi)有可參考的界面程序,開(kāi)發(fā)起來(lái)就比較費(fèi)勁,具體有什么功能,都是干嘛的,工藝需要什么等等都是未知數(shù),沒(méi)辦法,只有硬著頭皮和現(xiàn)場(chǎng)的工藝人員,電氣人員,來(lái)回溝通交流,加上一些我自己的理解,正式踏上了工業(yè)軟件開(kāi)發(fā)的道路。

 

開(kāi)始做項(xiàng)目的時(shí)候,硫化機(jī)設(shè)備是采用PLC作為主控制器的,第一道攔路虎就是如何將三菱的PLC(邏輯控制器,通常作為設(shè)備的核心控制單元)的數(shù)據(jù)給拿到我的軟件中來(lái)呢?這真是一個(gè)棘手的問(wèn)題啊,首先就是百度,搜索到了MX component組件,初步試了試,真的比較麻煩,關(guān)鍵還沒(méi)弄通。然后就去看看有沒(méi)有其他的方式實(shí)現(xiàn),后來(lái)就在工廠的備件庫(kù)里看到了三菱的以太網(wǎng)模塊QJ71E71-100,然后就搜索支持的通訊說(shuō)明,在三菱的官網(wǎng)上找到了通信說(shuō)明,打開(kāi)一看,我去,這么長(zhǎng)篇大論。那也沒(méi)有辦法,按照邊測(cè)試邊開(kāi)發(fā),勉勉強(qiáng)強(qiáng)讀到了我想要讀的數(shù)據(jù)(當(dāng)然,這時(shí)候的代碼基本都是寫(xiě)死的),又開(kāi)始解析數(shù)據(jù)成真實(shí)的數(shù)據(jù),然后研究如何存入數(shù)據(jù)庫(kù)中去,再研究怎么顯示曲線,到這里為止,這個(gè)項(xiàng)目的基本技術(shù)難題基本算是攻克了,持續(xù)的迭代,那是后話了。

 

在接下來(lái)的兩三年里,接觸并開(kāi)發(fā)了好幾個(gè)類(lèi)似的項(xiàng)目,發(fā)現(xiàn)通常工業(yè)軟件的需求是采集,分析,存數(shù)據(jù)庫(kù),顯示。后來(lái)對(duì)通信的理解深入,由單機(jī)軟件發(fā)展成了CS架構(gòu)的軟件,微軟的數(shù)據(jù)庫(kù)SQL Server本來(lái)就支持局域網(wǎng)訪問(wèn)。后來(lái)在17年趁著換工作和考駕照的間隙,梳理了上份工作積累的經(jīng)驗(yàn),和實(shí)際的需求,再加上自己的代碼水平也稍微進(jìn)步了一點(diǎn)點(diǎn),就整理成了HslCommunication,并將之開(kāi)源出來(lái),初步的功能是三菱PLC的數(shù)據(jù)讀寫(xiě),C#軟件之間的數(shù)據(jù)通信。后來(lái)又集成了modbus協(xié)議,西門(mén)子,歐姆龍,ab plc,三菱串口等等,發(fā)現(xiàn)寫(xiě)庫(kù)的要求和寫(xiě)簡(jiǎn)單程序的要求并不是等同的,要寫(xiě)成庫(kù)的話,需要保證功能靈活性,你寫(xiě)的代碼基本符合大多數(shù)人的使用需求,而不是某種特定的情況。也就是說(shuō),有些人可能簡(jiǎn)單的使用而已,而有些人會(huì)深入使用,壓榨性能。然后就是代碼了,所有寫(xiě)代碼的標(biāo)準(zhǔn)的最終目的都是為了讓代碼可讀性增強(qiáng),可維護(hù)性增強(qiáng),方便快速的理解,升級(jí),查錯(cuò)。這方便確實(shí)卻要經(jīng)驗(yàn)積累。

 

做這個(gè)項(xiàng)目(HslCommunication)的目標(biāo)和開(kāi)源的初衷是方便廣大的像我這種的在工廠一線的軟件工程師,我一直覺(jué)得我們不應(yīng)該把自己看做是程序員,程序員的角色更像是碼農(nóng),主要工作就是敲代碼,而軟件工程師應(yīng)該是更大的定義,設(shè)計(jì)軟件的整體架構(gòu)和開(kāi)發(fā)的。這幾年大多數(shù)工作都開(kāi)始意識(shí)到工業(yè)軟件,上位機(jī)軟件,數(shù)據(jù)追述系統(tǒng),SCADA軟件,MES軟件開(kāi)發(fā)的重要性,所以像我這樣的有通信需求的人應(yīng)該不在少數(shù),況且開(kāi)源有助于別人來(lái)一起改進(jìn),和代碼測(cè)試。所以在開(kāi)源之后,在博客園就陸陸續(xù)續(xù)的寫(xiě)了一些文章,比如如何使用C#和三菱PLC通訊,C#和西門(mén)子通訊等等。從博客園的點(diǎn)擊量來(lái)看,確實(shí)有大量的工廠的程序員有這方便的需求,而直接采用socket來(lái)開(kāi)發(fā),比較晦澀難懂,坑又比較多,事實(shí)上確實(shí)有很多人來(lái)報(bào)告了bug。幫助我修復(fù)了這個(gè)組件,提高了穩(wěn)定性。再次感謝所有使用或是報(bào)告bug的萬(wàn)千網(wǎng)友,沒(méi)有你們的支持就沒(méi)有本項(xiàng)目的今天。

 

由于我也是這個(gè)項(xiàng)目的使用者之一,實(shí)際上我自己在工作或是其他方面的使用也是很頻繁的,在開(kāi)發(fā)項(xiàng)目上就會(huì)站在使用者的角度出發(fā),比如我想讀取三菱PLC的D100的數(shù)據(jù),能不能有個(gè)組件一兩行代碼就可以實(shí)現(xiàn)?偽代碼的邏輯就是

1. 實(shí)例化

2. 讀

這樣才算是簡(jiǎn)單的操作,本著這樣設(shè)計(jì)思想,最終有了現(xiàn)在的開(kāi)源項(xiàng)目。

 

HslCommunication 能干什么?


相比大多數(shù)人比較關(guān)心這個(gè)問(wèn)題,綜合前言的介紹,這個(gè)組件主要是用于工業(yè)通信的,也有兩個(gè)程序之間的通訊,還有其他雜七雜八的功能,更像是我的工具插件。各種小功能,擴(kuò)展的小功能等等。直接上圖:

demo

這是這個(gè)開(kāi)源項(xiàng)目的demo程序,基本上將80%的功能列舉出來(lái)了,當(dāng)然還有一些小功能沒(méi)有列舉。大多數(shù)支持的設(shè)備都在上面進(jìn)行顯示了,可以方便的進(jìn)行測(cè)試,看看是不是可以實(shí)現(xiàn)讀寫(xiě)的操作(對(duì)現(xiàn)場(chǎng)實(shí)際在生產(chǎn)的設(shè)備應(yīng)當(dāng)注意寫(xiě)入不正確的數(shù)據(jù)會(huì)導(dǎo)致意外事故發(fā)生)。比如我們來(lái)看看三菱的PLC的demo程序:

melsec

其他的截圖畫(huà)面就不一一舉例了,都是類(lèi)似或是基本類(lèi)似的??梢苑奖愕氖褂胐emo進(jìn)行測(cè)試。

特別注意,本組件實(shí)現(xiàn)的所有的通訊都是基于socket直接實(shí)現(xiàn)的,通信部分不依賴任何第三方通訊庫(kù)或是組件安裝,也就是說(shuō),你拿個(gè)dll可以直接和PLC通訊,這對(duì)于部署,開(kāi)發(fā)調(diào)試,升級(jí)都是非常方便的。

當(dāng)你需要進(jìn)行PLC通信時(shí),可以先用demo程序進(jìn)行測(cè)試,如果demo程序可以讀寫(xiě),那么用本組件也就絕對(duì)可以讀寫(xiě),有些PLC的參數(shù)如果不清楚,就需要聯(lián)系電氣工程師進(jìn)行確認(rèn)。比如AB PLC的slot,不知道該寫(xiě)什么,就嘗試為0,如果不行,就只能聯(lián)系電氣工程師解決這個(gè)問(wèn)題。

 

demo項(xiàng)目的意義:當(dāng)我開(kāi)發(fā)了三菱PLC的通訊程序和西門(mén)子的通訊程序之后,我發(fā)現(xiàn)如果我想要測(cè)試一個(gè)新的PLC通不通?或是簡(jiǎn)單的通過(guò)代碼讀PLC的某個(gè)地址的程序的時(shí)候,就好費(fèi)勁,需要經(jīng)常創(chuàng)建一些小項(xiàng)目,這些小項(xiàng)目本身并沒(méi)有什么實(shí)際的意義,就是簡(jiǎn)單的讀個(gè)數(shù)據(jù)之類(lèi)的。后來(lái)就想把這部分內(nèi)容做成一個(gè)通用的測(cè)試,于是就有了demo項(xiàng)目,將本項(xiàng)目支持的各種設(shè)備都往界面上羅列,做成一個(gè)測(cè)試環(huán)境的demo程序,這樣當(dāng)大家也有這樣的需求的時(shí)候,并不需要再新建一些無(wú)用的小項(xiàng)目了,本demo就基本上滿足大家所有的需求了。

demo項(xiàng)目的彩蛋:在18年11月之后,demo項(xiàng)目實(shí)現(xiàn)了版本控制和自動(dòng)升級(jí),12月之后實(shí)現(xiàn)了統(tǒng)計(jì)全球的使用情況,下圖就是demo項(xiàng)目 v5.6.2-最新 的2018年12月到2019年2月中旬的全球使用情況(這是不完全統(tǒng)計(jì),舊版未統(tǒng)計(jì),大量的舊版不支持自動(dòng)更新,有些demo屏蔽了檢測(cè),實(shí)際使用量應(yīng)該遠(yuǎn)超圖片所示)

 

 

整體框架說(shuō)明


整個(gè)框架的項(xiàng)目結(jié)構(gòu)如下:

首先文件夾 TestProject 里面的項(xiàng)目都是一些demo項(xiàng)目,當(dāng)然最重要的就是 HslCommunicationDemo 項(xiàng)目了。就是最上面的demo項(xiàng)目的截圖,Hsl具體能干什么可以參照這個(gè)。

本項(xiàng)目使用了三個(gè)框架的項(xiàng)目,也就是說(shuō),本項(xiàng)目提供dll文件包含了三個(gè)框架版本:

  • .net framework 3.5
  • .net framework 4.5
  • .net standard 2.0

維護(hù)三份源代碼顯然是什么痛苦的,所以我采用了維護(hù)一份源代碼,也就是 .Net 4.5的代碼,其他兩個(gè)項(xiàng)目引用.net 4.5的代碼,如果有不一致的地方,就用預(yù)編譯指令進(jìn)行區(qū)分。例如在modbusserver類(lèi)中

 而 HslCommunication_Net45.Test 項(xiàng)目是一個(gè)單元測(cè)試項(xiàng)目,包含了一些代碼類(lèi)的測(cè)試,還有示例代碼的編寫(xiě)。所以我們的重點(diǎn)來(lái)看看 .net 4.5的項(xiàng)目即可,整體的結(jié)構(gòu)如下圖:

 

BasicFramework 放些了一些基于的小工具的類(lèi),比如SoftBasic提供了大量小的靜態(tài)輔助方法,幫助你快速開(kāi)發(fā)實(shí)現(xiàn)一些基礎(chǔ)的小功能的。

Core 里放置了一些本項(xiàng)目的核心代碼,所有網(wǎng)絡(luò)通信類(lèi)的基礎(chǔ)類(lèi),基礎(chǔ)功能實(shí)現(xiàn)都在Core里。

Enthernet 里放置了一些高級(jí)程序語(yǔ)言之間的通信,比如兩個(gè)exe間通信,或是局域網(wǎng)兩臺(tái)電腦通信,或是多個(gè)電腦程序通信。

LogNet 是實(shí)現(xiàn)了本項(xiàng)目的日志工具,可以方便的存儲(chǔ)日志信息。

ModBus 實(shí)現(xiàn)了基于網(wǎng)絡(luò)的modbus-tcp協(xié)議,modbus-rtu協(xié)議,modbus-server,modbus-ascii協(xié)議的通信。

Profinet 實(shí)現(xiàn)了三菱,西門(mén)子,歐姆龍,松下,ab  plc的數(shù)據(jù)通信。

 

 

OperateResult 類(lèi)說(shuō)明


 

這個(gè)類(lèi)為什么拿出來(lái)出來(lái)說(shuō)呢?因?yàn)檫@個(gè)類(lèi)貫穿了HSL整個(gè)項(xiàng)目,是本開(kāi)源項(xiàng)目的思想之一。對(duì)這個(gè)類(lèi)的理解,和對(duì)于本項(xiàng)目的理解至關(guān)重要。

 

左邊也即是這個(gè)類(lèi)的位置,右邊是這個(gè)類(lèi)的定義,在項(xiàng)目最初的開(kāi)發(fā)階段,我遇到了一個(gè)問(wèn)題,這也是軟件開(kāi)發(fā)過(guò)程中大家都會(huì)遇到的問(wèn)題,比如我要實(shí)現(xiàn)一個(gè)讀取PLC一個(gè)數(shù)據(jù)的操作,讀取成功了自然皆大歡喜,如果讀取失敗了呢?

我如何將讀取失敗,或是寫(xiě)入失敗,或是操作失敗的信息傳遞給調(diào)用者呢?除了失敗的信息之外,應(yīng)該還要包含一個(gè)為什么失敗的信息,PLC本身的失敗會(huì)返回一個(gè)錯(cuò)誤碼,那就也需要一個(gè)錯(cuò)誤碼。所以就有了 OperateResult 的雛形:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/// <summary>
/// 指示本次訪問(wèn)是否成功
/// </summary>
public bool IsSuccess { get; set; }
/// <summary>
/// 具體的錯(cuò)誤描述
/// </summary>
public string Message { get; set; } = StringResources.Language.UnknownError;
/// <summary>
/// 具體的錯(cuò)誤代碼
/// </summary>
public int ErrorCode { get; set; } = 10000;

 

于是就有了上面的三個(gè)屬性內(nèi)容,但是這時(shí)候還有一點(diǎn)需要注意,返回的結(jié)果對(duì)象應(yīng)該是可以帶內(nèi)容的,比如你讀取了一個(gè)int數(shù)據(jù),應(yīng)該帶一個(gè)int的結(jié)果,讀取了一個(gè)short的數(shù)據(jù),就應(yīng)該帶一個(gè)short類(lèi)型的數(shù)據(jù),如果需要這個(gè)結(jié)果對(duì)象支持多類(lèi)型的內(nèi)容的話,查了查書(shū),發(fā)現(xiàn)有個(gè)泛型的功能剛好合適,但是之后又發(fā)現(xiàn),萬(wàn)一我想要帶2個(gè)不同類(lèi)型的結(jié)果對(duì)象時(shí),那怎么辦?這時(shí)候就需要定義多個(gè)不同類(lèi)型的 OperateResult 類(lèi)型了。

 

此處定義多達(dá)十個(gè)的泛型對(duì)象,滿足絕大多數(shù)的情況請(qǐng)用。這個(gè)類(lèi)型對(duì)象除了能返回帶有錯(cuò)誤信息的結(jié)果對(duì)象之外,還允許進(jìn)行結(jié)果路由,我們來(lái)看看這個(gè)項(xiàng)目里的一個(gè)方法:

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
/// <summary>
/// 使用底層的數(shù)據(jù)報(bào)文來(lái)通訊,傳入需要發(fā)送的消息,返回最終的數(shù)據(jù)結(jié)果,被拆分成了頭子節(jié)和內(nèi)容字節(jié)信息
/// </summary>
/// <param name="socket">網(wǎng)絡(luò)套接字</param>
/// <param name="send">發(fā)送的數(shù)據(jù)</param>
/// <returns>結(jié)果對(duì)象</returns>
/// <remarks>
/// 當(dāng)子類(lèi)重寫(xiě)InitializationOnConnect方法和ExtraOnDisconnect方法時(shí),需要和設(shè)備進(jìn)行數(shù)據(jù)交互后,必須用本方法來(lái)數(shù)據(jù)交互,因?yàn)楸痉椒ㄊ菬o(wú)鎖的。
/// </remarks>
protected OperateResult<byte[], byte[]> ReadFromCoreServerBase(Socket socket, byte[] send )
{
    LogNet?.WriteDebug( ToString( ), StringResources.Language.Send + " : " + BasicFramework.SoftBasic.ByteToHexString( send, ' ' ) );
    TNetMessage netMsg = new TNetMessage
    {
        SendBytes = send
    };
    // 發(fā)送數(shù)據(jù)信息
    OperateResult sendResult = Send( socket, send );
    if (!sendResult.IsSuccess)
    {
        socket?.Close( );
        return OperateResult.CreateFailedResult<byte[], byte[]>( sendResult );
    }
    // 接收超時(shí)時(shí)間大于0時(shí)才允許接收遠(yuǎn)程的數(shù)據(jù)
    if (receiveTimeOut >= 0)
    {
        // 接收數(shù)據(jù)信息
        OperateResult<TNetMessage> resultReceive = ReceiveMessage(socket, receiveTimeOut, netMsg);
        if (!resultReceive.IsSuccess)
        {
            socket?.Close( );
            return new OperateResult<byte[], byte[]>( StringResources.Language.ReceiveDataTimeout + receiveTimeOut );
        }
        LogNet?.WriteDebug( ToString( ), StringResources.Language.Receive + " : " +
            BasicFramework.SoftBasic.ByteToHexString( BasicFramework.SoftBasic.SpliceTwoByteArray( resultReceive.Content.HeadBytes,
            resultReceive.Content.ContentBytes ), ' ' ) );
        // Success
        return OperateResult.CreateSuccessResult( resultReceive.Content.HeadBytes, resultReceive.Content.ContentBytes );
    }
    else
    {
        // Not need receive
        return OperateResult.CreateSuccessResult( new byte[0], new byte[0] );
    }
}

 

我們看到,方法里面的錯(cuò)誤信息,可以由結(jié)果路由進(jìn)行層層上傳,最終拋給調(diào)用者,代碼里需要做的就是發(fā)生錯(cuò)誤的時(shí)候處理好后續(xù)的邏輯即可。這個(gè)類(lèi)提供了幾個(gè)靜態(tài)方法快速的處理結(jié)果路由

 

 

通訊核心說(shuō)明


講完了結(jié)果路由再來(lái)說(shuō)說(shuō),整個(gè)網(wǎng)絡(luò)類(lèi)的核心在于 NetworkBase類(lèi),在項(xiàng)目的開(kāi)發(fā)過(guò)來(lái)中,尤其是開(kāi)發(fā)了幾個(gè)不同的PLC和C#程序之間的服務(wù)器客戶端通信之后,發(fā)現(xiàn)有些底層代碼是有些重復(fù)的,所以經(jīng)過(guò)不斷的提煉代碼形成了所有網(wǎng)絡(luò)的底層基類(lèi),這個(gè)類(lèi)呢,只是提供了一個(gè)socket相關(guān)通用的操作邏輯,比如,創(chuàng)建并連接的socket對(duì)象,接收指定長(zhǎng)度的數(shù)據(jù),發(fā)送字節(jié)數(shù)據(jù),關(guān)閉,接收流,發(fā)送流等等操作。

 

這個(gè)類(lèi)實(shí)現(xiàn)了基礎(chǔ)的字節(jié)收發(fā)功能和連接斷開(kāi)功能。接下來(lái)就是 NetworkDoubleBase 類(lèi)的實(shí)現(xiàn),實(shí)現(xiàn)了長(zhǎng)短連接的操作,在我們實(shí)際讀寫(xiě)設(shè)備的過(guò)程中,網(wǎng)絡(luò)狀況往往是差別很大,所以本項(xiàng)目的初衷就是同時(shí)支持長(zhǎng)連接和短連接。根據(jù)大家需求的不同,

所謂的短連接是讀取的時(shí)候再連接,讀取完成就關(guān)閉連接。缺點(diǎn)就是連接打開(kāi)和關(guān)閉耗時(shí),影響讀取速率,優(yōu)點(diǎn)就是對(duì)網(wǎng)絡(luò)狀況反饋即使,讀取失敗了就說(shuō)明網(wǎng)絡(luò)斷了,適合頻率較低的讀寫(xiě)。

長(zhǎng)連接就是讀取開(kāi)始前連接一次,就不再關(guān)閉,進(jìn)行頻繁的讀取,最后再關(guān)閉,好處當(dāng)然是高速了,缺點(diǎn)就是網(wǎng)絡(luò)狀況不是那么好的時(shí)候,效率比較低下,對(duì)網(wǎng)絡(luò)狀況反應(yīng)也不及時(shí)。

短連接就是直接的實(shí)例化,然后讀取寫(xiě)入操作,每一次操作都是一次完整的通信過(guò)程。

切換長(zhǎng)連接有兩種辦法,效果是一致的,

1. 對(duì)象讀寫(xiě)前調(diào)用ConnectServer();

2. 對(duì)象讀寫(xiě)前調(diào)用SetPersistentConnection( );

這兩個(gè)方法都是雙模式類(lèi)里支持并實(shí)現(xiàn)的。所有的派生類(lèi)都符合這個(gè)調(diào)用機(jī)制。

 

實(shí)現(xiàn)了長(zhǎng)短的連接后,還要實(shí)現(xiàn)設(shè)備的BCL類(lèi)型的讀寫(xiě),本質(zhì)是基于byte數(shù)組和C#基礎(chǔ)類(lèi)型的轉(zhuǎn)換,但是這里有個(gè)問(wèn)題,不同的PLC,modbus協(xié)議對(duì)于轉(zhuǎn)換的格式不是固定的,有可能是一樣的,有可能不是一樣的,所以又抽象出來(lái)一個(gè) IByteTransform 接口

 

 這個(gè)接口集成到了下面的設(shè)備交互的基類(lèi) NetworkDeviceBase 里,這個(gè)基類(lèi)實(shí)現(xiàn)了一些基礎(chǔ)的類(lèi)型的數(shù)據(jù)讀寫(xiě)。

所以到這里可以看到,從NetworkDeviceBase類(lèi)繼承出去的設(shè)備類(lèi)(大部分的設(shè)備通信協(xié)議都是從這個(gè)繼承出去的),其基本的讀寫(xiě)代碼都是一致的,關(guān)于解析協(xié)議,通信的底層都是封裝完畢,

 

 

通訊舉例說(shuō)明


先舉例說(shuō)明三菱PLC的讀寫(xiě)操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 實(shí)例化對(duì)象,指定PLC的ip地址和端口號(hào)
MelsecMcNet melsecMc = new MelsecMcNet( "192.168.1.110", 6000 );
// 連接對(duì)象
OperateResult connect = melsecMc.ConnectServer( );
if (!connect.IsSuccess)
{
    Console.WriteLine( "connect failed:" + connect.Message );
    return;
}
// 舉例讀取D100的值
short D100 = melsecMc.ReadInt16( "D100" ).Content;
melsecMc.ConnectClose( );

經(jīng)過(guò)層層封裝后,讀寫(xiě)的邏輯精簡(jiǎn)為,實(shí)例化,連接,讀寫(xiě),關(guān)閉。無(wú)論是三菱的PLC,還是西門(mén)子的PLC,都是一致的,因?yàn)榛?lèi)的模型都是一致的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 實(shí)例化對(duì)象,指定PLC的ip地址和端口號(hào)
SiemensS7Net siemens = new SiemensS7Net( SiemensPLCS.S1200, " 192.168.1.110" );
// 連接對(duì)象
OperateResult connect = siemens.ConnectServer( );
if (!connect.IsSuccess)
{
    Console.WriteLine( "connect failed:" + connect.Message );
    return;
}
// 舉例讀取M100的值
short M100 = siemens.ReadInt16( "M100" ).Content;
siemens.ConnectClose( );

當(dāng)然,支持大多數(shù)的C#類(lèi)型數(shù)據(jù)讀寫(xiě)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MelsecMcNet melsec_net = new MelsecMcNet( "192.168.0.100", 6000 );
// 此處以D寄存器作為示例
short short_D1000 = melsec_net.ReadInt16( "D1000" ).Content;         // 讀取D1000的short值
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ù)
// 讀取數(shù)組
short[] short_D1000_array = melsec_net.ReadInt16( "D1000", 10 ).Content;         // 讀取D1000的short值
ushort[] ushort_D1000_array = melsec_net.ReadUInt16( "D1000", 10 ).Content;      // 讀取D1000的ushort值
int[] int_D1000_array = melsec_net.ReadInt32( "D1000", 10 ).Content;             // 讀取D1000-D1001組成的int數(shù)據(jù)
uint[] uint_D1000_array = melsec_net.ReadUInt32( "D1000", 10 ).Content;          // 讀取D1000-D1001組成的uint數(shù)據(jù)
float[] float_D1000_array = melsec_net.ReadFloat( "D1000", 10 ).Content;         // 讀取D1000-D1001組成的float數(shù)據(jù)
long[] long_D1000_array = melsec_net.ReadInt64( "D1000", 10 ).Content;           // 讀取D1000-D1003組成的long數(shù)據(jù)
ulong[] ulong_D1000_array = melsec_net.ReadUInt64( "D1000", 10 ).Content;        // 讀取D1000-D1003組成的long數(shù)據(jù)
double[] double_D1000_array = melsec_net.ReadDouble( "D1000", 10 ).Content;      // 讀取D1000-D1003組成的double數(shù)據(jù)

寫(xiě)入的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MelsecMcNet melsec_net = new MelsecMcNet( "192.168.0.100", 6000 );
// 此處以D寄存器作為示例
melsec_net.Write( "D1000", (short)1234 );                // 寫(xiě)入D1000  short值  ,W3C0,R3C0 效果是一樣的
melsec_net.Write( "D1000", (ushort)45678 );              // 寫(xiě)入D1000  ushort值
melsec_net.Write( "D1000", 1234566 );                    // 寫(xiě)入D1000  int值
melsec_net.Write( "D1000", (uint)1234566 );               // 寫(xiě)入D1000  uint值
melsec_net.Write( "D1000", 123.456f );                    // 寫(xiě)入D1000  float值
melsec_net.Write( "D1000", 123.456d );                    // 寫(xiě)入D1000  double值
melsec_net.Write( "D1000", 123456661235123534L );          // 寫(xiě)入D1000  long值
melsec_net.Write( "D1000", 523456661235123534UL );          // 寫(xiě)入D1000  ulong值
melsec_net.Write( "D1000", "K123456789" );                // 寫(xiě)入D1000  string值
// 讀取數(shù)組
melsec_net.Write( "D1000", new short[] { 123, 3566, -123 } );                // 寫(xiě)入D1000  short值  ,W3C0,R3C0 效果是一樣的
melsec_net.Write( "D1000", new ushort[] { 12242, 42321, 12323 } );              // 寫(xiě)入D1000  ushort值
melsec_net.Write( "D1000", new int[] { 1234312312, 12312312, -1237213 } );                    // 寫(xiě)入D1000  int值
melsec_net.Write( "D1000", new uint[] { 523123212, 213,13123 } );               // 寫(xiě)入D1000  uint值
melsec_net.Write( "D1000", new float[] { 123.456f, 35.3f, -675.2f } );                    // 寫(xiě)入D1000  float值
melsec_net.Write( "D1000", new double[] { 12343.542312d, 213123.123d, -231232.53432d } );                    // 寫(xiě)入D1000  double值
melsec_net.Write( "D1000", new long[] { 1231231242312,34312312323214,-1283862312631823 } );          // 寫(xiě)入D1000  long值
melsec_net.Write( "D1000", new ulong[] { 1231231242312, 34312312323214, 9731283862312631823 } );          // 寫(xiě)入D1000  ulong值

這里舉例了三菱的PLC,實(shí)際上各種PLC的操作都是類(lèi)似的。

 Redis實(shí)現(xiàn)


 

除了上述的基本的設(shè)備通信,還實(shí)現(xiàn)了redis數(shù)據(jù)庫(kù)讀寫(xiě)操作,分了兩個(gè)類(lèi)實(shí)現(xiàn),下圖為一般的通信功能

同時(shí)demo中實(shí)現(xiàn)了一個(gè)瀏覽redis服務(wù)器的界面功能

redis

 

最后的總結(jié)


 本通信庫(kù)實(shí)現(xiàn)了.net 3.5 和 .net 4.5的框架,還附帶了一些簡(jiǎn)單的控件,此外還實(shí)現(xiàn)了.net standard版本,已在linux測(cè)試成功,由于官方在.net core2.2中還未實(shí)現(xiàn)串口類(lèi),所以暫時(shí)沒(méi)有實(shí)現(xiàn)串口相關(guān)的。

未來(lái)的方向,希望繼續(xù)優(yōu)化代碼,架構(gòu),集成實(shí)現(xiàn)更多設(shè)備通信,方便廣大的網(wǎng)友直接開(kāi)發(fā)測(cè)試。

 

開(kāi)源地址:https://github.com/dathlin/HslCommunication

官網(wǎng):http://www./

 更多詳細(xì)的內(nèi)容請(qǐng)查看源代碼的readme文件。

 

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多