先分清兩種條件呼叫
子程式被條件分支跳過時,其中靠呼叫更新的狀態不會執行。本篇比較 A 只在 Enable 為真時呼叫,與 B 每掃描呼叫但由外層決定是否採用輸出。先用自訂邊緣模型追蹤前值,再決定停用期間要繼續取樣、凍結,還是恢復時重新同步。外部時鐘仍可能前進,因此不能把未呼叫等同所有計時都暫停。
以CODESYS R_TRIG作平台參考,功能塊需要在實際呼叫時取得CLK並更新記憶;官方文件不支持未呼叫時在背景執行的推論。若程式沒有呼叫實例,就不能期待捕捉每個掃描的輸入變化。
呼叫圖要標出每個條件分支與實例名稱,因為功能塊只在通過該分支時才有執行證據。監看時先看呼叫點,再看輸入與輸出,才能分辨是資料錯還是根本沒有進入。
本例的基礎模型固定為:每次呼叫先算 Pulse=CLK AND NOT Previous,再令 Previous=CLK;不呼叫時兩個欄位都保留。Previous 初值為 FALSE。它是教學用狀態模型,沒有 Reset 腳位;下文另加的同步與 Reset 都是自訂包裝層,不能當成標準 R_TRIG 的介面。
重新呼叫時若時間缺口過大,可回報TIME_GAP並重新建立前值。直接把長時間缺口當成一個普通掃描,會使事件時間線難以解釋。
下列表格逐列表示連續時間,必須沿用上一列的 Previous,只有換成另一條獨立測試才重新初始化。請依指定的時間與輸入序列逐列核對;偽碼須依目標 PLC 語法調整。
100ms時間線與前值更新
輸入在0、100、200、300、400ms為0、1、0、1、1。A在100、200ms跳過,B每100ms呼叫,兩實例起始Previous均為0。A的前值在跳過期間保持0,所以300ms重新呼叫時把CLK=1判成上升;B在100ms判斷、200ms更新成0、300ms才再次產生上升。
| 時間 ms | CLK | A 呼叫/前值前→後/Pulse | B 前值前→後/Pulse |
|---|---|---|---|
| 0 | 0 | 是/0→0/0 | 0→0/0 |
| 100 | 1 | 否/0→0/0 | 0→1/1 |
| 200 | 0 | 否/0→0/0 | 1→0/0 |
| 300 | 1 | 是/0→1/1 | 0→1/1 |
| 400 | 1 | 是/1→1/0 | 1→1/0 |
表中的 Pulse 是實例保存的輸出,不是已發送到下游的事件。本例 A 在跳過前恰好為 0,所以跳過時仍為 0;若先在 100 ms 呼叫得到 1,再於 200、300 ms 跳過,Pulse 便會保持 1。外層應以本次確實呼叫及允許採用等條件控制事件,不能每掃描見到保留的 1 就累加。
若子程式返回後輸出仍保留上一值,畫面上的Pulse可能長時間像真事件。若外層每掃描清零,又可能讓事件被清除後下游尚未讀到。輸出生命週期需要明確的單次事件契約。
若輸入在兩次呼叫間快速往返,兩種設計都可能漏掉事件;差別只在已呼叫的模組能否看到取樣點。要捕捉短脈衝,應查硬體或高速任務規格。
A和B交換呼叫順序後,獨立實例的結果應維持;若結果改變,查共享全域變數、診斷結構、輸出暫存或同一個功能塊實例。
時間表的呼叫前Previous、呼叫後Previous、Q與Enable都要記錄。若A只在300ms看到高電位,結果表達的是恢復時的判斷,不是證明輸入在300ms才上升。
啟用輸入不等於跳過實例
若停用期間仍要追蹤輸入,只是不讓事件往下游傳遞,可每掃描呼叫R_TRIG,再用Enable AND Q採用事件。Previous仍更新,恢復時不會把停用期間維持的高電位誤判成新事件。
若需求是凍結狀態,才跳過呼叫;恢復時要選接受高電位、先同步前值或回報狀態缺口,這不是R_TRIG自動決定的政策。
再做一條獨立測試:0 ms 的 CLK=0,100 ms 變成 1 後一直維持;Enable 在 100、200 ms 為 FALSE,300 ms 恢復。基礎 A 在 300 ms 得 Pulse=1,B 的原始 Pulse 在 100 ms 已出現,但當時被 Enable 抑制;300 ms 時 B 得 0。這個差異才是停用期間維持高電位的重點。
Reset和初始化不是同一件事。初始化可在第一次啟動建立前值,Reset則是運轉中的明確命令;兩者同掃描出現時的優先序必須寫在需求。
計時也要先選契約。例如在 0 ms 起算、期限 300 ms,100 與 200 ms 不呼叫:自訂絕對期限模型在 300 ms 恢復時,以 Now-Start>=300 判定到期;自訂有效取樣模型若缺口作廢,則先回 TIME_GAP,不直接宣布到期。兩種都可描述需求,但都不是對所有平台 TON 的保證。
每次恢復都要記錄是否採用新事件,並讓下游知道事件來自正常取樣還是恢復同步。這個欄位能避免維護人員把補判結果誤認成原始邊緣。
TON不能泛稱一定累加掃描或未呼叫一定停住。Q與ET須在實際呼叫語意下核對;無證據時用自訂狀態偽碼明寫每次呼叫才更新,不能冒充現成TON。
恢復 Reset與遺失事件
若輸入由0變1又回0,A完全未呼叫便無法知道事件;恢復時CLK=0,單一目前值不能還原短脈衝。這是取樣限制,需要另查硬體捕捉或高速任務。
若希望恢復的高電位不自動形成命令,可在基礎 A 外再加一個同步包裝層 A_sync。第一次恢復只令 Previous=CLK、Pulse=0;後續連續呼叫才使用邊緣公式。前面時間表仍是未包裝的 A,因此 300 ms 為 1;改用 A_sync,同一列必須改為 0。不要把兩個策略混成同一份驗收答案。
在100ms呼叫時,實際Now可能是97或114ms;時間表只是驗收框架。若控制器要求準確逾時,保存可信時間戳,不能由計數器名稱推定精度。
驗收證據至少包含呼叫條件、CLK、Previous前值、Previous後值、Q、輸出採用旗標和錯誤狀態。只截最後一個Q位元不足以重建事件。
若需每次事件只通知一次,事件採用後要由接收端或事件緩衝明確清除。讓Pulse一直保留,會把一個事件誤當成持續命令。
若選擇重新建立前值,第一筆恢復資料只作基準,不輸出事件;第二筆連續有效資料才恢復一般判斷。這是本案例的明確政策。
本例包裝層的 Reset 優先於一般判斷:當次令 Previous=CLK、Pulse=0,並清除缺口診斷;它不把 Previous 一律清成 0。若 CLK 持續為 1,解除 Reset 後仍不出新事件;必須先觀察到 0,再觀察到 1。失敗先查是否誤用清零策略、是否共用實例,以及呼叫是否真的發生。
驗收 FAQ與平台限制
完成後應能說明A為何300ms才判斷,B為何100與300ms各出一次。測試包括全程不呼叫、恢復CLK為0、恢復CLK為1、停用短脈衝和Reset同掃描;記錄呼叫次數、CLK、Previous、Q、Enable、Reset。
| 情境 | A策略 | B策略 | 重點 |
|---|---|---|---|
| 正常連續呼叫 | 依邊緣公式 | 依邊緣公式 | 前值逐列延續 |
| 跳過兩次 | 前值與輸出保留 | 仍取樣 | A 可能漏事件 |
| 停用但仍呼叫 | 已不屬於基礎 A | 外層 Enable 抑制 | B 前值仍更新 |
| A_sync 恢復且 CLK=1 | 同步前值,Pulse=0 | 前值已持續更新 | 區分基礎 A 與包裝層 |
FAQ:一、未呼叫R_TRIG會背景更新嗎?不能假定。二、每掃描呼叫但Enable為假與跳過相同嗎?不相同。三、TON未呼叫一定累加或停住嗎?不能泛稱,依官方文件與平台測試。四、恢復能補回漏掉短脈衝嗎?不能,未取樣資料已不存在。
適用限制:CODESYS Function Block、R_TRIG與TON文件作查閱來源;Q系列和其他PLC細節需依CPU核對。
停用期間仍呼叫的設計適合需要追蹤輸入的模組;跳過呼叫的設計適合刻意凍結狀態,但都要記錄停用起點、恢復時刻與是否允許補判。
若移植到另一個PLC,先查功能塊是否需要實例、時間型別的解析度、未呼叫時輸出是否保留、Reset命令及任務排程。不能以相同指令名稱推論相同語意。
本篇不涉及安全功能。任何與設備動作相關的輸出,都要經過獨立互鎖、模式和安全控制設計,不能由R_TRIG或TON的呼叫策略代替。
參考:CODESYS TON