Labview程序設(shè)計(jì)模式_第1頁(yè)
Labview程序設(shè)計(jì)模式_第2頁(yè)
Labview程序設(shè)計(jì)模式_第3頁(yè)
Labview程序設(shè)計(jì)模式_第4頁(yè)
Labview程序設(shè)計(jì)模式_第5頁(yè)
已閱讀5頁(yè),還剩16頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、LabVIEW程序設(shè)計(jì)模式,這個(gè)相對(duì)學(xué)術(shù)化的詞語(yǔ)是對(duì)一系列用于LabVIEW程序設(shè)計(jì)結(jié)構(gòu)的歸納和總結(jié)。在建造房子時(shí),需要針對(duì)房子的用途設(shè)計(jì)整個(gè)房屋的架構(gòu),確保房子在這個(gè)架構(gòu)上的堅(jiān)固性和可建造性。寫程序時(shí)同樣如此,不同的應(yīng)用需要使用不同的程序設(shè)計(jì)結(jié)構(gòu)。例如我們?cè)贚abVIEW中構(gòu)建一個(gè)用戶界面型程序時(shí),往往首先在背面板中加入一個(gè)大的while循環(huán)以使程序持續(xù)運(yùn)行。如果需要響應(yīng)用戶界面事件則還需要加入一個(gè)Event事件結(jié)構(gòu)。那么我們是否曾經(jīng)考慮過(guò)以下的這些問(wèn)題:(1)     應(yīng)用中是否存在并行響應(yīng)的情況?如在持續(xù)的數(shù)據(jù)采集過(guò)程中,是否需要同時(shí)響應(yīng)

2、單擊菜單的事件?(2)     底層獲取的數(shù)據(jù)如何與上層的數(shù)據(jù)顯示部分進(jìn)行數(shù)據(jù)交互?(3)     上層的界面如何受底層程序的控制?(4)     同一個(gè)循環(huán)中采用哪種方式進(jìn)行數(shù)據(jù)交換?是局域變量、全局變量、共享變量還是移位寄存器?(5)     程序是否具有可擴(kuò)展性?(6)     如果程序運(yùn)行過(guò)程中,發(fā)生系統(tǒng)錯(cuò)誤或者硬件通訊錯(cuò)誤,是否會(huì)停止運(yùn)行

3、?待錯(cuò)誤排除后是否會(huì)繼續(xù)運(yùn)行?(7)     如何組織程序中的核心數(shù)據(jù)結(jié)構(gòu)?是否需要采用面向?qū)ο蟪绦蛟O(shè)計(jì)?(8)     如何記錄測(cè)試數(shù)據(jù)并生成報(bào)表?如何保存用戶配置參數(shù)?(9)     如何處理程序運(yùn)行中的斷電情況?重新啟動(dòng)時(shí)的繼續(xù)運(yùn)行?數(shù)據(jù)的最低丟失?(10) 如何實(shí)現(xiàn)運(yùn)行過(guò)程的采樣觸發(fā)和多點(diǎn)采樣的同步?當(dāng)然,也許只是使用LabVIEW臨時(shí)地調(diào)試或開(kāi)發(fā)某個(gè)小的應(yīng)用,無(wú)需考慮上述的問(wèn)題。但是,如果使用LabVIEW開(kāi)發(fā)一個(gè)典型應(yīng)用的程

4、序卻無(wú)法回避這些問(wèn)題。因此,有必要對(duì)各種程序開(kāi)發(fā)的應(yīng)用進(jìn)行歸納和總結(jié),提取它們對(duì)應(yīng)的LabVIEW程序結(jié)構(gòu)中的共性。此外,針對(duì)這些共性研究哪種結(jié)構(gòu)更加適合于應(yīng)用。這些結(jié)論綜合起來(lái)就形成了程序設(shè)計(jì)的模式。對(duì)于初學(xué)者而言,理解和掌握程序設(shè)計(jì)模式往往能起到事半功倍的效果;而對(duì)高級(jí)用戶而言,歸納各種程序設(shè)計(jì)模式又能夠不斷完善程序中遇到的問(wèn)題,并衍生一套符合特定應(yīng)用的特有的程序設(shè)計(jì)模式。狀態(tài)機(jī)是一種最為經(jīng)典的程序設(shè)計(jì)模式,在LabVIEW 7.1(含)之前它幾乎統(tǒng)治了大部分的LabVIEW主程序。最基本的狀態(tài)機(jī)結(jié)構(gòu)如圖 1所示。狀態(tài)是狀態(tài)機(jī)運(yùn)行的經(jīng)脈,在開(kāi)始使用狀態(tài)機(jī)模式撰寫程序時(shí)需要將應(yīng)用分

