摘要:研究了軟件PLC中梯形圖的邏輯化表達以及編譯為指令表的實現方法,對梯形圖元素之間的串并聯關系進行了深入探討,在此基礎上給出了基于C++的梯形圖邏輯表達模型,實現了梯形圖到指令表的轉換。該實現在可擴展性以及支持復雜梯形圖轉換方面具有一定優勢。
關鍵詞:軟件PLC;梯形圖;邏輯表達模型
中圖分類號:TP273文獻標識碼:A文章編號:1009-3044(2008)33-1399-03
On Implementing Ladder-diagram Compilation with C++ in Soft-PLC
YUAN Chun-hua, SHI Jing, BO Zhan-chun
(Dept. of Automobile and Digital Control, Shanghai Xinqiao Vocational and Technical College, Shanghai 201806, China)
Abstract: The logic expression of the ladder diagram (LD) and the realization method of compiling the LD to the instruction list (IL) in soft PLC were studied. The series-parallel connection between the LD elements was thoroughly analyzed. Based on this work, the logic expression model of the LD based on C++ was given and the conversion from LD to IL implemented. The implementation has certain advantages in its expansibility and in supporting complicated LD conversion.
Key words: soft PLC; ladder diagram; logic expression model
1 引言
工業自動化控制領域的國際標準IEC61131的推出和實施,使得遵循此國際標準,充分利用工控機或嵌入式計算機的軟硬件資源,用軟件來實現和擴展傳統硬件PLC的功能得以實現。
軟件PLC以通用操作系統和PC為軟硬件平臺,用軟件實現傳統硬件PLC的控制軟功能。軟件PLC的開發中,編程語言模塊的開發是其中的一個關鍵環節。IEC61131-3標準中提出了5種編程標準語言,分別是:梯形圖、功能塊圖、順序功能圖、指令表和結構化文本。每一種語言都有其優點和適用的人群,梯形圖直觀明了,為大多數的工程人員所喜用,是編寫PLC的首選語言。由梯形圖編制的PLC程序一般需要首先經過編譯并轉換為指令表程序(或進一步編譯成特定的字節碼)后,才可以加載到相應的軟PLC執行系統上運行。
本文分析了梯形圖元素間的不同串并聯關系,以C++為開發語言實現了梯形圖程序到指令表程序的編譯轉換。
2 梯形圖的邏輯表達
實現梯形圖的軟件化編輯、存儲以及編譯、執行,首先必須對梯形圖模型進行分析,并在此基礎上結合軟件程序設計的基本原理,構造符合梯形圖表達及運行特點的軟件表達。基于面向對象編程中繼承、數據封裝及多態的概念,首先對梯形圖中的圖形化元素進行數據抽象和行為抽象,然后在此基礎上建立起適合梯形圖表達的C++類層次圖。
為表達梯形圖中的不同元素之間的各種連接關系,我們引入“根(Root)”、“集合點(Assembly Point)”以及“分支(Branch)”的概念:從根可以引出多條分支,每條分支由若干元素串聯而成,而這些分支或者連接到某一集合點,或者連接到輸出節點;匯集在某一集合點的若干條分支之間構成了一種并聯關系(如圖1所示)。
根和集合點是梯形圖中的虛擬元素,它們不代表任何實際的元件或者軟觸點,但這兩類虛擬元素的引入為描述梯形圖中元素以及分支之間的復雜連接關系提供了極大的方便。根元素中記錄了從該根節點引出的所有分支信息;而集合點元素中則記錄了有哪些分支連接到該集合點。分支則是梯形圖中的另一個虛擬元素:具有直接串聯關系的若干元素構成一個分支。根以及集合點都可以成為分支上的元素;一條分支或者結束于某個根節點或輸出節點,或者連接到某個集合點后結束。
梯形圖中的元件(如計數器、定時器等)觸點、功能塊單元以及輸出單元都可以看作是梯形圖中基本元素。采用面向對象方法對梯形圖結構進行抽象,我們定義基類LDElement表征不同元素的最基本屬性和方法,同時針對不同種類的元素定義相應的派生類。其相應的C++描述示意如下:
class LDElement{
virtual void compile(LDElement*) = 0; //編譯該元素
LDRoot* m_pRoot; //該元素的直接Root節點
LDBranch* m_pParent; //該元素的直接父節點
};
class LDBranch : public LDElement{
virtual void compile(LDElement*);
std::list
};
class LDRoot : public LDElement{
virtual void compile(LDElement*);
std::list
};
class LDAssemblyPoint : public LDElement{
virtual void compile(LDElement*);
std::list
};
在設計中充分利用C++ 標準模版庫提供的各種標準容器類(如鏈表容器類std::list等)可以方便實現梯形圖元素節點的動態添加和刪除,極大地簡化了系統開發。

