使用LabVIEW進行順序控制

使用LabVIEW進行順序控制

在LabVIEW的環境下,程式設計人員只要利用內建的Sequence Structure,就可以很輕易的達到順序控制的目的,圖1.1就是利用Stacked Sequence Structure進行順序控制的範例。

話雖如此,但畢竟對於複雜的順序控制架構而言還是有些許限制。例如:執行到某一個程序時,需要跳過(Skip)某個程序、當程序發生錯誤時,希望直接進行程式中斷(Break)或希望再執行一次上一個步驟…等情況時,這些都是Stacked Sequence Structure沒法做到的,因為Stacked Sequence Structure會從第一個Frame執行到最後一個Frame。

![|279x411](upload://i9mE0jktUIb6fmutOq2o5pgBn89.png)

圖1.1 Stacked Sequence Structure的順序控制架構

在圖1.1程序執行的過程中程序是由0到1再到2依序進行,程式沒辦法跳過單一程序而執行下一個程序,例如:由0到2;也沒辦法回到上一個步驟,如由1到0或由2到1,這樣也就沒有辦法做到所謂重複結構、循序結構或選擇結構的順序控制,對於整個順序控制架構的規劃上,就會受到較多的限制。

為了讓整個順序控制的規劃更富有變化及彈性,規劃出一套適合這樣多變架構的規劃方式─State Machine。

何謂State Machine

State Machine總括而言只是一個程式設計人員在開發軟體時的一個架構,這個架構並不是只在LabVIEW環境下才有,在其他程式語言裡也可以利用這樣的架構做為程式開發的基礎。

這個架構的形成,可以讓程式有順序的循環執行程式步驟,可以跳過(Skip)某個程序,可以執行某個指定的程序,更可以在執行完某個程序後進行中斷(Break)…。

而且在流程的規劃上比較趨近於流程圖(Data-Flow Chart)的概念,簡單的說,設計人員只要規劃好程序流程圖,就等於完成絕大部分的工作,而剩下的工作只要把流程圖上的程序一一排入程式裡。除此之外,還可以將重複結構、循序結構及選擇結構的設計概念加入在其中,甚至還可以做出GOTO的效果。

如何規劃State Machine流程

在開始進行程式規劃前,首先必須要進行的莫過於流程圖的規劃。

你可以依據所要開發的動作流程及程序,先規劃出類似於圖1.2的程序架構。就如同上一節所說的〝規劃好程序流程圖,就等於完成絕大部分的工作〞

圖1.2中將整個程式架構區分為幾個主要的程序:Initialize、Standby、Run、Error及Exit。

![|248x248](upload://kNA5Grkb6hyPaSDsMmqvHAnCuS8.jpeg)

圖1.2 程序架構

每個程序單獨看起來,都可以視為單一的程序。程序與程序間也會因為這中間的關聯性或是呼叫條件的變化而改變結果,例如:Standby程序中,按下Start按鈕時,程式會進入Run程序執行程式或按下Stop按鈕時,則程式停止或離開。因為選擇結果的不同,會去呼叫不一樣的程序,這樣的架構也就是所謂選擇結構或是類似於GOTO功能。

State Machine的執行程序

完成程序架構的規劃後,接下來要做的就是將這樣的架構及流程實現在程式裡。

圖1.3a到圖1.3d就是將一連串的程序架構利用State Machine架構來完成的,每個Case Structure裡面,似乎都有這相同的元件,如Select、Bundle By Name…等,基本上已經把整個程式給單純化,看上去是不是簡單許多。

在以State Machine為主的控制架構中,程式是如何執行的呢?

以圖1.3a 為例,在程式一開始執行時,程式依據Cluster的資料流向及Step_Enum的參數項目(Item)執行Initial程序。執行結果如果發生異常(Error)時,Step_Enum的Item參數則經由Select元件,變更執行Error程序。反之,若無異常發生時,則執行Standby程序。

![|600x160](upload://b72VC47WArKgrKnemUyv5F1vdBI.png)

圖1.3a Initial程序

選擇結構中的另一個類型的選擇結構在圖1.3b 中就可以很明顯的看出來,在Standby 的Case程序裡分別有Start及Exit二個Boolean Button,在操作上可以知道當使用者按下Start Button時,則會進入Run的程序裡執行程序。當按下Exit Button時,則會離開整個程式。在未按下任何按鈕時(Start與Exit皆為False),Step_Enum參數不會有任何改變,會一直在Standby程序中等待。

![|491x164](upload://8XTGqV42W95Q1u6BKqpGqh47GuS.png)

圖1.3b Standby程序

圖1.3c則是當Run程序執行完後,如未發生異常,則重複回到Standby程序,等待下一次的執行。利用這樣的方式,程式一直不斷的循序執行,直到程序發生異常或Exit按鈕被觸發。

![|491x164](upload://fUisTBlKLZcDyJm96vdwJ2DqMdv.png)

圖1.3c Run程序

![|491x163](upload://gkgb5p7sXjc7LHiZTAycn4jD0MN.png)

圖1.3d Error程序

當程式的某一個程序發生異常時,都會進入Error程序並執行,顯示錯誤訊息在螢幕上,藉著這樣的方式統一處理異常訊息。

當然,設計人員也可以自行定義錯誤代碼(Error Code)、錯誤訊息(Error Message)或顯示訊息的方式。這些在未來的自訂錯誤訊息文章中將會有詳細介紹。

這樣一連串討論下來,說穿了State Machine的架構,最多就是利用Case Structure來做為整個架構的核心,再配合Select的選擇元件所完成的。當然,你也可以利用其他方式來作為選擇指定程序的方法。

它的優點在於,設計人員可以依據不同的程式程序,將開發或測試完成的SubVi加入在程序(Case Structure)裡,也可以很輕易的增加或減少Step_Enum中的程序,讓整個看似複雜的程式系統,有條不紊的呈現,這樣對於往後在進行程式維護時,將有所益助。

另外,在Parameter In 圖1.4部分,設計人員可以利用先前介紹過的型別定義Type Definition的方法來建立Parameter In元件,這樣當你在改變程序步驟或增加元件時,能縮短設計人員的開發時間,增加程式在開發時的彈性。

![|206x230](upload://djmmXJ0jxIbVCWCC4W6198Ovwrg.png)

圖1.4 Parameter In參數

建構State Machine

在這一節中,我們依據圖1.2的程序架構圖,一步一步的建構整個程式流程。

步驟一:

在整個程式的運作上,參(變)數佔了很重要的部分,所以在程序的一開始,就必須規劃整個程式所需要的參(變)數。依據程序架構圖所示,規劃出幾個必須的參(變)數:

  1. 控制程序步驟的參(變)數─Step_Enum。

  2. 停止整個While Loop的Boolean參(變)數─Exit。

  3. 異常訊息的參(變)數─Error。

步驟二:

依步驟一規劃的參(變)數,首先建構Enum件裡的Item,這裡設計人員可以依照程序步驟增加所需要的項目(Item) 圖1.5。

![|478x285](upload://5REu0VOjPdPIRN3D711OFH6Fh3s.png)

圖1.5 建立Step_Enum的Item

建立完成Step_Enum後,將Step_Enum元件定義成Type Definition元件,這樣做是為了增加往後如果要增加或刪除程序時的方便性。

![|402x242](upload://neAzkQFUoI1ckQt8mTK17gQxELR.png)

圖1.6 將參(變)數Cluster叢集起來

接下來把Step_Enum、Exit及Error利用Cluster叢集起來 圖1.6,為了往後參(變)數管理上的方便,也可以把Cluster元件定義成Type Definition元件。

步驟三:

建立While Loop及Case Structure,並在While Loop上建立位移暫存器(Shift Register),以便於Cluster傳遞參(變)數。

在讀取Cluster參數上可以利用Unbundle或Unbundle by Name元件 圖1.7。

![|390x290](upload://sTfawRxXKvUALXWB4nSuG88tZWg.png)

圖1.7 Unbundle及Unbundle by name元件

在將Unbundle的參數一一完成接線 圖1.8。

![|612x209](upload://f9viYwvTvXqeBU14BGEwTG4GmNr.png)

圖1.7 Unbundle及Unbundle by name元件

在Case Structure完成與Step_Enum的接線後,發現Selector Label上只出現〝Initial,Default〞及〝Standby〞二個程序 圖1.8。

![|477x111](upload://84h763gOYzllM0J1UhAEHtWRwV.png)

圖1.8 Case Structure的Selector Label選項

為了把所有選項顯示出來,可以在Selector Label上,按滑鼠右鍵選擇〝Add Case for Every Value〞圖1.9。

![|291x329](upload://jz1U48bu48CxhE4JEKm2DlcsvPp.png)

圖1.9 Add Case for Every Value選項

![|608x237](upload://176DiiD6LP4GukoIrJ3yAZwXiVD.png)

圖1.10 執行後的Selector Label選項

完成後,可以看出來已將所有Step_Enum裡的選項全部顯示出來 圖1.10。

步驟四:

在每個Case Structure程序裡,除了讀取資料外,還必須在Case程序完成時改變位移暫存器裡的Cluster參數。這時候,就必須運用Bundle或Bundle By Name元件 圖1.11。與Unbundle或Unbundle By Name不ㄧ樣的是,前者是寫入參數後者是讀取參數。

![|289x308](upload://aTUeYGQwbetczbP9CjbvPrHQ13j.png)

圖1.11 Bundle與Bundle By Name元件

在Bundle元件上的Input cluster位置上給予指定的Input,也就是將左邊的位移暫存器的Cluster直接接到Input cluster接點上 圖1.12。

![|600x143](upload://v7S0Gn56m6yyFwFMYxcuxKOGZbL.png)

圖1.12 將Cluster接到Bundle的Input Cluster接點上

完成指定的Input cluster後,在Bundle的參數項目上就會與左邊的Unbundle的參數項目相同 圖1.13。

![|468x158](upload://lX5drKhwY76DUgzFLSdv9w72sAu.png)

圖1.13 Bundle與Unbundle的參數項目相同

在每個Case程序裡,都依照步驟四的方式建立Bundle來改變你所需要改變的參數。這樣,基本上這樣就已經完成State Machine的大致架構,接下來的工作就只剩,如何把SubVi排入Case Structure裡、如何改變呼叫程序或是進行條件判斷了 圖1.14。

![|607x241](upload://i48Q6cHFJDDwq5ASxavUmhthEe4.png)

圖1.14 建構Case裡的程序及呼叫條件

結論

這裡所討論的只是其中一種程式架構,並不是非得要使用這樣的架構才能達到順序控制的目的。

State Machine架構,雖然可以很容易的將複雜的程序變得簡單,相對的也會把簡單的控制程序變得複雜。所以,在進行程式規劃前最好先衡量一下,需要使用何種架構來進行程式開發。