5、為若干個(gè)狀態(tài)。下面以圖中的應(yīng)用為例說(shuō)明基本狀態(tài)機(jī)的使用?!緫?yīng)用1】前面板具有3個(gè)按鈕(Control)和1個(gè)波形顯示控件Chart(Indicator),功能分別是:1)        開(kāi)始采集:Label是start,單擊后開(kāi)始進(jìn)行模擬數(shù)據(jù)采集程序(這里使用隨機(jī)數(shù)代替)。2)        關(guān)于:Label是dialog,單擊后彈出對(duì)話框以說(shuō)明這個(gè)程序的版權(quán)、幫助等信息。3)     

6、   停止:Label是stop,單擊后停止程序的運(yùn)行。4)        Chart:用于顯示獲取的隨機(jī)數(shù)。這是一個(gè)非常簡(jiǎn)單的應(yīng)用,但是具有一定的代表性。根據(jù)要求,該應(yīng)用至少包含以下5種狀態(tài)結(jié)構(gòu)。1)        Initial:初始化狀態(tài);2)        Idle:空閑狀態(tài),用于響應(yīng)各種用戶界面操作;3) &

7、#160;      acquire:采集狀態(tài),用于持續(xù)模擬采集數(shù)據(jù);4)        about:用于彈出關(guān)于和幫助對(duì)話框;5)        stop:停止?fàn)顟B(tài),退出循環(huán)并中止程序。(a)    背面板(b)    前面板圖 1 基本的狀態(tài)機(jī)結(jié)構(gòu)背面板仔細(xì)分析圖中的基本狀態(tài)

8、機(jī),可以看出狀態(tài)始終貫穿整個(gè)應(yīng)用程序,并由移位寄存器進(jìn)行值的寄存和傳遞。當(dāng)前狀態(tài)分支的結(jié)果將決定下一個(gè)狀態(tài),如圖中的Idle狀態(tài)。在這個(gè)狀態(tài)中,程序?qū)⒆詣?dòng)檢測(cè)前面板的三個(gè)按鈕是否被按下。如果start被按下,則進(jìn)入acquire狀態(tài);如果dialog被按下,則進(jìn)入about狀態(tài);如果stop被按下,則進(jìn)入stop狀態(tài);否則如果沒(méi)有任何按鈕被按下,則仍然進(jìn)入當(dāng)前的Idle狀態(tài)繼續(xù)檢測(cè)。在acquire狀態(tài)中,為了保證程序的重復(fù)采集使得下一個(gè)狀態(tài)仍然為acquire,但是這樣會(huì)導(dǎo)致程序無(wú)法停止(中斷采集)。于是需要在acquire狀態(tài)分支中加入stop的探測(cè),如果stop被按下,則不再進(jìn)入acqu

9、ire狀態(tài)而直接進(jìn)入stop狀態(tài)。從應(yīng)用1可以看出,基本狀態(tài)機(jī)模式大體上能夠滿足主程序結(jié)構(gòu)的需要。該模式能夠很好地使得應(yīng)用程序的各個(gè)功能以狀態(tài)的方式有順序地執(zhí)行,并且保證了程序的可讀性(以狀態(tài)圖的方式顯示清晰明了)和擴(kuò)展性(日后只需要擴(kuò)展?fàn)顟B(tài)即可擴(kuò)展相應(yīng)的功能)。事例中使用的是“string”型結(jié)構(gòu)來(lái)標(biāo)記狀態(tài),事實(shí)上也可以使用其它的數(shù)據(jù)類型替換,如ring、numeric或enum。從嚴(yán)格意義而言,ring并不屬于一種數(shù)據(jù)類型,它只是一種特殊的numeric性,其性質(zhì)與numeric基本上一樣。盡管ring與enum控件從外觀上看是一樣的,如圖 2所示,但是它們實(shí)質(zhì)上是不同的。主要體

10、現(xiàn)為以下7點(diǎn):針對(duì)基本狀態(tài)機(jī)模式的第(13)個(gè)問(wèn)題,需要對(duì)模式進(jìn)行改進(jìn)。本節(jié)將一一分析這些問(wèn)題對(duì)應(yīng)的解決方案,并最終形成一種新的狀態(tài)機(jī)模式消息隊(duì)列型狀態(tài)機(jī)模式。(1)     狀態(tài)的分類不清晰。這是一個(gè)涉及各個(gè)狀態(tài)分類管理的問(wèn)題,是一個(gè)組織問(wèn)題。我們可以做一個(gè)類比,在一個(gè)書(shū)桌上有許多種類的書(shū)籍(通信、計(jì)算機(jī)、機(jī)械、法律等),這些書(shū)都擺放在書(shū)桌上很整齊。但是我們?cè)趯ふ乙槐緯?shū)時(shí)并不會(huì)覺(jué)得很迅速和隨意,因?yàn)闀?shū)籍的擺放是無(wú)序的,每次尋找書(shū)籍我們不得不從第一本開(kāi)始瀏覽直至找到我們想要的書(shū)籍?;蛟S可以做一些改變,我們?cè)O(shè)置一些書(shū)立,將不同種類的書(shū)使用書(shū)立分開(kāi)

