施昊言 王庭有
(昆明理工大學機電工程學院)
PLC在如今的工業發展趨勢下扮演著越來越重要的角色,未來對于控制系統的要求會更高。 我國PLC編程軟件尚在起步階段,許多理論技術仍需攻克, 故對于編程軟件的研究不但有非常大的市場需求,在學術發展上也同樣具有很大的價值。
羅驍等利用MATLAB的GUI工具搭建指令表語言編輯界面,實現了指令表的編輯并將指令表語言轉換為硬件可以識別的編碼[1]。 李應春等基于Qt開發了一種功能較為豐富的PLC編程軟件,可以實現梯形圖語言的編輯,并將梯形圖語言通過自研轉換算法轉換為指令表語言,但無法對指令表語言進行編輯并將指令表語言轉換為梯形圖語言[2]。 趙會勇提出一種指令表轉梯形圖的方法,但沒有實現到軟件中[3]。
在此, 筆者通過分析指令表各類指令的特點,結合棧對指令進行歸并,歸并過程中對梯形圖繪制坐標進行改變, 從而確定各梯形圖位置,完成指令表到梯形圖的轉換。
指令表語言與梯形圖語言不同,梯形圖程序有相應的流動順序,而指令表更突出于其接近底層編程語言的特性,以操作堆棧為主,因而其程序運行更加快速高效[4~6],但同時也會導致容易寫錯指令句,為此需要將重點放在指令表的堆棧結構是否正確上。
指令表語言中,不同指令對堆棧的操作是有差異的, 在將指令表轉換為梯形圖的過程中,需要考慮各種指令對棧深的要求。 MPS、LD等指令會使棧的深度增加,其中LD指令會對相應的寄存器操作,取出保存的數據并壓棧,增加棧深度,處理這類指令時要保證棧深在最大值以內。 MPP、ANB、ORB等指令會使棧深減少,其中MPP指令是彈出棧頂數據,ANB和ORB是將棧頂前2個數據取出進行與或操作得到1個結果,再將該結果壓棧,棧內元素從2個降為1個,棧深減少,故需要保證棧的深度不能為0, 棧內沒有數據會造成指令執行錯誤。 MRD、OUT等指令不對堆棧進行操作,不會對棧深造成影響,但需要保證棧深大于1,否則無法讀取數據, 導致轉換失敗。 MPS壓棧指令和MPP出棧指令要成對,MRD指令需要有MPS指令為前提才能使用。
為了準確實現轉換過程,不僅需要在轉換前完成指令表的語法檢測,還需要考慮指令表轉換后得到的結果能否符合梯形圖的語法規則,如果忽略了梯形圖的屬性問題,就會造成轉換得到的結果無法被硬件處理的結果,因此需要制定轉換規則。
梯形圖在軟件中以矩陣形式儲存元件位置,通過橫豎連接線組成邏輯塊,在向梯形圖轉換時,就是要將指令轉換成對應的邏輯塊。 指令表的特性是堆棧操作, 因而構建其與梯形圖的聯系時也需要建立在堆棧操作之上,指令表程序運行時,遇到堆棧深度增加的情況, 就代表梯形圖構建了新的邏輯塊。 若堆棧深度減少,相當于2個邏輯塊發生了新的“與”或者“或”的邏輯合并。 但有部分情況的指令表是無法實現轉換的[7],例如,OUT指令后不能使用ORB指令,程序段如下:

其中, 第1、2條指令構成了一條完整的輸入輸出塊,第3條指令生成了一個輸入元件,將這兩個塊進行“或”合并,得到的梯形圖如圖1所示,該程序違背了梯形圖的編輯準則,故程序錯誤。

圖1 “或”錯誤
指令壓棧后,指令構成的梯形圖塊下方不能新增元件,程序段如下:

若按照指令表的規則將梯形圖轉換出來,得到的結果如圖2所示。

圖2 “與”錯誤
由于只有X1被壓棧, 后續增加X1下方的X2與X4元件并未入棧,在出棧后輸出Y2時,Y2要穿過X4與X5之間的連接線從X1輸出, 從而導致X3短路,程序錯誤。 因此,當有梯形圖邏輯塊被壓棧時,塊的y軸方向不允許再添加新的元件。
在指令表語言中,AND指令代表兩個元件串聯,OR指令代表兩個元件并聯, 這兩條指令中的元件很容易判斷它們在梯形圖中的位置,一般是以前一條指令中的元件為參考點來計算。對于LD類指令,代表一個新邏輯塊第1個元件,但無法從該指令中知道元件是并聯邏輯塊和串聯邏輯塊中的哪一個起始的。 通常需要借助ANB、ORB這類指令的輔助才能判斷:與ANB成對出現,是串聯邏輯塊的起始;與ORB成對出現,則是并聯塊;如果是單獨出現,則代表該元件是整個程序的起始元件。
考慮到以上問題, 將LD指令轉換為ANB、ORB這類邏輯清晰的指令來判斷邏輯關系:當LD和ALD成對出現時, 給LD指令增加標記AND,當LD和ORB成對出現時, 增加標記OR, 單獨出現時,增加標記SIGLE。
指令表向梯形圖轉換的步驟如下。
第1步,設計梯形圖位置判斷方式。 將指令表轉換為梯形圖,需要知道該梯形圖在軟件界面中的坐標,才能在梯形圖編輯界面中繪制相應的元件圖, 而元件坐標位置的變換與進棧順序有關。首先定義一個表示元件位置的結構體:

結構體的TopLeft代表左上角頂點,Bottom-Right代表右下角頂點,這兩個頂點構成的對角線決定了一個邏輯塊所處的位置及所占的行數和列數,如圖3所示,通過紅色虛線框內左上角星點可以得到X6、X7、X8組成的邏輯塊的起點坐標,再結合右下角星點坐標就可以計算出該邏輯塊為2行2列。 Point也是結構體,其成員變量就是點的x、y坐標,程序段如下:

圖3 確定元件坐標
struct Point

在轉換過程中,需要經常將Location類對象壓棧出棧,并頻繁取用該對象信息,因此令Location1是位于棧頂的類對象,Location2為棧內的下一個類對象,為了簡化表述,再令:

第2步,LD指令設置標志。 順序遍歷指令表,若為LD指令,則將其壓入棧中,并將LD指令標志位設為SINGLE;若為ORB指令,則修改置于棧頂的LD指令的標志位為OR,并彈出棧頂指令;若為ANB指令,則修改置于棧頂的LD指令的標志位為AND,并彈出棧頂指令。
如圖4所示, 以梯形圖轉換得到的指令表為例,掃描到LD1后,將該指令標志位設為SINGLE;繼續向下遍歷,掃描到LD3后,將該指令標志位設為SINGLE,掃描到ORB指令后,則將LD3的標志位修改為OR;掃描到LD6,將LD6標志位設為SINGLE,掃描到ANB指令后, 則修改LD6標志位為AND;繼續掃描,LD10的標志位也為AND。

圖4 為指令表設置標志位
第3步,掃描指令表程序,轉換為梯形圖。 第2步得到LD帶有標志位的指令表,只要結合標志位遍歷指令,并借助棧調整元件坐標,就能在編輯界面繪制得到相應的梯形圖,不同指令對于棧和元件坐標的影響也不同,掃描過程如下:
a. 創建一個Location對象, 并將該對象壓入棧中, 由于此時梯形圖編輯界面為空, 如圖5所示,因此TLx=0,TLy=0,BRx=0,BRy=0。

圖5 梯形圖初始界面
b. 掃描LD指令。若標志位為SINGLE,則此元件為程序的起始,在梯形圖編輯界面(0,0)處繪制元件,如圖6所示,并將該元件的位置信息對象Location 壓 入 棧 中, 此 時TLx=0,TLy=0,BRx=BR1x+1,BRy=BR1y+1。

圖6 LD指令對坐標的影響
若標志位為AND,則此元件為串聯邏輯塊的起始,在梯形圖編輯界面坐標(TL1x+1,TL1y)位置繪制元件,并將該元件的位置信息對象Location壓入棧中,且TLx=TL1x+1,TLy=TL1y,BRx=BR1x+1,BRy=BR1y。
若標志位為ORB,則此元件為并聯邏輯塊的起始,在梯形圖編輯界面坐標(TL1x,TL1y+1)位置繪制元件,并將該元件的位置信息對象Location壓入棧中,且TLx=TL1x,TLy=TL1y+1,BRx=BR1x,BRy=BR1y+1。
c. 掃描AND指令。AND指令代表兩個邏輯塊是串聯關系,需要在(TL1x+1,TL1y)處繪制元件,如圖7所示, 并修改棧頂Location對象信息, 此時TLx=TL1x,TLy=TL1y,BRx=BR1x+1,BRy=BR1y。

圖7 AND指令對坐標的影響
d. 掃描OUT指令。 由于該指令不會對棧進行任何操作,只需在(TL1x+1,TL1y)位置繪制輸出線圈即可, 同時修改棧頂對象數據為TLx=TL1x+1,TLy=TL1y,BRx=BR1x+1,BRy=BR1y。
e. 掃描ORB指令。 ORB指令將棧內的兩個邏輯塊進行“或”操作并生成新的塊,使棧深降低。兩個邏輯塊進行合并后,視不同情況進行補線。
插入橫線。 比較Location1和Location2的BRx值, 取最小值, 假設Location1的BR1x小于Location2的BR2x,則在(BR1x,TL1y)處繪制橫線,橫線長度為BR2x-BR1x。 修改Location2的信息為TLx =TL2x,TLy =TL2y,BRx =max (BR1x,BR2x),BRy=max(BR1y,BR2y),并彈出棧頂對象。
插入豎線。 在補齊橫線之后,只需在這兩個邏輯塊最右方加入豎線連接即可。
f. 掃描OR指令。 OR指令代表該元件與前面邏輯塊是并聯的,需要在(TL1x,TL1y+1)處繪制元件,根據ORB指令中的補線思想插入相應的橫豎線, 并將棧頂Location對象信息修改為TLx=TL1x,TLy=TL1y,BRx=BR1x,BRy=BR1y+1。
g. 掃描ANB指令。 ANB指令是將棧內的兩個邏輯塊進行“與”操作并生成新的塊,使棧深降低,和ORB指令不同的是,兩個邏輯塊不需要進行補線操作, 因此只需修改Location2的信息為TLx =TL2x,TLy =TL2y,BRx =max (BR1x,BR2x),BRy=max(BR1y,BR2y),并將棧頂對象彈出。
最終得到梯形圖如圖8所示。

圖8 轉換結果
考慮到指令表語言的內存操作特性以及梯形圖在結構上的轉換問題,筆者提出了一種借助棧實現的塊合并轉換算法,通過對多意指令LD設置標志位區分功能,二次掃描帶標志的指令表并通過棧改變元件在編輯界面的顯示坐標,最終完成指令表到梯形圖的轉換。