許多 PLC 程式設計師都有 Arduino 的使用經驗。
許多 PLC 程式設計師的電子程式設計之旅始於微控制器課程。你的第一個程式很可能是經典的「Hello World」或讓連接到 Arduino 的 LED 燈閃爍。這些技能為看似毫不相關的程式設計環境(包括可程式邏輯控制器(PLC))奠定了良好的基礎。
我們將利用現有的知識,從 Arduino 的 map() 函數入手,逐步過渡到類似的基於梯形圖邏輯 (LL) 的 map 函數。在 PLC 內部,此 map 函數將以使用者自訂功能區塊(UDFB)的形式實作。我們的討論以常用的施耐德電機 Modicon PLC 為例。雖然本教學也適用於大多數基於梯形圖邏輯程式設計的 PLC,但具體的實作細節會有所不同。
該應用的測試平台如圖 1 所示。圖中可以看到 Schneider Electric 的 TM221CE24T Modicon PLC 驅動 Banner K50 Pro 觸控按鈕。
圖 1:Schneider Electric Modicon PLC 驅動 Banner K50 Pro 觸控按鈕。
將 Arduino 技能應用於 PLC
在深入探討 PLC 實作之前,我們先從 Arduino 的角度來探索三個基本概念。這包括:
- 函數組成部分的回顧
- 點表示法的概念
- map() 函數的數學原理
回顧這些 C 語言程式設計概念後,您會發現這些基礎知識可以直接應用於基於 Modicon 的 UDFB。您或許會認同,LLC 和 C 語言比您原先想像的更接近。將來,您可能會發現這種更廣闊的視角為使用結構化文字進行 PLC 程式設計奠定了完美的基礎。
函數的組成部分
回想一下,函數的作用是封裝一組 C 語句。也許你曾經寫過一個 Arduino 函數,讓 LED 閃爍 N 次。回想一下,這個函數可能有一個名稱,例如 blinkLED。它可能包含一些參數,例如 N,用於指定 LED 閃爍的次數。你可能也傳遞了其他參數,例如 LED 的亮燈時間和滅燈時間。你甚至可能還對 I/O 引腳進行了參數化。
void LEDblink(int pin, int N, long msOnTime, long msOffTime) {
pinMode(pin, OUTPUT);
for (int i = 0; i < N; i++) {
digitalWrite(pin, HIGH);
delay(msOnTime);
digitalWrite(pin, LOW);
delay(msOffTime);
}
}
技術提示:雖然 C 函數只能有一個傳回類型,但我們可以使用間接定址來擴展其傳回值的數量。對於間接定址,我們將數組或結構體的位址傳遞給函數。這樣,函數就可以存取數組或結構體中的所有元素。元素的總數受限於所用微控制器的記憶體和架構。
結構體和點號表示法
在學習 PLC 之前,我們應該先了解 C 語言程式設計中使用的點號表示法。請看以下程式碼:
typedef struct { // Structure definition
float minVoltage;
float maxVoltage;
float deviation;
} Status;
Status CellStatus; // instance of the structure
請注意,最後一行程式碼建立了一個 Status 結構體的實例。此結構體包含 minVoltage、maxVoltage 和 deviation 三個欄位。要存取結構體中的各個字段,我們使用點號表示法。例如:
CellStatus.minVoltage = 13.8;
float maxVoltage = CellStatus.maxVoltage;
在每種情況下,我們都可以看到結構名稱後面跟著一個點,再後跟感興趣的領域。
Arduino map() 函數
在討論 PLC UDFB 之前,我們還有最後一個概念要探討。具體來說,我們將從 Arduino 的角度來探討 map 函數的數學運算,然後再將其應用到 PLC 中。
Arduino map() 函數是代數運算在直線方程式的應用:
y = mx + b (斜截式)
y – y_1 = m(x – x_1) (點斜式方程)
在 Arduino 中,您可能會使用 map() 函數來縮放來自 Arduino 類比數位轉換器(ADC)的類比輸入。
int rawADCval = analogRead(0);
int HumanReadableVoltage = map(rawADCval, 0, 1023, 0, 5); //Assume a 5 VDC ADC reference
簡單來說,這意味著 ADC 輸出 0 到 1023 映射到 0 到 5V 直流電壓。然而,這裡存在著一個很大的問題,因為電壓值只允許為 0、1、2、3、4 和 5。這是整數資料型別的限制,我們將暫時使用浮點數型別來解決這個問題。
map() 函數本身的定義如下:
long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
仔細檢查 map() 函數可知,它實作了點斜式方程式:
y \ – y_1 = m(x\ – x_1)
程式中
m = \dfrac{out\_max - out\_min} {in\_max - in\_min}
產生
y = \dfrac{out\_max - out\_min}{in\_max - in\_min} (x - in\_min) + out\_min;
修改 Arduino map 函數以支援浮點運算
我個人更傾向於編寫一個使用浮點資料類型的函數。這可以透過更改函數的資料類型輕鬆實現,如下所示。這個小小的改動就解決了先前提到的整數運算問題。
float fmap(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
float rawADCval = analogRead(0);
int HumanReadableVoltage = fmap(rawADCval, 0.0, 1023.0, 0.0, 5.0);
Modicon 使用者自訂功能區塊 (UDFB) 簡介
至此,我們回顧了與映射(縮放)功能相關的基本程式設計概念,包括:
- 函數的組成部分
- 函數組件的名稱
- 結構體
- 資料類型的限制
- 點表示法
- 點斜式方程
現在,我們可以為 Modicon PLC 建立一個基於梯形圖邏輯的 UDFB。 UDFB 如圖 2 所示。 UDFB 的定義包含兩個部分。圖 2 的下半部顯示了 UDFB 名稱、布林輸入和參數。圖 2 的上半部顯示了梯形圖邏輯。
圖 2:Modicon FMAP 使用者自訂功能塊。
致能 (EN) 和致能輸出 (ENO) 用於將 UDFB 掛載到梯級上。
顯而易見,所有梯形圖邏輯元件都「掛載」在梯級上,如圖 3 中 FMAP UDFB 的梯級 #2 實例所示。這項重要操作在圖 2 的下半部中定義。這裡我們看到了致能 (EN) 和致能輸出 (ENO) 對。在圖 2 的梯級中,我們可以看到 ENO 是 EN 訊號的副本。換句話說,如果 EN 訊號存在,則該模組的 ENO 訊號將為真。將來,這允許我們將多個這樣的區塊放置在同一梯級上,每個下游區塊都會接收到致能訊號的副本。
技術提示:UDFB 有幾種不同的「懸掛」輸入輸出對。
此範例為傳統的 EN/ENO 對。此區塊僅在致能時才會工作,且 ENO 是 EN 訊號的直接副本。
電平敏感對包含一個 EN 訊號和一個 VALID 訊號。此區塊僅在致能時才會運作。當 UDFB 完成指定操作時,VALID 訊號將會被置位。方向控制值 (DCV) 就是一個很好的例子。UDFB 在接收 EN 訊號後會發出訊號使 DCV 翻轉。當被監控的汽缸移動到正確位置後,VALID 訊號會在稍後置位。通常也會包含一個 BUSY 輸出訊號。
邊緣敏感 UDFB 包含一個觸發 (TRIG) 和一個 DONE 訊號對。接收到 TRIG 輸入後,UDFB 將執行其指派的任務。任務完成後,UDFB 將向 DONE 輸出發送脈衝訊號。與電平感應式使用者自訂回饋觸發器 (UDFB) 類似,邊緣感應式使用者自訂回饋觸發器 (UFDB) 也具有 BUSY 輸出訊號。此外,它通常還具有 ABORT 或 RESET 輸入,用於撤銷觸發操作。例如,考慮像“西蒙說”這樣的遊戲。可以使用邊緣感應式 UDFB 進行電腦回放。遊戲結束後,可以觸發另一個邊緣感應式 UDFB 進行用戶回放。
這個傳統 UDFB 的運作是基於EN訊號。
EN 訊號用於致能各種 UDFB 數學運算。如圖2所示,每個梯級的起始端都連接著 EN 觸點。簡單來說,UDFB 的輸出只有在 EN 訊號致能時才會更新。這可能會讓人感到困惑,因為存在一種隱式記憶機制,即當 EN 訊號缺失時,UDFB 會保持上次的輸出值。如果傳統 UDFB 沒有更新,首先要檢查的就是這個機制。
技術提示:傳統 UDFB 的隱式記憶機制可能是個有益的特性。它允許週期性脈衝瞬時更新 UDFB 的輸出。例如,在製程控制器中使用的 UDFB 可以透過每秒脈衝(PPS)訊號來更新並保持其輸出值。
UDFB 參數
圖 2 展示了與 UDFB 相關的參數。「參數」一詞可以粗略地理解為與 UDFB 關聯的記憶體結構。這一點很重要,原因如下:
-
對於所有非布林類型的 UDFB 輸出,參數類型既是輸入也是輸出。在本例中,我們使用浮點類型進行所有直線方程式的計算。
-
如圖 4 所示,可以透過點號表示法存取「參數」。
-
當 UDFB 被實例化時,每個實例都會關聯一個記憶體。在底層,這類似於本文前面提到的「Status CellStatus;」結構。此操作也解釋了為什麼每個 UDFB 都有自己的參數和內部變數。
UDFB 數學運算
圖 2 的第 1 和第 2 行展示了我們在本文前面探討的 FMAP 函數的 UDFB 實作。請注意,我們使用了兩個操作數的數學運算。例如,增量輸出 (D_OUT) 是 OUT_MAX 和 OUT_MIN 之差。同樣,D_IN = IN_MAX – IN_MIN。斜率 (M) 的計算公式為 D_OUT / D_IN。其餘運算繼續執行斜截式方程,求解給定 X 輸入下的 Y 值。
如何實例化 UDFB
我們首先介紹了 Arduino。具體來說,我們研究了直線方程式、函數的各個部分和點符號。至此,我們已經成功地將函數與 UDFB 進行了比較。我們也看到了 C 函數和 UDFB 機制之間的相似之處,並且理解 UDFB 隨意使用參數一詞來描述輸入和輸出。最後,我們暗示每個 UDFB 實例化都與其自己的類似結構的記憶體物件相關聯。我們現在準備實例化 UDFB 並使用點表示法。
FMAP UDFB 的實際掛在梯級實例化如圖 3 梯級 2 所示。梯級 #0 和 #1 上顯示的操作區塊支援 UDFB。例如。梯級 #1 上的第一個區塊將常數值 0.0 載入到 %FMAP0.IN_MIN 記憶體位置。您將認識到用於存取與實例化 UDFB 關聯的成員(變數)的點運算子。
考慮到這種表示法和記憶體結構,我們可以有把握地說 Schneider 的機器編程(Machine Expert)處理 UDFB 的方式與 C++ 處理物件的方式相同。兩種程式語言都執行封裝。
在這個例子中,UDFB 的用途是什麼?
UDFB 的全部用途是將 Modicon PLC 的類比數位轉換器 (ADC) 值轉換為人類可讀取的值。在圖 3 的第 0 行,我們看到 ADC 的原始值為 533。回想一下,Modicon ADC 配置為提供 0 到 10 VDC 的滿量程,對應 0 到 1000 的值。在第 3 行,我們看到 UDFB 右側緊鄰一個運算區塊。請注意,該值已縮放為浮點值 5.33。
誠然,這個 UDFB 範例的設計有些過度。的確,可以使用一個簡單的除以 10 的運算區塊。但是,假設電壓代表物理系統壓力,例如 1 到 7VDC 對應 30 到 90psi。在這種情況下,我們應該使用兩個 FMAP UDFB。第一個 UDFB 應該將訊號轉換為人類可讀的格式。第二個區塊可以將這個易於理解的浮點值對應到對應的壓力值(psi)。這種雙區塊結構最大限度地提高了後續技術人員的閱讀體驗。例如,技術人員可以使用電壓表讀取 PLC 面板上的實際電壓值,然後查看 PLC 程式碼中對應的數值。
技術提示:許多 PLC 程式設計環境都支援功能塊(UDF)和使用者自訂功能塊(UDFB)。它們基本上相似,差別在於封裝方式。每個 UDFB 實例都有自己的記憶體結構,而功能塊則沒有。例如,如果使用功能塊,就無法實現前面提到的設定並記住功能。
圖 3:FMAP UFDB 掛載在第 2 層。比例參數使用點號表示法載入到第 1 層。此外,原始 ADC 值也載入到第 1 層。
技術提示:實現 UDFB 時務必格外謹慎。請始終牢記,PLC 的生命週期以數十年計。多年後,即使最初的程式設計師早已不在人世,技術人員和工程師仍需對程式碼進行故障排除和修改。清晰的文件和單一用途是 UDFB 的必備屬性。換句話說,程式設計要以清晰為先。切勿耍小聰明!
結論
使用者自訂功能塊 (UDFB) 相當於 PLC 中的 “C” 函數。兩者都提供了一種封裝常用程式碼的方法,從而形成相對易於閱讀的分層程式碼結構。這種結構抽象化了底層程式碼,使程式設計師和未來的工業技術人員能夠輕鬆地理解程式流程。這兩種軟體結構都允許程式設計師從其庫中選擇功能強大且經過全面調試的軟體,從而節省大量時間。
繼續探索更多工業控制系統資訊
如果您覺得本次討論對您有幫助,您可能還想了解以下內容:
DigiKey 導航
- 完整目錄:工業控制與自動化
- 特色硬體:: https://www.se.com/us/en/product/TMH2GDB/graphic-display-modicon-m221-unit-240-x-160pixels/