11、。并且在書(shū)立上標(biāo)明這些書(shū)籍表示的種類。這樣我們?cè)趯ふ夷骋环N書(shū)籍時(shí)就不需要從第一本書(shū)開(kāi)始尋找了,只需要找到對(duì)應(yīng)的書(shū)立,在這些書(shū)立中尋找即可。讓我們回到程序,并給程序的狀態(tài)設(shè)置一些“書(shū)立”。如圖 4所示,系統(tǒng)共有9個(gè)有效狀態(tài)(UI Initial、Data Initial、Instr Initial、Temperature、Power、FFT、JTFA、Data Clean、Exit)。如果把這些狀態(tài)混在一起,我們需要找到某一個(gè)狀態(tài)時(shí)會(huì)比較困惑和麻煩。如同上面所述,將這些狀態(tài)分為4類并設(shè)置了4個(gè)“書(shū)立”(Initial、Acquire、Analyse、System)分隔這些狀態(tài)。在實(shí)際的

12、狀態(tài)控制中,需要確保程序只會(huì)進(jìn)入實(shí)際的狀態(tài)中運(yùn)行而不會(huì)進(jìn)入到“書(shū)立”分支中,因此對(duì)每個(gè)“書(shū)立”加入了“-”以示區(qū)別。圖 4 狀態(tài)分類盡管我們只是進(jìn)行了少量的修改,但是這的確有利于程序狀態(tài)的組織和閱讀,尤其是當(dāng)程序具有很多個(gè)狀態(tài)的時(shí)候。(2)     缺乏數(shù)據(jù)共享和錯(cuò)誤處理機(jī)制。在層疊式的順序結(jié)構(gòu)中,數(shù)據(jù)在幀之間的傳遞是靠“順序局域變量”實(shí)現(xiàn)的。那么如果在case結(jié)構(gòu)中如何傳遞不同分支的數(shù)據(jù)呢?這個(gè)問(wèn)題似乎很容易解決,使用局域變量,全局變量或共享變量都能夠解決,但是這些并不是最優(yōu)的解決方案。因?yàn)樯鲜龅姆绞綍?huì)明顯系統(tǒng)運(yùn)行的內(nèi)存空

13、間和時(shí)間。由于狀態(tài)機(jī)的基本組成元素除了case結(jié)構(gòu)之外還有循環(huán),因此可以使用移位寄存器來(lái)傳遞數(shù)據(jù)。如圖 5所示。圖 5 狀態(tài)機(jī)中的數(shù)據(jù)傳遞圖 5使用移位寄存器進(jìn)行數(shù)據(jù)共享和傳遞,將所有的數(shù)據(jù)封裝在一個(gè)簇中并對(duì)每個(gè)數(shù)據(jù)命名,這樣在使用數(shù)據(jù)時(shí)就可以使用“Unbundle by name”或“bundle by name”。需要說(shuō)明的是,即使使用一個(gè)數(shù)據(jù)需要共享,仍然希望采用簇的封裝形式,這樣當(dāng)后續(xù)需要增加擴(kuò)展數(shù)據(jù)的時(shí)候并不會(huì)影響現(xiàn)有的數(shù)據(jù)引用。(3)     每一個(gè)狀態(tài)分支只能夠決定后面的一個(gè)狀態(tài),而無(wú)法決定

14、一個(gè)狀態(tài)序列(多個(gè)狀態(tài))。在基本狀態(tài)機(jī)中之所以存在這個(gè)問(wèn)題是因?yàn)闋顟B(tài)的傳遞使用的是Scalar(標(biāo)量)形式,如果需要傳遞一個(gè)狀態(tài)序列,很明顯可以使用隊(duì)列或數(shù)組進(jìn)行狀態(tài)的傳遞。在LabVIEW程序設(shè)計(jì)模式中將這種具備處理狀態(tài)序列的狀態(tài)機(jī)稱為“消息隊(duì)列型狀態(tài)機(jī)”,它是在基本狀態(tài)機(jī)基礎(chǔ)上的改進(jìn)。顧名思義,這種模式就像銀行辦理業(yè)務(wù)時(shí)排隊(duì)一樣采用隊(duì)列的方式。當(dāng)儲(chǔ)戶進(jìn)入銀行時(shí),首先到叫號(hào)機(jī)處領(lǐng)取號(hào)碼進(jìn)行排隊(duì)(進(jìn)入隊(duì)列)并等待。然后,當(dāng)前面的儲(chǔ)戶辦理完業(yè)務(wù)后就可以到相應(yīng)的窗口辦理業(yè)務(wù)(退出隊(duì)列)。事實(shí)上,這種方式在現(xiàn)代生活中隨處可見(jiàn)。在LabVIEW中至少有兩種實(shí)現(xiàn)消息隊(duì)列的方法。如圖 6所示。前

