本文是CSDN上看到的一篇質量比較高的文章,自己仔細讀了幾遍收獲很大,值得一起學習。我在作者的基礎上重新排版添加了一些備注和修改了一些錯誤的地方。由于字數比較多,因此分成了上下篇。
一、前言
本文將會講解高度抽象的設計模式,設計模式與案例無關,并不以案例講題。反正學校按這種方式教了那么久也沒人聽得懂。我將主要以理論為主,避免與具體案例綁定,以防止讀者先入為主,以為某一設計模式只能適用于某案例,或某一設計模式只能單獨使用,不能結合其它設計模式,又或者某一案例只適合某一設計模式。
快捷鍵:
- Shift + Alt + F4 轉換和編譯所有程序
- Alt + O + W PLC寫入
簡單程序
Y0 := TRUE;
K1Y1 := HF;//指從Y1開始的4個連續端口設置為二進制1111,也就是四路導通。
為什么要用K開頭呢? K在PLC符號中代表后面的文本將作為十進制數字使用,然而數字不能用于標識符的第一個字母,這是所有編程語言的通例。 K1是指4個連續端口。為什么是4個? 1位16進制數代表4個端口。這個K1是指“1位16進制數”的意思,也就是4個開關量。如果改為K2,就是“2位16進制數”,代表8個開關量。Y1表示從Y1端口開始計數,實際上就是C語言里的起始指針,數組指針之類的含義。
三菱ST編程相對西門子更簡單,因為它可以直接使用X、Y、M、D這幾個系統標識,而西門子變量和端口全部都要聲明,然后定義到指定地址才能使用。
二、結構化文本入門
PLC的經典用法就是串并聯邏輯電路,ST語言的串聯用AND操作符,并聯用OR操作符,動斷觸點(常閉)用NOT操作符,此外還支持奇校驗XOR操作符。
2.1 單按鈕
M1 := X0 AND NOT M0;(* 上升沿檢測,如果X0是通,M0是斷,則M1是通 *)
Y0 := Y0 XOR M1;(* 上升沿的時候轉換狀態,如果Y0和M1中通的個數為單數,則Y0為通,否則為斷 *)
M0 := X0;(* 記憶X0的上一個狀態 *)
2.2 起保停
X0為通時Y0設置為通,X1為通時Y0設置為斷,自鎖電路。
Y0 := NOT X1 AND (X0 OR Y0);
在梯形圖中,有一種專業的自鎖電路的替代方法,就是SET和RST指令。它們在ST中被封裝成系統宏函數。
SET(X0, Y0);(* 按下X0時,Y0置位 *)
RST(X1, Y0);(* 按下X1時,Y0復位 *)
這是推薦使用的方法,簡單易懂。ST宏函數和系統功能塊非常多,我們能夠記住一些指令就很不容易了,何況它們還有不同的參數。GX Work2提供了一個快捷鍵,Ctrl + F1,把插入點定位在寫好的函數名上,按Ctrl + F1,IDE會自動插入參數提示。如果連函數名也不記得了,可以在右邊的窗口雙擊插入函數名或功能塊名。西門子Portal則是從左邊的自定義程序和右邊的系統程序中拖拽到工作區。系統函數的第一個形參都是使能標志,相當于每一個系統函數內置了一個條件表達式,只有當第一個形參傳入TRUE(通)的時候,才執行指令的功能。
2.3 XOR高電平奇校驗
Y0 := X0 XOR X1 XOR X2;//做一個三聯開關,X0,X1,X2的狀態變化都會引起Y0翻轉。
這個程序在X0,X1,X2之中任意一個改變狀態時,都會使Y0狀態變化,也就是任意一個開關都可以自由地操作燈的亮滅。這個表達式如果要用標準的串并聯梯形圖來做,會非常麻煩。
- 連續XOR表達式也叫“ 高電平奇校驗 ”就是輸入點中TRUE的個數為單數的時候,結果為TRUE,雙數的時候結果為FALSE。
- 連續WOR表達式( 低電平奇校驗 )的效果是輸入點中的FALSE個數為單數時,結果為FALSE,雙數的時候結果為TRUE。
我們做邏輯運算多用的是高電平奇校驗公式,很少用到低電平奇校驗公式。當奇校驗公式中有奇數個常量目標電平時,根據奇校驗的算法,可以證明它等價于偶校驗,其實也等于在中間的某個位置加入一個NOT運算符或對最終結果取反。
了解了奇校驗的特點后,我們也可以用一個計數器來代替奇校驗公式。
2.4 上升沿和下降沿
ST中的上升沿檢測使用LDP,下降沿使用LDF。升級版的單按鈕控制:
Y0 := Y0 XOR LDP(TRUE, X0);
LDP的第一個形參還是使能的意思,幾乎所有的指令都有很大概率在第一個形參寫TRUE,因為三菱PLC所有的指令都需要使能,而多數情況下,這些指令是需要永久使能的。LDP的第二個形參是上升沿檢測的變量,這里檢測的是X0的上升沿。實際上對應單片機內部電路,X0的引腳可能是收到了下降沿,這個LDP是指的從斷到通的狀態,與單片機電平方向無關。當收到上升沿的時候,LDP返回一個掃描周期的TRUE,TRUE與XOR組合,就等價于一個NOT,就將Y0翻轉了,而LDP只返回一個掃描周期的TRUE,所以也只有這一個掃描周期的XOR等價于NOT,其余掃描周期則為XOR FALSE,也就是不起作用。這樣就實現了X0在從斷到通時Y0會發生狀態翻轉,也就是記憶按鈕的效果。
2.5 定時器和計數器
定時器
輸出自變量,ENO:執行結果:位。定時器觸點:TS普通,STS累計。定時器線圈:TC普通,STC累計。定時器當前值:TN普通,STN累計。
計數器
輸出自變量,ENO:執行結果:位。計數器觸點:CS。計數器線圈:CC。計數器當前值:CN
擴展AB相編碼器的ST寫法
擴展閱讀https://blog.csdn.net/rediculous/article/details/102656817 注意: ST語言不能直接寫C251
- C和T元件的線圈加第二個字符C,如CC0, TC1等,C就是
Coin
線圈。 - 觸點加S,如C0的觸點就是CS0,S就是
Switch
開關的意思。 - 數值加N,如C0的數值就是CN0,N是
Number
數字的意思。
ST編寫AB相編碼器
OUT_C_32(TRUE,CC251,0);
第一個參數是使能C251,當它為TRUE時,X0和X1被指定用于C251,這是PLC內部系統的設計,無法更改。第二個參數如果是CC251,表示使用C251,如果是CC252就使用C252。
C252比C251多使用一個X2作為復位。C254比C252多一個X6做外部使能。C253和C252功能一樣,但綁定的是X3,X4,X5。C255和C254功能一樣,但綁定的是X3,X4,X5,X7。
第三個參數是CS251的閥值。即CS251 := CN251 >= [第三個參數]
。與普通計數器不同,第三個參數不會限制計數器的增長。如果不需要使用CS251,則第三個參數可以隨便寫。計數器復位當然,C251也可以使用RST(X2, CN251);來復位,C252也可以用OUT_C_32(X6, CC252, 0);RST(X2, CN252);達到與C254一樣的效果。但指令表的響應時間為0.3ms,比直接使用內置的功能慢。
梯形圖剩下的功能就只有定時器和計數器了。下面演示一下定時器和計數器的用法。這個程序功能為按下X0兩次后,Y0輸出1秒的通,然后變回斷。
OUT_C(X0, CC0, 2);(* 對X0計數,它是邊沿有效的,計數器C0,CC0是C0的線圈,第2個C代表"Coin" *)
SET(CS0, M0);(* 達到2的時候,CS0變為TRUE,對M0置位,將M0也變為TRUE,CS0是C0的觸點,第2個S代表"Switch"開關的意思 *)
RST(M0, CN0);(* M0為TRUE時,復位計數器C0,M0為TRUE時,按X0不會計數,因為它一直被復位,CN0是C0的數值,第2個N是"Number"數字的意思 *)
OUT_T(M0, TC0, 10);(* M0為TRUE時,定時器T0開始計時,三菱FX3U定時器單位是100ms,第3個參數10表示1秒 *)
RST(TS0, M0);(* 時間到的時候TS0為TRUE,這一步就會復位M0,將系統狀態變回起始值 *)
Y0 := M0;(* 將M0的值從Y0輸出 *)
三、語句
3.1 條件分支IF-THEN…ELSE_IF-THEN…ELSE…END_IF;
我們再來試試自鎖電路的一種標準化寫法,它同樣具有很好的可讀性。
IF X0 THEN
Y0 := TRUE;
ELSE_IF X1 THEN
Y0 := FALSE;
END_IF;(* 注意:這個END_IF是要加分號結尾的,ST語言坑死人,多少新手被坑在這里好久才發現突然需要一個分號 *)
比起SET和RST,使用了條件分支使程序看起來更像是說明文檔。它的大意是:“如果X0通了,則讓Y0也通,如果X0沒通,但是X1通了,就讓Y0斷開,如果以上條件都不滿足,就什么也不做,保持之前的狀態。” 再來一個自鎖(X0,X1)+強制點動(X2)+翻轉(X3)的綜合型開關電路,動力輸出設計為Y4,并且每當按下按鈕時,會有對應的指示燈亮起,指示燈設計Yn對應Xn:
K1Y0 := K1X0;(* 4路指示燈直接賦值 *)
IF X0 THEN
Y4 := TRUE;(* 啟動 *)
ELSE_IF X1 THEN
Y4 := FALSE;(* 停止 *)
ELSE_IF LDP(TRUE, X3) THEN
Y4 := NOT Y4;(* 翻轉 *)
ELSE_IF LDP(TRUE, X2) OR LDF(TRUE, X2) THEN
Y4 := X2;(* X2動作時,取消記憶,強制變為手動 *)
END_IF;(* 再次強調:這個END_IF是要加分號結尾的,ST語言坑死人,多少新手被坑在這里好久才發現突然需要一個分號 *)
讀者可以自己試試用梯形圖串并聯方式實現這個電路,一個簡單的功能做成梯形圖也會非常復雜。條件分支的完整模板為:
IF conditions THEN
tasks;(* 語法上IF語句任何一段分支的tasks都可以是空的。如果是空的,分號也可以不要 *)
ELSE_IF conditions THEN (* 如果沒有其它條件,ELSE_IF必須省略,如果有多個,ELSE_IF應當有很多,語法上沒有上限,可以寫到程序存儲器不夠了為止 *)
tasks;
ELSE_IF conditions THEN
tasks;
...
ELSE (* 如果沒有默認操作,ELSE可以省略,也可以不省略 *)
tasks;
END_IF;(* 這個地方破天荒地有一個分號 *)
3.2 狀態分支CASE-OF 1: … 2: … 3: … n: … ELSE … END_CASE;
這種分支結構是專門用于狀態變量的,需要使用數字作為狀態變量,但代碼中不一定要按大小順序排版,也不一定要連續。未顯式定義的數字會轉接到ELSE段中。做一個演示用的紅綠燈,有紅亮(Y0)、黃亮(Y1)、綠亮(Y2)三種狀態,用一個按鈕X0來控制。這個程序并不十分適合這一場景,只是做為介紹語法之用,具體工程中只需要5~6行代碼就搞定了。
IF LDP(TRUE, X0) THEN
D0 := D0 + 1;(* 狀態變量如果無止境地加上去會怎么樣?事實上不會,因為在CASE里有做限制 *)
END_IF;
CASE D0 OF
0:(* 狀態0的時候Y0通。不一定要換行,只是為了寫注釋方便我在冒號后面直接換行了*)
Y0 := TRUE;
Y1 := FALSE;
Y2 := FALSE;
1:(* 狀態1時Y1通 *)
Y0 := FALSE;
Y1 := TRUE;
Y2 := FALSE;
2:(* 狀態2時Y2通*)
Y0 := FALSE;
Y1 := FALSE;
Y2 := TRUE;
ELSE(* 其它狀態時,跳到狀態0 *)
D0 := 0;
END_CASE;
與C語言家族不同,結構化文本不需要break,它不會從一個狀態直接就執行到下一個狀態。case語句的結構很簡單,開頭CASE和OF中間只能寫一個數值變量,后面是常量標簽加個冒號,一個ELSE代表未定義的數值,最后以END_CASE;結尾,注意那個分號。簡化的寫法,通過條件判斷來賦值:
IF LDP(TRUE, X0) THEN
D0 := (D0 + 1) MOD 3;
END_IF;
Y0 := D0 = 0;
Y1 := D0 = 1;
Y2 := D0 = 2;
還有依次傳遞狀態 (不推薦)
IF LDP(TRUE, X0) THEN
Y2 := Y1;
Y1 := Y0;
END_IF;
Y0 := NOT (Y1 OR Y2);
個人比較推薦6行寫法,比較正規,5行寫法太作了,可讀性不好。目前看來CASE語句好像沒什么用。事實上CASE語句是IF語句的定制化版本,適合范圍更窄,但能少寫一些代碼。接下來的設計模式中如果條件允許,用CASE會有更好的可讀性,因為不重要的部分(標簽數字)不會太顯眼。
3.3 循環
FOR temp := 起始值 TO 完成值 BY 增量 DO
業務代碼
END_FOR;
while x0 then
y0 := 1;
end_while;
REPEAT
D0 := D0 + 1;
UNTIL D0 == 0 END_REPEAT;
3.4 跳轉指令
- EXIT
提前終止當前循環,進入尾部的代碼,相當于C的 break。
- CONTINUE
提前跳過本次循環,進入首部的代碼,與C的continue類似。但三菱GX Works2中沒有這個關鍵字。
- RETURN
返回,相當于X86匯編的RET指令,RETURN是無操作數指令。ST的函數返回值直接函數名接受值。三菱FX3U的函數是一次性的,建議不要將自定義函數用于FX3U。造成三菱FX3U函數為一次性的原因是FX3U沒有動態棧。能夠函數復用的X86軟件的編譯器會給每一個CALL指令前面加上硬件壓棧指令PUSH,在RET之后會加上硬件彈棧指令POP。硬件棧是由CPU直接操作的連續內存空間,不是軟件模擬的數據結構。它需要CPU內置有棧指針寄存器。而FX3U的PLC程序是虛擬的處理器,沒有設計棧指針的功能。雖然可以用軟件棧代替,但他們也沒有這么做。這就導致了所有CALL命令都綁定在一塊固定的寄存器上,無法嵌套。而且寄存器綁定函數后就會導致數據耦合,產生難以預料的后果。
三菱FX3U的功能塊可以產生多個實例,每一個實例綁定獨立的寄存器,就可以安全地做到代碼復用。對于純計算,即沒有狀態存儲功能的函數和功能塊,可以放心地復用,對于有狀態存儲功能的功能塊需要創建多個實例。所有支持梯形圖的PLC都難以實現動態棧,因為動態棧和梯形圖的程序理念是相背離的,動態棧希望程序盡可能使用動態變量,而梯形圖依賴于靜態變量。動與靜的矛盾之下,PLC設計者必須進行取舍。FX3U的內存量是足夠動靜共存的,問題在于動態棧很難兼容梯形圖,而梯形圖才是PLC的主要賣點。
- JMP
跳轉到指定標簽位置,和X86指令同名,可以用于代碼混淆,不建議手寫。但三菱GX Works2中沒有這個關鍵字。不確定是不是我的資料的問題。三菱Q系列有JMP指令(比FX系列可以節省一個LD M8000,其實沒什么很大的意義),但不能作為ST的函數或關鍵字。
-
plc
+關注
關注
5016文章
13388瀏覽量
465427 -
設計模式
+關注
關注
0文章
53瀏覽量
8655 -
csdn
+關注
關注
2文章
17瀏覽量
6862
發布評論請先 登錄
相關推薦
評論