labview中dll的調(diào)用(包括生成dll)
LabVIEW 中是通過(guò)Call Library Function Node(CLN)節(jié)點(diǎn)來(lái)完成DLL文件調(diào)用的。創(chuàng)建一個(gè)新的VI,右擊程序框圖,在Functions Palette中依次選中Connectivity——Libraries&Executables工具欄即可找到該節(jié)點(diǎn)(圖1)。
本文引用地址:http://m.butianyuan.cn/article/201701/337129.htm圖1 Call Library Function Node
將節(jié)點(diǎn)放置在程序框圖中,雙擊會(huì)出現(xiàn)它的配置對(duì)話框,共有四頁(yè)。第一頁(yè)用于填寫(xiě)被調(diào)用函數(shù)的信息(圖2)。Library name or path需給出DLL文件名和路徑,操作系統(tǒng)路徑下的DLL文件,直接輸入文件名也可調(diào)用,否則必須輸入全路徑。在這里已經(jīng)給出名字的DLL是被靜態(tài)加載到程序中的,也就是說(shuō)當(dāng)調(diào)用了這個(gè)DLL的VI被裝入內(nèi)存時(shí),DLL同時(shí)被裝入內(nèi)存。LabVIEW也可動(dòng)態(tài)加載DLL,只要勾選上Specify path on diagram的選項(xiàng)即可。選擇了這個(gè)選項(xiàng),在 Library name or path中輸入的內(nèi)容就無(wú)效了,取而代之的是CLN 節(jié)點(diǎn)多出一對(duì)輸入輸出,用于指明所需要使用的DLL的路徑。這樣,當(dāng)VI被打開(kāi)時(shí),DLL不會(huì)被裝入內(nèi)存,只用程序運(yùn)行到需要使用這個(gè)DLL中的函數(shù)時(shí),才把其裝入內(nèi)存。Function name是需要調(diào)用的函數(shù)的名稱,LabVIEW會(huì)把DLL中所有的暴露出來(lái)的函數(shù)都列出,用戶只要在下拉框中選取即可。Thread欄用于設(shè)定哪個(gè)線程里運(yùn)行被調(diào)用的函數(shù)。用戶可以通過(guò) CLN 節(jié)點(diǎn)的配置面板來(lái)指定被調(diào)用函數(shù)運(yùn)行所在的線程。CLN 的線程選項(xiàng)非常簡(jiǎn)單,只有兩項(xiàng): Run in UI thread和Run in any thread。LabVIEW的程序框圖上直接可以看出一個(gè) CLN節(jié)點(diǎn)是選用
圖2 填寫(xiě)被調(diào)用函數(shù)信息
的什么線程。如果Run in UI thread,節(jié)點(diǎn)顏色是橙色的;Run in any thread則是淺黃色的(圖3)。
圖3 CLN不同線程對(duì)比
通常情況下,除非使用的動(dòng)態(tài)鏈接庫(kù)是多線程安全的,CLN 中選擇Run in any thread方式;否則必須選擇Run in UI thread方式。判斷一個(gè)動(dòng)態(tài)鏈接庫(kù)是不是多線程安全的,需通過(guò)以下方法:如果一個(gè)動(dòng)態(tài)鏈接庫(kù)的文檔中沒(méi)有明確說(shuō)明它是多線程安全的,那么就要當(dāng)作是非多線程安全的;在可以看到動(dòng)態(tài)鏈接庫(kù)源代碼的條件下,如果代碼中存在全局變量、靜態(tài)變量或者代碼中看不到有l(wèi)ock一類的操作,那么這個(gè)動(dòng)態(tài)鏈接庫(kù)也就肯定不是多線程安全的。
選擇了Run in any thread方式,LabVIEW會(huì)在最方便的線程內(nèi)運(yùn)行動(dòng)態(tài)鏈接庫(kù)函數(shù),且一般會(huì)與調(diào)用它的VI在同一個(gè)線程內(nèi)運(yùn)行。因?yàn)長(zhǎng)abVIEW是自動(dòng)多線程的語(yǔ)言,它也很可能會(huì)把動(dòng)態(tài)鏈接庫(kù)函數(shù)分配給一個(gè)單獨(dú)的線程運(yùn)行。如果程序中存在沒(méi)有直接或間接先后關(guān)系的兩個(gè)CLN節(jié)點(diǎn),LabVIEW很可能會(huì)同時(shí)在不同的線程內(nèi)運(yùn)行它們所調(diào)用的函數(shù),也許是同一函數(shù)。對(duì)于非多線程安全的動(dòng)態(tài)鏈接庫(kù),這是很危險(xiǎn)的操作。很容易引起數(shù)據(jù)混亂,甚至是程序崩潰。
選擇Run in UI thread方式,因?yàn)長(zhǎng)abVIEW只有一個(gè)界面線程,所以如果所有的CLN設(shè)置都是界面線程,那么就可以保證這些CLN調(diào)用的函數(shù)肯定全部都運(yùn)行在同一線程下,肯定不會(huì)被同時(shí)調(diào)用。對(duì)于非多線程安全的動(dòng)態(tài)鏈接庫(kù),這種方式就保證了它的安全。
讓我們回到配置對(duì)話框第一頁(yè),Calling convention用于指明被調(diào)用函數(shù)的調(diào)用約定。這里只支持兩種約定:stdcall和C call。它們之間的區(qū)別在于,stdcall由被調(diào)用者負(fù)責(zé)清理堆棧,C call由調(diào)用者清理堆棧。這個(gè)設(shè)置錯(cuò)誤時(shí),可能會(huì)引起LabVIEW崩潰,也就是說(shuō)如果LabVIEW調(diào)用DLL函數(shù)時(shí)出現(xiàn)異常,首先應(yīng)該考慮這個(gè)設(shè)置是否正確。(Windows API一般使用的都是stdcall;標(biāo)準(zhǔn)C的庫(kù)函數(shù)大多使用C call。如果函數(shù)聲明中有類似__stdcall這樣的關(guān)鍵字,它就是stdcall的。)第二頁(yè)是函數(shù)參數(shù)的配置(圖4)。
圖4 配置函數(shù)的參數(shù)
DLL和LabVIEW之間傳遞參數(shù),最常用的三種數(shù)據(jù)類型是數(shù)值、數(shù)值型數(shù)組和字符串。C語(yǔ)言中經(jīng)常把指針或者數(shù)據(jù)的地址在函數(shù)間傳遞,在32位操作系統(tǒng)中,可以使用int32數(shù)值來(lái)表示指針。因此,當(dāng)需要在LabVIEW中傳遞指針數(shù)據(jù)時(shí),可以使用I32或U32數(shù)值類型來(lái)表示這個(gè)地址類型的數(shù)據(jù)。但是,64位的程序中,數(shù)據(jù)的地址只能使用I64或U64來(lái)表示。這樣,如果一個(gè)調(diào)用了DLL函數(shù)的VI,并且函數(shù)參數(shù)中有地址型數(shù)據(jù),使用固定數(shù)據(jù)類型的數(shù)值來(lái)表示地址,就要準(zhǔn)備兩份代碼。解決方法是使用LabVIEW中的新的數(shù)據(jù)類型Pointer-sized Integer。這個(gè)數(shù)據(jù)類型的長(zhǎng)度在不同的平臺(tái)上會(huì)自動(dòng)使用32位或64位長(zhǎng)度。如果在C語(yǔ)言函數(shù)參數(shù)聲明中有const關(guān)鍵字,可以選中Constant選項(xiàng)。布爾類型在DLL函數(shù)和LabVIEW VI之間傳遞沒(méi)有專有的數(shù)據(jù)類型,是利用數(shù)值類型來(lái)傳遞的。輸入時(shí)先把布爾值轉(zhuǎn)變?yōu)閿?shù)值,在傳遞給DLL函數(shù);輸出時(shí)再把數(shù)值轉(zhuǎn)為布爾值。對(duì)于數(shù)組的傳遞,LabVIEW只支持C數(shù)據(jù)類型中的數(shù)值型數(shù)組,傳遞數(shù)組類型需要注意的的是“Array Format”要選擇“Array Data Pointer”。這個(gè)設(shè)置中還有其他兩個(gè)選項(xiàng),帶有“Handle”的參數(shù)類型都是表示LabVIEW定義的特殊類型的。在第三方的DLL中不會(huì)使用到數(shù)組參數(shù)作為輸出值時(shí),要記得為輸出的數(shù)組數(shù)開(kāi)辟空間。開(kāi)辟數(shù)據(jù)空間的方法有兩種:第一種方法,創(chuàng)建一個(gè)長(zhǎng)度滿足要求的數(shù)組,作為初始值傳遞給參數(shù),輸出數(shù)的數(shù)據(jù)就會(huì)被放置在輸入數(shù)組的所在的內(nèi)存空間內(nèi)。第二種方法是直接在參數(shù)配置面板上進(jìn)行設(shè)置。在Minimum size中寫(xiě)入一個(gè)固定的數(shù)值,LabVIEW就會(huì)按此大小為輸出的數(shù)組開(kāi)辟空間。在 Minimum size 中選擇函數(shù)的其它數(shù)值參數(shù),而不是固定數(shù)值。這樣LabVIEW會(huì)按照當(dāng)時(shí)被選擇的參數(shù)值的大小來(lái)開(kāi)辟空間。字符串與使用與數(shù)組是非常類似的,實(shí)際上在C語(yǔ)言中字符串就是一個(gè)I8數(shù)組。
在NI軟件的安裝路徑下打開(kāi)當(dāng)前使用版本的LabVIEW文件夾,通過(guò) examplesdlldata passingCall NativeCode.llb找到簡(jiǎn)單數(shù)據(jù)類型在LabVIEW與C之間的對(duì)應(yīng)關(guān)系。部分常見(jiàn)關(guān)系見(jiàn)表1。
表1 數(shù)據(jù)類型對(duì)比
第三頁(yè)用于為DLL設(shè)置一些回調(diào)函數(shù),可以使用這些回調(diào)函數(shù)在特定的情形下完成初始化、清理資源等工作(圖5)。
圖5 設(shè)置回調(diào)函數(shù)
如果為Reserve選擇了一個(gè)回調(diào)函數(shù),那么當(dāng)一個(gè)新的線程開(kāi)始調(diào)用這個(gè)DLL時(shí),這個(gè)回調(diào)函數(shù)首先被調(diào)用??梢岳眠@個(gè)函數(shù)為新線程使用到的數(shù)據(jù)做初始化工作。線程在使用完這個(gè)DLL之后,它會(huì)去調(diào)用Unreserve中指定的回調(diào)函數(shù)。Abort中指定的函數(shù)用于VI非正常結(jié)束時(shí)被調(diào)用,也就是讓一個(gè)程序在運(yùn)行完前停止。這些回調(diào)函數(shù)的原型在Prototype for these procedures中列出,必須要由DLL的開(kāi)發(fā)者按照特定的格式實(shí)現(xiàn)。如果使用的DLL不是專為L(zhǎng)abVIEW設(shè)計(jì)的,一般不會(huì)包含這樣的回調(diào)函數(shù)。
第四頁(yè)是錯(cuò)誤處理方式,用戶可根據(jù)需要選擇相應(yīng)的錯(cuò)誤檢查級(jí)別。
另外還需要注意的是,C語(yǔ)言中的struct在LabVIEW中可以使用cluster來(lái)表示,但有時(shí)需要作出相應(yīng)的調(diào)整。這是因?yàn)樵贑語(yǔ)言中,struct的字節(jié)對(duì)齊是可以進(jìn)行設(shè)置的,這就決定了其各元素的存放地址的可變性。C語(yǔ)言中的對(duì)字節(jié)對(duì)齊數(shù)可通過(guò)#pragma pack指令或在工程屬性中進(jìn)行指定。而在LabVIEW的cluster中,所有元素只能是1字節(jié)對(duì)齊的,所以如果要和C語(yǔ)言中非1字節(jié)對(duì)齊的struct對(duì)應(yīng),需要做出一些調(diào)整。比如,對(duì)于C語(yǔ)言中2字節(jié)對(duì)齊的struct,第一個(gè)元素如果是I8型的,在LabVIEW的cluster中第一個(gè)元素對(duì)應(yīng)不變,但不能緊挨著放第二個(gè)元素,必須留一個(gè)無(wú)意義的空位。C語(yǔ)言的struct其實(shí)也是如此,只不過(guò)沒(méi)有表現(xiàn)出來(lái)。所以為了方便,如果自己用C語(yǔ)言生成DLL文件供LabVIEW調(diào)用最好將struct都設(shè)為1字節(jié)對(duì)齊。C語(yǔ)言的struct中可以嵌套數(shù)組,但是這和LabVIEW中含有數(shù)組元素的cluster是不一樣的,LabVIEW中需要將數(shù)組中的元素都拆開(kāi)放入cluster中。
如果C語(yǔ)言的struct中含有一個(gè)指針,LabVIEW中的cluster只能用一個(gè)U32數(shù)值(32位系統(tǒng)上,64位系統(tǒng)上使用U64)來(lái)表示指針的地址,而不能將指針?biāo)赶虻膬?nèi)容放到Cluster中去。如果聲明的是指向struct的指針,才能在LabVIEW中使用cluster與之對(duì)應(yīng)。CLN節(jié)點(diǎn)的配置面板中,沒(méi)有一個(gè)專門(mén)命名的“struct”或者“cluster”參數(shù)類型,應(yīng)選擇“Adapt to Type”就可以了。如果參數(shù)的類型就是結(jié)構(gòu)而非指針,考慮到C函數(shù)參數(shù)的壓棧順序,把一個(gè)結(jié)構(gòu)體作為參數(shù)傳給函數(shù),相當(dāng)于把結(jié)構(gòu)中每個(gè)元素分別作為參數(shù)傳遞給函數(shù)。圖6為C語(yǔ)言中struct和LabVIEW中cluster的部分匹配圖。
圖6 struct和cluster匹配
LabVIEW打包DLL文件
我們接下來(lái)學(xué)習(xí)如何使用LabVIEW來(lái)打包一個(gè)DLL文件。
首先我們編寫(xiě)一個(gè)名為Scale.vi的程序,功能很簡(jiǎn)單就是對(duì)輸入的數(shù)據(jù)乘上10,然后再輸出(圖7)。
圖7 scale.vi
必須在任務(wù)管理器中才能生成.dll文件。所以我們首先建立一個(gè)project,過(guò)程如下:
點(diǎn)擊File>>New Project:
圖8 生成新項(xiàng)目
接著彈出是否將該VI添加到新項(xiàng)目的對(duì)話框:
圖9 是否添加VI到新建項(xiàng)目
選擇Add,生成新的項(xiàng)目管理器,將其保存在需要的路徑下:
圖10 項(xiàng)目管理器
右鍵單擊項(xiàng)目瀏覽器窗口中的Build Specifications,在快捷菜單中選擇New>>Shared Library(DLL),彈出對(duì)DLL文件進(jìn)行設(shè)置的對(duì)話框。點(diǎn)擊Category>>Information,根據(jù)自己需求修改Build specification name和Target filename:
圖11 Information頁(yè)面
點(diǎn)擊Source Files>>Project Files>> Scale.vi>> ,彈出對(duì)話框,直接用默認(rèn)值,點(diǎn)擊OK:
圖12 Define VI Prototype
相關(guān)推薦
技術(shù)專區(qū)
- FPGA
- DSP
- MCU
- 示波器
- 步進(jìn)電機(jī)
- Zigbee
- LabVIEW
- Arduino
- RFID
- NFC
- STM32
- Protel
- GPS
- MSP430
- Multisim
- 濾波器
- CAN總線
- 開(kāi)關(guān)電源
- 單片機(jī)
- PCB
- USB
- ARM
- CPLD
- 連接器
- MEMS
- CMOS
- MIPS
- EMC
- EDA
- ROM
- 陀螺儀
- VHDL
- 比較器
- Verilog
- 穩(wěn)壓電源
- RAM
- AVR
- 傳感器
- 可控硅
- IGBT
- 嵌入式開(kāi)發(fā)
- 逆變器
- Quartus
- RS-232
- Cyclone
- 電位器
- 電機(jī)控制
- 藍(lán)牙
- PLC
- PWM
- 汽車(chē)電子
- 轉(zhuǎn)換器
- 電源管理
- 信號(hào)放大器
評(píng)論