15、者使用數(shù)組函數(shù)實(shí)現(xiàn)隊(duì)列元素的入列和出列;后者使用隊(duì)列函數(shù)實(shí)現(xiàn)隊(duì)列元素的入列和出列。二者都能夠?qū)崿F(xiàn)隊(duì)列的有序操作和狀態(tài)的序列變化。圖 6 消息隊(duì)列型狀態(tài)機(jī)模式本節(jié)解決了基本狀態(tài)機(jī)模式中的(1)(3)個(gè)問(wèn)題,為了更好地比較和使用這些特點(diǎn),特使用一個(gè)實(shí)例說(shuō)明消息隊(duì)列型狀態(tài)機(jī)的使用過(guò)程?!緫?yīng)用2】本例要模擬一個(gè)自動(dòng)販賣機(jī)的工作過(guò)程。它的一次正常交易過(guò)程為:投幣選擇需要購(gòu)買的商品找?guī)?,?dāng)幣值不足或商品已經(jīng)銷售完畢時(shí)則無(wú)法購(gòu)買。程序的前面板如圖 7所示。在販賣機(jī)的左上側(cè)有4個(gè)按鈕。(1)     1USD:?jiǎn)螕魰r(shí)表示投入1美元

16、的貨幣,2USD和5USD類同;(2)     Change Back:表示找零,也就是將目前剩余的貨幣退還給用戶。程序的右側(cè)是5個(gè)按鈕,表示5種不同類別的可樂(lè)(這里均使用了可口可樂(lè)的圖標(biāo)),每種可樂(lè)的價(jià)格均是1美元??蓸?lè)的下面數(shù)字表示販賣機(jī)中剩余的該商品的數(shù)量,初始為每種20瓶。Current money顯示販賣機(jī)中剩余的貨幣數(shù),你可以繼續(xù)購(gòu)買可樂(lè)或者選擇退回。單擊Stop按鈕將退出應(yīng)用程序。本例將使用本節(jié)介紹的消息隊(duì)列狀態(tài)機(jī)模式解決這個(gè)應(yīng)用(也可以使用其它的設(shè)計(jì)模式)。系統(tǒng)的功能并不復(fù)雜,關(guān)鍵是要判斷販賣機(jī)中的剩余錢數(shù)和剩余的貨物數(shù)以決定交

17、易是否成功。圖 7 自動(dòng)販賣機(jī)前面板程序背面板如圖 8所示。系統(tǒng)分為5個(gè)狀態(tài),并分為2大類。(1)     第一類:Initiala)        UI Initial:前面板界面的初始化。b)        Data Initial:數(shù)據(jù)的初始化。(2)     第二類:Systema) 

18、60;      Idle(Default):空閑狀態(tài)。b)        CheckMoney:販賣機(jī)中的剩余錢數(shù)和剩余的貨物數(shù)以決定交易是否成功。c)        Exit:退出程序。程序開(kāi)始運(yùn)行時(shí)進(jìn)入U(xiǎn)I Initial和Data Initial狀態(tài),完成初始化操作。從圖中可以看出系統(tǒng)采用數(shù)組函數(shù)處理消息隊(duì)列。圖 8 自動(dòng)販賣機(jī)背面板在UI Init

19、ial中,系統(tǒng)給標(biāo)題欄和說(shuō)明欄賦值,并將前面板的商品設(shè)置為不可購(gòu)買狀態(tài),因?yàn)樵诔跏蓟瘯r(shí)還沒(méi)有完成投幣動(dòng)作。如圖 9所示。圖 9 UI Initial分支在Data Initial中包含兩個(gè)共享的數(shù)據(jù):Money和GState,前者表示販賣機(jī)中剩余的幣值,初始化值為0;而后者表示販賣機(jī)中各個(gè)商品剩余的數(shù)量,初始化值為20。數(shù)據(jù)使用移位寄存器傳遞以便于在各個(gè)case分支中共享和使用,如圖 10所示。圖 10 Data Initial分支CheckMoney分支主要是為了防止不合法的交易(如投入的幣值不足或商品數(shù)量不足),如圖 1

20、1所示。圖 11 CheckMoney分支當(dāng)程序運(yùn)行到Exit分支時(shí),將停止循環(huán)并退出程序,如圖 12所示。圖 12 Exit分支Idle分支用來(lái)監(jiān)控前面板各個(gè)按鈕控件的變化并執(zhí)行相應(yīng)的狀態(tài)。該分支比較復(fù)雜,當(dāng)檢測(cè)到第0個(gè)按鈕被按下時(shí)(即1USD按鈕),販賣機(jī)中的貨幣值應(yīng)該加一,同時(shí)需要判斷是否達(dá)到了交易條件(即進(jìn)入CheckMoney狀態(tài))。其它的狀態(tài)可以執(zhí)行相應(yīng)的代碼即可,這里不再重復(fù)解釋。圖 13 Idle分支從本例可以看出,相比基本狀態(tài)機(jī)而言,盡管程序的復(fù)雜度增加了,但是在構(gòu)建大型的應(yīng)用程序時(shí)也更加地健壯,代碼也易于