圖1 根、集合點示意圖
利用C++面向對象技術,通過將梯形圖中的不同類型元素進行抽象,同時引入“根”以及“集合點”兩類虛擬梯形圖元素,可以使我們能夠以一種一致的方式表達梯形圖的復雜邏輯關系。在這種邏輯表達下,梯形圖的左母線可以看作是整個梯形圖的Root節點,而一個完整的梯形圖則可以用一個Root節點來表達。事實上,在我們的實現中,梯形圖類LadderDiagram直接繼承自LDRoot類(如圖2所示)。
下面的偽代碼展示了遍歷整個梯形圖基本步驟:
for each(根節點中的分支 LDBranch* pB)
for each(分支中的元素 LDElement* pE)
pE->Visit(); // 訪問元素
3 梯形圖到指令表的編譯轉換
梯形圖的基本執行策略是自上而下、從左至右逐行掃描,循環執行。為完成梯形圖到指令表的轉換,最重要的就是正確識別不同元素及分支之間的連接嵌套關系。根、集合點以及分支這三類梯形圖組件為存儲以及正確識別元素、分支之間連接關系提供了保障。同時,所有梯形圖元素都記錄了以下兩項基本信息:其所屬的直接根節點以及分支節點。對于分支,除了記錄其所屬根節點外,還額外記錄了其連接到的集合點信息。
3.1 元素及分支之間的連接關系分析
3.1.1 串聯關系
串聯關系是梯形圖中最基本,也是最容易識別的連接關系:具有串聯關系的元素總是屬于同一個分支,根以及集合點都可以成為分支上的元素;一條分支或者結束于某個根節點或者結束于某個輸出節點,或者連接到某個集合點后結束。
3.1.2 并聯關系
梯形圖中允許兩種不同的并聯關系:一種稱之為“簡單并聯關系”,即具有并聯關系的若干分支源自相同的直接根節點,同時它們又匯集在同一個集合點。如圖3所示,分支{X1}和{X2}之間形成簡單并聯關系,二者皆源自根R1并在AP1匯合。
另一種稱為“嵌套并聯關系”,即源自相同根節點的若干分支分別連接到不同的集合點(稱之為“同根嵌套”,如圖3中{X2}與{X4,X5}兩分支之間的嵌套關系)或者源自不同根節點的若干分支匯集在同一集合點(稱之為“異根嵌套”,如圖3中{X4,X5}與{X6,X7}兩分支之間的嵌套關系)。在編譯梯形圖的過程中,正確識別不同類型的分支并聯關系是決定是否需要以及在什么時候插入ORB/ANB等塊操作指令的基本依據。
簡單并聯關系的判斷比較簡單:由于分支元素中存儲了根節點和集合點信息,通過檢查兩個分支是否連接到同一個集合點并具有相同的根節點可以很容易得到這一信息。而同根嵌套實際上完全可以看作是簡單并聯關系的泛化,例如圖3中分支{X1}和{X2}的并聯結果同X3相與之后形成一個新的分支,而這個分支與分支{X4,X5}之間實際上形成了一種簡單并聯關系。異根嵌套關系則可以通過比較兩個連接到同一集合點的分支是否具有相同的直接根節點來完成。

圖2 梯形圖主要C++類繼承關系示意圖

