2.6 定義輸入訊號


一個電子訊號可以解譯出 4 個有意義訊號:0 訊號(off)、1 訊號(on)、上升緣訊號(rising edge 0→1)和下降緣訊號(falling edge 1→0),如下圖所示。



1 訊號0 訊號可用在偵測外部輔助裝置有訊號無訊號,例如:冷却水打開偵測、潤滑油位準安全檢測。不過我們卻無法使用此電子訊號來偵測按鍵及雙向計數器,這樣會造成誤動作。


說明如下:因為 PLC 每 4 ms 進行一次 I/O 交換,假設控制吹氣幫浦的往復式按鍵為雙態觸變(Toggle)模式,假設按一次按鍵的時間約 20 ms,那麼經過 I/O 交換則會連續偵測到 1 訊號四次(誤以為按了四次按鍵),所以 PLC 也就會因此處理這個按鍵訊號四次,造成錯誤的結果。



以下以吹氣幫浦的程式做說明:

#define kiAirPump (plc.gdi[0].bit.bit02) //吹氣幫浦的按鍵輸入訊號

#define oAirPump (plc.gdo[0].bit.bit01)  //吹氣幫浦控制輸出訊號,若輸出為 1,吹氣幫浦打開 ;

                                                                                              // 若輸出為 0,則不開啟。                          

if(kiAirPump){

 oAirPump = !oAirPump;

}


oAirPump 程序處理結果:1(on)→0(off)→1(on)→0(off),這是錯誤的結果。


在這個應用中,吹氣幫浦只要處理一次就可以,所以如果改成只計算此訊號的上升緣,那麼就將只會處理 1 次。請參照下面的程式範例:

#define kiAirPump (riseGdi[0].bit.bit02) //吹氣幫浦的按鍵輸入訊號之上升緣

#define oAirPump (plc.gdo[0].bit.bit01)  //吹氣幫浦控制輸出訊號,若輸出為 1,吹氣幫浦打開 ;

                                                                                               //若輸出為 0,則不開啟。                              

if(kiAirPump){

 oAirPump = !oAirPump;

}


oAirPump 程序處理結果:1(on),即按一次按鍵吹氣幫浦只執行一次。



單方向計數器可以使用上升或下降緣計算輸入訊號,才不會有誤動作,如下圖:



雙方向計數器則有以下兩者使用方法,可以得到正確訊號。


若一開始的訊號為 0,使用下降緣計算才不會因正反轉時誤判而少計數一次。



若一開始的訊號為 1,使用上升緣計算才不會因正反轉時誤判而少計數一次。



為了取得上升緣及下降緣訊號,需要比對現在的輸入狀態和前一次的輸入狀態。



為了達到比對的目的,需要宣告和 I/O 有同樣資料型態和運算空間,所以需要宣告 oldGDIriseGDIfallGDI 來儲存前一次的輸入訊號狀態及其上升緣或下降緣。



範例:

InPortGdi oldGdi0, oldGdi1, oldGdi2, oldGdi3, oldMpi0, oldMpi1, oldMpi2;

//用來儲存上一次的輸入訊號狀態

InPortGdi riseGdi0, riseGdi1, riseGdi2, riseGdi3, riseMpi0, riseMpi1, riseMpi2;

//用來儲存這一次的輸入訊號之上升緣

InportGdi fallGdi2; //用來儲存上一次的輸入訊號之下降緣

//Start of plcRun function

riseGdi0.iPort = (~oldGdi0.iPort) & plc.gdi[0].iPort;  //gdi0 的上升緣

riseGdi1.iPort = (~oldGdi1.iPort) & plc.gdi[1].iPort;  //gdi1 的上升緣

riseGdi2.iPort = (~oldGdi2.iPort) & plc.gdi[2].iPort;  //gdi2 的上升緣

riseGdi3.iPort = (~oldGdi3.iPort) & plc.gdi[3].iPort;  //gdi3 的上升緣

riseMpi0.iPort = (~oldMpi0.iPort) & plc.mpi[0].iPort;  //mpi0 的上升緣

riseMpi1.iPort = (~oldMpi1.iPort) & plc.mpi[1].iPort;  //mpi1 的上升緣

riseMpi2.iPort = (~oldMpi2.iPort) & plc.mpi[2].iPort;  //mpi2 的上升緣

fallGdi2.iPort = (oldGdi2.iPort) & (~plc.gdi[2].iPort; //gdi2 的下降緣


//plcRun 結束時會儲存輸入訊號的狀態

oldGdi0.iPort = plc.gdi[0].iPort; //save gdi0 as pass state

oldGdi1.iPort = plc.gdi[1].iPort; //save gdi1 as pass state

oldGdi2.iPort = plc.gdi[2].iPort; //save gdi2 as pass state

oldGdi3.iPort = plc.gdi[3].iPort; //save gdi3 as pass state

oldMpi0.iPort = plc.mpi[0].iPort; //save mpi0 as pass state

oldMpi1.iPort = plc.mpi[1].iPort; //save mpi1 as pass state

oldMpi2.iPort = plc.mpi[2].iPort; //save mpi2 as pass state