21、維護(hù)和查看。針對(duì)基本狀態(tài)機(jī)模式的第(45)個(gè)問(wèn)題,需要對(duì)模式進(jìn)行改進(jìn)。本節(jié)將一一分析這些問(wèn)題對(duì)應(yīng)的解決方案,并最終形成一種新的狀態(tài)機(jī)模式用戶界面事件模式。(1)     程序一直在占用CPU資源。(2)     無(wú)法響應(yīng)更多的前面板事件。熟悉LabVIEW的工程師應(yīng)該能夠很容易地解決這兩個(gè)問(wèn)題,在LabVIEW 7.0以后的版本中提供的事件結(jié)構(gòu)(Event Structure)能夠讓我們非常便捷地處理這兩類問(wèn)題。在LabVIEW中事件結(jié)構(gòu)的使用并不是一件難事,根據(jù)事件的發(fā)出源,事件可以抽象地分為

22、用戶界面事件和用戶自定義事件。相關(guān)的基本知識(shí)可以參考有關(guān)的書(shū)籍,這里不再闡述事件結(jié)構(gòu)的使用方法。圖 14所示的結(jié)構(gòu)稱為用戶界面事件模式,它能夠很便捷地響應(yīng)各種事件并且不占用CPU的資源,這是由LabVIEW中事件結(jié)構(gòu)本身的特性決定的。圖 14 用戶界面事件模式【應(yīng)用3】本例要模擬一個(gè)簡(jiǎn)單的畫圖板功能。它有4個(gè)功能選項(xiàng):點(diǎn)(point)、線(line)、圓(circle)和橢圓(oval),一次完成的繪畫過(guò)程是:在畫布上單擊鼠標(biāo)開(kāi)始繪制按住鼠標(biāo)的同時(shí)在畫布上拖動(dòng)鼠標(biāo)在畫布上放開(kāi)鼠標(biāo)結(jié)束繪制。程序的前面板如圖 15所示,由上下兩大部分組成。上面用于選擇需要畫

23、圖的樣式,下面是畫布,右上方的X表示程序的結(jié)束。圖 15 畫圖板前面板由于系統(tǒng)需要響應(yīng)鼠標(biāo)在畫布上單擊、移動(dòng)和釋放事件,因此使用狀態(tài)機(jī)模式是無(wú)法解決的,只能通過(guò)事件結(jié)構(gòu)。因此本例將使用用戶界面事件模式實(shí)現(xiàn)上述的畫圖板功能。程序的背面板如圖 16所示。共有4個(gè)事件。(1)     Panel Close?:響應(yīng)前面板的X動(dòng)作,這是一個(gè)過(guò)濾性事件,當(dāng)事件發(fā)生時(shí)并不真正關(guān)閉前面板而只是停止程序的運(yùn)行。(2)     Picture <Mouse Down>:表

24、示繪畫的開(kāi)始。(3)     Picture <Mouse Move>:表示繪畫的路徑和軌跡。(4)     Picture <Mouse Up> <Mouse Leave>:表示繪畫的結(jié)束,此時(shí)一定要加入<Mouse Leave>事件,因?yàn)楫?dāng)鼠標(biāo)移動(dòng)到畫布的外面時(shí)就可以認(rèn)為是繪畫結(jié)束了,并不需要一定要求鼠標(biāo)在畫布中釋放。圖 16 畫圖板背面板Picture <Mouse Down>事件如圖 17所示,這個(gè)

25、步驟表示繪制的開(kāi)始,每次的繪制都必須從這個(gè)步驟開(kāi)始。事件分支左側(cè)的Button參數(shù)表示單擊鼠標(biāo)的鍵位,只有在單擊鼠標(biāo)左鍵時(shí)才被認(rèn)為是合理的和有效的,當(dāng)單擊其它的鍵位時(shí)并不開(kāi)始繪制。在有效繪制中,需要將畫筆移動(dòng)到鼠標(biāo)當(dāng)前單擊的位置。當(dāng)選擇的畫圖模式是Line、和Point時(shí),使用Draw point.vi函數(shù)可以在當(dāng)前的位置上畫一個(gè)點(diǎn)并且將畫筆移動(dòng)到當(dāng)前位置。從圖中可以看出系統(tǒng)定義了4個(gè)移位寄存器變量以實(shí)現(xiàn)不同事件分支的共享,它們的含義如下:(1)     表示當(dāng)前畫布中的圖像,事實(shí)上就是前面板picture中的內(nèi)容。因?yàn)槊看萎媹D時(shí)都是在當(dāng)前畫布

26、上圖像進(jìn)行疊加,所以需要使用移位寄存器以避免過(guò)多地局域變量。(2)     表示開(kāi)始繪制時(shí)的鼠標(biāo)位置,也就是Mouse Down在畫布上的相對(duì)位置,繪制的起點(diǎn)。(3)     表示是否開(kāi)始了繪制。前面提過(guò)每次的繪制過(guò)程都是從Mouse Down開(kāi)始的,如果沒(méi)有這個(gè)動(dòng)作,那么在鼠標(biāo)在畫布上的移動(dòng)是無(wú)效的。(4)     表示開(kāi)始繪制時(shí)的圖像,這個(gè)變量與(1)是不一樣的。它表示在Mouse Down時(shí)畫布上的圖像,而不是畫布中的實(shí)時(shí)圖像。圖 