圖3 梯形圖分支間并連關系增意圖
3.1.3 多輸出根節點
如果源自某根節點的多個分支最終連接到不同的輸出元素,則我們稱這個節點為“多輸出根節點”。在編譯梯形圖的過程中,正確識別多輸出根節點是決定是否需要使用堆棧指令的基本依據。簡單起見,我們在梯形圖類中跟蹤記錄所有的輸出元素信息,并通過向上逐級回溯其根節點的方法來判定給定根元素是否為多輸出根節點。
3.2 編譯梯形圖
如前所述,梯形圖類直接繼承自LDRoot根元素類,該根元素下的各個分支元素逐級展開,從而完整記錄了梯形圖元素之間的各種連接關系。簡單來講,編譯梯形圖的過程就是逐級遍歷編譯根節點下的所有分支元素,各分支元素再逐個遍歷編譯其包含的元素的過程。
如前所示,抽象基類LDElement定義了統一編譯接口compile(LDElement* pPrev),繼承自LDElement的各個子類通過該接口方法實現自己的編譯過程。
3.2.1 非虛擬元素的編譯
編譯觸點(LDContact)、輸出(LDOutput)等非虛擬元素比較簡單,一般只要根據元素具體類型給出相應的操作指令即可。編譯過程中,需要檢查前一個元素(由compile接口參數pPrev給出)是否為NULL以判斷與前一元素的串并聯關系,并依此對最終操作指令作出選擇。
3.2.2 虛擬元素的編譯
本文所指的虛擬元素主要包括分支、根和集合點三類。
1) 分支的編譯
視具體情況,分支的編譯可能由其直接根元素驅動,也可能由其連接的集合點驅動。如果是集合點驅動的(即在編譯集合點元素時逆向回溯過程中啟動的編譯過程),則編譯前需要首先檢查該分支是否與前一個分支具有相同的直接根元素。如果不同,則表明這兩個分支之間是一種異根嵌套的并聯關系,則需要先插入一條ANB指令;如果相同,則表明這兩個分支之間是一種簡單并聯關系,可以直接開始遍歷并編譯該分支上的元素。當該分支上的所有元素都編譯完成后,還需要檢查是否需要插入ORB指令,這取決于該分支是否為源自根節點的第一個分支以及該分支上是否有多個元素。這一編譯過程的偽代碼示意如下:
void LDBranch::compile(LDElement* pPrev)
{
// 判斷該分支的編譯是否為集合點驅動的
if (pPrev != NULL){ // 是集合點驅動的
// 判斷是否存在異根嵌套關系
if (pPrev->getRoot() != getRoot()){
addInstruction(INST_ANB); // 異根嵌套關系,需插入一條 ANB 指令
}
}
// 開始依次編譯分支上的各個元素
for each LDElement* pE on this branch
pE->compile(pPrev);
if (該分支連接到某個集合點 元素個數超過1){
addInstruction(INST_ORB); // 插入 ORB 指令
}
return ;
}
盡管根元素和集合點元素也都可以成為某個分支上的元素,但在編譯分支上的各個元素時并不需要對此類元素進行任何特殊處理:C++面向對象的多態特性可以保證與具體元素相匹配的編譯過程會被正確執行。
2) 集合點的編譯
集合點總是屬于某個分支,因而其編譯總是發生在分支元素依次編譯其構成元素的過程中。根據梯形圖的基本執行策略,必須等到所有到達該集合點的梯階全部執行完畢后,才可以向下掃描執行下一個元素。為保證這一基本策略,在編譯集合點元素時,采取了一種回溯的編譯機制:即依次遍歷并編譯連接到該集合點的所有分支。
在開始編譯各個分支之前,還需要考慮多輸出根節點的問題。如果某個分支的直接根節點是多輸出根節點,則需要在編譯前插入必要的堆棧操作指令。當該集合點編譯完成后,還需要檢查是否需要插入ANB指令,這取決于該集合點的直接根節點是否為梯形圖本身。該編譯過程的偽代碼示意如下:
void LDAssemblePoint::compile(LDElement*)
{
for each(連接到該集合點的分支 LDBranch* pB) {
if (當前分支的直接根節點為多輸出根節點){
// 檢查當前分支是否為其根節點的最后一條分支
LDRoot* pRoot = pB->getRoot();
if (pRoot->isLastBranch(pB)){
addInstruction(INST_MPP); // 插入 \"MPP\" -- Stack POP 指令
}else{//不是最后一條分支
addInstruction(INST_MRD);//插入\"MRD\" -- Stack Read 指令
}
}
pB->compile(pPrevBranch);// 開始編譯該分支
}
// 所有分支都已編譯完畢,檢查是否需要插入\"AND-BLOCK\"指令
if (如果該根節點不是梯形圖本身)
addInstruction(INST_ANB);
return;
}
3) 根的編譯
由于梯形圖類直接繼承自根元素類,因此從某種意義上來講,根元素的編譯過程實際上也就是梯形圖的編譯過程。與編譯最頂端根元素(即梯形圖)不同的是,在編譯普通根元素下的各個分支前,需要判斷該根元素是否為多輸出根節點,并根據具體情況決定是否需要插入必要的堆棧操作指令。限于篇幅,此處不再展開。
4 結束語
作者采用面向對象的數據抽象技術,建立了基于C++的梯形圖邏輯表達模型,并通過引入根、集合點以及分支等梯形圖虛擬元素,完整記錄了梯形圖的復雜邏輯關系,實現了梯形圖到指令表的編譯轉換。
測試結果表明,該實現較好地實現了梯形圖到指令表的轉換,可以很好地支持具有復雜串并聯關系的梯形圖,其編譯結果可以達到手工編譯結果一致的水平。面向對象技術的多態特性也為該系統的可擴展性提供了技術保障。
參考文獻:
[1] 莫易敏.PLC梯形圖轉化為指令表算法及實現[J].控制工程,2006,13(6):573-576.
[2] 張萬忠.可編程控制器應用技術[M].北京:化學工業出版社,2005.
[3] 葛芬.基于AOV圖及二叉樹的梯形圖與指令表互換算法[J].南京航空航天大學學報,2006,38(6):754-758.
[4] 黃云鷹.軟PLC梯形圖可視化編輯軟件C++實現[J].機電一體化,2006,12(5):52-54.
[5] 尚靖.基于開放式數控系統平臺的軟件PLC[J].機械與電子,2006(7):14-17.
[6] 儀維.基于JAVA環境的軟PLC平臺的研究與開發[J].機電一體化,2007(1):39-42.