27、;17 Picture <Mouse Down>事件Picture <Mouse Move>事件如圖 18所示,該事件是繪圖的過(guò)程中,因此移位寄存器(3)的值必須是true??梢愿鶕?jù)不同的畫圖類型使用相應(yīng)的函數(shù)進(jìn)行繪圖,如畫Line時(shí),只需要把當(dāng)前鼠標(biāo)的位置作為L(zhǎng)ine的終點(diǎn)。圖 18 Picture <Mouse Move>事件Picture <Mouse Up> <Mouse Leave>事件如圖 19所示,該事件表示繪制的結(jié)束,因此只需要把移位寄存器(3)的值設(shè)置為false即可

28、。圖 19 Picture <Mouse Up> <Mouse Leave>事件本例的實(shí)現(xiàn)過(guò)程并不復(fù)雜,但是涉及到了4個(gè)移位寄存器變量。一旦變量共享的數(shù)據(jù)較多時(shí)往往需要使用大量的移位寄存器,因?yàn)榻ㄗh使用cluster的形式將各個(gè)變量有序地組織起來(lái)上兩節(jié)分別解決了基本狀態(tài)機(jī)的第(15)個(gè)問(wèn)題,但是是否具備一種模式能夠綜合隊(duì)列型狀態(tài)機(jī)模式和用戶界面事件型模式的優(yōu)點(diǎn)呢?這樣可以同時(shí)避免基本狀態(tài)機(jī)的第(15)個(gè)問(wèn)題。答案是肯定的,本節(jié)將介紹如何將狀態(tài)機(jī)與事件結(jié)構(gòu)結(jié)合起來(lái)形成一種新的、穩(wěn)定的模式。狀態(tài)機(jī)模式的基本構(gòu)成元素是while循環(huán)和case結(jié)構(gòu),而事件結(jié)

29、構(gòu)模式的基本構(gòu)成元素是while循環(huán)和event結(jié)構(gòu),因此新的模式應(yīng)該由while循環(huán)、case結(jié)構(gòu)和event結(jié)構(gòu)組成。而while循環(huán)的目的是為了保證程序的持續(xù)運(yùn)行,因此必須在最外層,這樣就只剩下了圖 20所示的兩種組合方式。在第一種方式中,每次循環(huán)的運(yùn)行需要經(jīng)過(guò)一個(gè)事件結(jié)構(gòu)才能夠?qū)崿F(xiàn)case中各個(gè)分支的運(yùn)行,那么到底需要多少個(gè)分支呢?一般而言不同的事件都會(huì)有不同的事件處理函數(shù)(這些函數(shù)可以在case結(jié)構(gòu)中共用),顯示這是無(wú)法滿足要求的,它從本質(zhì)上而言仍然是一種事件結(jié)構(gòu)。在第二種方式中,程序的主體是一個(gè)狀態(tài)機(jī)結(jié)構(gòu),不同的是在某一個(gè)狀態(tài)分子中有一個(gè)事件結(jié)構(gòu)。我們可以回憶狀態(tài)機(jī)模式中

30、的“空閑Idle”狀態(tài),這正是長(zhǎng)時(shí)間占用CPU資源的源頭,如果在Idle中加入一個(gè)事件結(jié)構(gòu)后就有效地規(guī)避了這個(gè)問(wèn)題。圖 20 三種結(jié)構(gòu)的組合方式因此圖 20中的第二種結(jié)構(gòu)綜合了狀態(tài)機(jī)和事件結(jié)構(gòu)的優(yōu)點(diǎn),有效地克服了基本狀態(tài)機(jī)的第(15)個(gè)問(wèn)題。此外,在【應(yīng)用2_自動(dòng)販賣機(jī)】例程中,按鈕1USD、2USD和5USD的作用是相同的,唯一不同的是它們的代表的幣值不同。如果我們希望系統(tǒng)共用“幣值相加”這個(gè)功能,即當(dāng)這三個(gè)按鈕任何一個(gè)被按下后都調(diào)用同一個(gè)函數(shù)(該函數(shù)的功能是將系統(tǒng)中原來(lái)的貨幣值與新加入的幣值相加得到新的值)。這樣,需要有一種途徑把1USD、2USD和5USD代

31、表的幣值作為參數(shù)傳遞給函數(shù)。圖 21所示為帶參數(shù)的狀態(tài)機(jī)結(jié)構(gòu),在消息隊(duì)列的狀態(tài)機(jī)模式中,加入了一個(gè)變體型的變量作為狀態(tài)傳遞的參數(shù)。實(shí)際上,可以把紅色的部分做成子vi,不僅節(jié)省了背面板空間而且能夠進(jìn)行錯(cuò)誤處理。程序中應(yīng)該設(shè)置一個(gè)專門的錯(cuò)誤處理狀態(tài),當(dāng)任何一個(gè)狀態(tài)運(yùn)行后如果發(fā)生錯(cuò)誤將直接轉(zhuǎn)到錯(cuò)誤處理狀態(tài)。當(dāng)然,也可以在圖 21的基礎(chǔ)上做一些改進(jìn)和變形,假定參數(shù)的數(shù)據(jù)類型為string型,這樣就把Data參數(shù)和State合并起來(lái),中間使用特殊符號(hào)(如)隔開(kāi)。圖 21 帶參數(shù)的狀態(tài)機(jī)結(jié)構(gòu)【應(yīng)用4】本節(jié)的例程將使用Multicolumn Listbox控件處理2維

32、數(shù)組排序問(wèn)題,前面板如圖 22所示。該Listbox用于顯示系統(tǒng)中的各種采集數(shù)據(jù)值,分為5列。程序的功能是當(dāng)單擊Listbox的列頭時(shí),對(duì)數(shù)據(jù)以該列的升序/降序進(jìn)行排序。單擊Stop按鈕或×按鈕則停止程序運(yùn)行。圖 22 2D數(shù)組排序_前面板系統(tǒng)使用狀態(tài)機(jī)和事件結(jié)構(gòu)相結(jié)合的模式,如圖 23所示。程序分為8個(gè)狀態(tài),共有4類。各個(gè)狀態(tài)的功能與消息隊(duì)列型的狀態(tài)機(jī)模式類似,程序加入了錯(cuò)誤處理部分。在背面板的循環(huán)中共享同一個(gè)“錯(cuò)誤簇”結(jié)構(gòu)的移位寄存器,當(dāng)存在錯(cuò)誤時(shí)程序?qū)簳r(shí)停止運(yùn)行其它的狀態(tài)而優(yōu)先進(jìn)入錯(cuò)誤狀態(tài)(這里是Error分支)。圖 23&#

33、160;2D數(shù)組排序_背面板在Idle狀態(tài)中,事件結(jié)構(gòu)可以防止CPU資源的長(zhǎng)時(shí)間占用,也可以響應(yīng)各種前面板事件,如圖 24所示。圖 24 狀態(tài)機(jī)中的事件結(jié)構(gòu)本例中引入了4個(gè)變量以供不同的狀態(tài)分支調(diào)用,如圖 25所示。其中的意義如下所述。(1)     Index:當(dāng)前排序的列號(hào),表示Listbox以哪一列為依據(jù)進(jìn)行排序。(2)     ASC:表示當(dāng)前排序的方式,true表示升序,而false表示降序。(3)    

34、 Column Header:表示Listbox的列頭數(shù)據(jù)。(4)     Data:表示Listbox的內(nèi)容數(shù)據(jù)。圖 25 數(shù)據(jù)變量在圖 26中,事件結(jié)構(gòu)處理的是Listbox的<Mouse Up>事件,此時(shí)只需要對(duì)內(nèi)部的變量賦值即可,并且當(dāng)該單擊是有效單擊時(shí)進(jìn)入“DSort”狀態(tài)進(jìn)行排序操作。圖 26 排序事件在圖 27所示的DSort狀態(tài)中,根據(jù)內(nèi)部變量的值對(duì)Listbox賦值并更新列頭的顯示。圖 27 DSort狀態(tài)圖 27調(diào)

35、用了2D數(shù)組的排序函數(shù),該函數(shù)的實(shí)現(xiàn)過(guò)程如圖 28所示。LabVIEW并沒(méi)有提供2D數(shù)組的排序方式,只提供了1D數(shù)組的排序函數(shù)。本例充分利用了LabVIEW提供的排序函數(shù)功能,當(dāng)然并不是唯一的,也可以使用LabVIEW實(shí)現(xiàn)常用的排序算法。圖 28 2D數(shù)組排序簡(jiǎn)單而言,動(dòng)態(tài)調(diào)用指的是通過(guò)程序控制另外一個(gè)程序的運(yùn)行、停止、賦值和獲取值等。LabVIEW提供了多種動(dòng)態(tài)調(diào)用的方式,從底層而言是通過(guò)VI Server技術(shù)實(shí)現(xiàn)的。圖 31所示為L(zhǎng)abVIEW中的Application Control選板,動(dòng)態(tài)調(diào)用所使用的節(jié)點(diǎn)都位于這個(gè)選板。當(dāng)調(diào)用一個(gè)在硬盤、內(nèi)存甚

36、至是網(wǎng)絡(luò)路徑上的vi時(shí),首先要使用Open VI Reference以將該VI載入內(nèi)存并獲取VI的“句柄(Reference)”;然后再使用該句柄進(jìn)行其它的控制操作;最后再關(guān)閉該VI的句柄避免內(nèi)存泄漏,這就完成了一次對(duì)VI的調(diào)用。圖 31 Application Control選板圖 32是一個(gè)動(dòng)態(tài)調(diào)用的具體實(shí)現(xiàn)代碼,首先使用Open VI Reference獲取被動(dòng)態(tài)調(diào)用VI的Reference(例子中是C:average.vi);再使用Call By Reference Node節(jié)電動(dòng)態(tài)運(yùn)行該VI;最后關(guān)閉VI的Reference。在使用Call By Ref

37、erence Node時(shí)需要事先指定被調(diào)用VI的輸入輸出接口,也就是說(shuō)這種動(dòng)態(tài)調(diào)用的前提是必須知道被調(diào)用VI的輸入輸出接口,否則無(wú)法進(jìn)行動(dòng)態(tài)調(diào)用。圖 32 VI的動(dòng)態(tài)調(diào)用Open VI Reference的路徑輸入是一個(gè)多態(tài)的輸入口,也可以使用String輸入,如圖 33所示。此時(shí)被調(diào)用的VI必須在內(nèi)存中,且輸入的是被調(diào)用VI的文件名。值得一提的是這種“文件名”調(diào)用方式在可執(zhí)行程序中是無(wú)法被調(diào)用的,因此建議最好采用路徑的調(diào)用方式。圖 33 Open VI Reference的多態(tài)性【應(yīng)用5】本例將使用LabVIEW的動(dòng)態(tài)調(diào)用方式實(shí)現(xiàn)斐波那契數(shù)列

38、(Fibonacci數(shù)列)。斐波那契數(shù)列指的是這樣一個(gè)數(shù)列:1,1,2,3,5,8,13,21 這個(gè)數(shù)列從第三項(xiàng)開(kāi)始,每一項(xiàng)都等于前兩項(xiàng)之和。在數(shù)學(xué)上表述為:f(n)=f(n-1)+f(n-2),其中n>=3,f(1)=f(2)=1。顯然這是一個(gè)比較熟悉的遞歸調(diào)用,但是在LabVIEW中似乎很難實(shí)現(xiàn)。由于LabVIEW不允許同名的VI同時(shí)在內(nèi)存中,因此一個(gè)VI是無(wú)法VI調(diào)用本身的。但是,通過(guò)VI的可重入技術(shù)和動(dòng)態(tài)調(diào)用技術(shù)卻可以實(shí)現(xiàn)VI的遞歸調(diào)用。圖 34所示為Fibonacci數(shù)列在LabVIEW中遞歸的實(shí)現(xiàn)方式。case結(jié)構(gòu)有兩個(gè)分支,當(dāng)n<=2時(shí)直接輸出f(

39、n)=1;當(dāng)n>=3時(shí),輸出f(n)=f(n-1)+f(n-2)。此時(shí)需要把VI設(shè)置為可重入狀態(tài)。圖 34 Fibonacci數(shù)列同理我們也可以使用這種遞歸的方式實(shí)現(xiàn)f(n)=n!的算法,從數(shù)學(xué)上可以寫作f(n)=n*f(n-1),其中n>=1,f(0)=1。具體的實(shí)例將不再詳述。此外,遞歸算法的效率比較低,在實(shí)際應(yīng)用中應(yīng)謹(jǐn)慎使用。打開(kāi)Highlight工具,在Call By Reference Node運(yùn)行時(shí),程序是處于等待狀態(tài)的,只有被調(diào)用的VI運(yùn)行完畢,主程序才會(huì)繼續(xù)執(zhí)行。這似乎無(wú)法解決在本節(jié)開(kāi)頭提到的問(wèn)題,那么是否存在一種動(dòng)態(tài)調(diào)用方式使被調(diào)用的VI與主V

40、I之間分別獨(dú)立運(yùn)行呢?答案是肯定的。VI本身是有很多的屬性和方法的,如圖 35所示。使用這些方法就可以動(dòng)態(tài)控制VI的運(yùn)行、停止和賦值,各個(gè)屬性節(jié)點(diǎn)和方法的具體含義見(jiàn)LabVIEW的幫助文檔。使用這種方式動(dòng)態(tài)調(diào)用VI時(shí),并不需要知道VI的輸入輸出接口。圖 35 VI Method圖 36是該使用“屬性節(jié)點(diǎn)和方法”實(shí)現(xiàn)動(dòng)態(tài)調(diào)用的一個(gè)實(shí)例。在大多數(shù)應(yīng)用程序啟動(dòng)時(shí)會(huì)顯示一個(gè)啟動(dòng)畫面用來(lái)顯示版權(quán)、開(kāi)發(fā)單位、軟件版本等信息,等待2秒之后關(guān)閉啟動(dòng)界面并啟動(dòng)應(yīng)用程序主界面。圖中使用了動(dòng)態(tài)調(diào)用的方式啟動(dòng)主程序(Main.vi)并使主程序獨(dú)立運(yùn)行,首先運(yùn)行程序后設(shè)置2秒鐘的延時(shí);其次,將啟動(dòng)畫面的界面設(shè)置為“隱藏”(并沒(méi)有退出內(nèi)存,只是隱藏了前面板),并且使用Open VI Reference獲取VI的句柄;然后使用FP.Open屬性打開(kāi)主程序的前面板(只是打開(kāi)

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論