1. 程式人生 > >LabVIEW如何方便地調用DLL文件

LabVIEW如何方便地調用DLL文件

采樣 動態鏈接 ans 路徑 view art left 寫入 初始

轉自:http://bbs.elecfans.com/jishu_469502_1_1.html LabVIEW調用DLL文件   LabVIEW支持通過調用DLL文件的方式與其它編程語言混合使用。比如,在實際的工程項目中,用戶可以用C++語言實現軟件的運算部分,並把這些功能構建在DLL文件中,然後再使用 LabVIEW編寫程序的界面部分,並通過調用編寫好的DLL來調用運算部分的功能。   LabVIEW 中是通過Call Library Function Node(CLN)節點來完成DLL文件調用的。創建一個新的VI,右擊程序框圖,在Functions Palette中依次選中Connectivity——Libraries&Executables工具欄即可找到該節點(圖1)。
<ignore_js_op>技術分享圖片

1.jpg (24.15 KB, 下載次數: 2)

下載附件 保存到相冊

2015-2-12 11:22 上傳

圖1 Call Library Function Node   將節點放置在程序框圖中,雙擊會出現它的配置對話框,共有四頁。第一頁用於填寫被調用函數的信息(圖2)。Library name or path需給出DLL文件名和路徑,操作系統路徑下的DLL文件,直接輸入文件名也可調用,否則必須輸入全路徑。在這裏已經給出名字的DLL是被靜態加載到程序中的,也就是說當調用了這個DLL的VI被裝入內存時,DLL同時被裝入內存。LabVIEW也可動態加載DLL,只要勾選上Specify path on diagram的選項即可。選擇了這個選項,在 Library name or path中輸入的內容就無效了,取而代之的是CLN 節點多出一對輸入輸出,用於指明所需要使用的DLL的路徑。這樣,當VI被打開時,DLL不會被裝入內存,只用程序運行到需要使用這個DLL中的函數時,才把其裝入內存。Function name是需要調用的函數的名稱,LabVIEW會把DLL中所有的暴露出來的函數都列出,用戶只要在下拉框中選取即可。Thread欄用於設定哪個線程裏運行被調用的函數。用戶可以通過 CLN 節點的配置面板來指定被調用函數運行所在的線程。CLN 的線程選項非常簡單,只有兩項: Run in UI thread和Run in any thread。LabVIEW的程序框圖上直接可以看出一個 CLN節點是選用
的什麽線程。如果Run in UI thread,節點顏色是橙色的;Run in any thread則是淺黃色的(圖3)。 <ignore_js_op>技術分享圖片

2.jpg (17.07 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:22 上傳

圖2 填寫被調用函數信息 <ignore_js_op>技術分享圖片

3.jpg (6.68 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:23 上傳

圖3 CLN不同線程對比   通常情況下,除非使用的動態鏈接庫是多線程安全的,CLN 中選擇Run in any thread方式;否則必須選擇Run in UI thread方式。判斷一個動態鏈接庫是不是多線程安全的,需通過以下方法:如果一個動態鏈接庫的文檔中沒有明確說明它是多線程安全的,那麽就要當作是非多線程安全的;在可以看到動態鏈接庫源代碼的條件下,如果代碼中存在全局變量、靜態變量或者代碼中看不到有lock一類的操作,那麽這個動態鏈接庫也就肯定不是多線程安全的。
  選擇了Run in any thread方式,LabVIEW會在最方便的線程內運行動態鏈接庫函數,且一般會與調用它的VI在同一個線程內運行。因為LabVIEW是自動多線程的語言,它也很可能會把動態鏈接庫函數分配給一個單獨的線程運行。如果程序中存在沒有直接或間接先後關系的兩個CLN節點,LabVIEW很可能會同時在不同的線程內運行它們所調用的函數,也許是同一函數。對於非多線程安全的動態鏈接庫,這是很危險的操作。很容易引起數據混亂,甚至是程序崩潰。   選擇Run in UI thread方式,因為LabVIEW只有一個界面線程,所以如果所有的CLN設置都是界面線程,那麽就可以保證這些CLN調用的函數肯定全部都運行在同一線程下,肯定不會被同時調用。對於非多線程安全的動態鏈接庫,這種方式就保證了它的安全。   讓我們回到配置對話框第一頁,Calling convention用於指明被調用函數的調用約定。這裏只支持兩種約定:stdcall和C call。它們之間的區別在於,stdcall由被調用者負責清理堆棧,C call由調用者清理堆棧。這個設置錯誤時,可能會引起LabVIEW崩潰,也就是說如果LabVIEW調用DLL函數時出現異常,首先應該考慮這個設置是否正確。(Windows API一般使用的都是stdcall;標準C的庫函數大多使用C call。如果函數聲明中有類似__stdcall這樣的關鍵字,它就是stdcall的。)第二頁是函數參數的配置(圖4)。 <ignore_js_>技術分享圖片

4.jpg (13.76 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:23 上傳

圖4 配置函數的參數   DLL和LabVIEW之間傳遞參數,最常用的三種數據類型是數值、數值型數組和字符串。C語言中經常把指針或者數據的地址在函數間傳遞,在32位操作系統中,可以使用int32數值來表示指針。因此,當需要在LabVIEW中傳遞指針數據時,可以使用I32或U32數值類型來表示這個地址類型的數據。但是,64位的程序中,數據的地址只能使用I64或U64來表示。這樣,如果一個調用了DLL函數的VI,並且函數參數中有地址型數據,使用固定數據類型的數值來表示地址,就要準備兩份代碼。解決方法是使用LabVIEW中的新的數據類型Pointer-sized Integer。這個數據類型的長度在不同的平臺上會自動使用32位或64位長度。如果在C語言函數參數聲明中有const關鍵字,可以選中Constant選項。布爾類型在DLL函數和LabVIEW VI之間傳遞沒有專有的數據類型,是利用數值類型來傳遞的。輸入時先把布爾值轉變為數值,在傳遞給DLL函數;輸出時再把數值轉為布爾值。對於數組的傳遞,LabVIEW只支持C數據類型中的數值型數組,傳遞數組類型需要註意的的是“Array Format”要選擇“Array Data Pointer”。這個設置中還有其他兩個選項,帶有“Handle”的參數類型都是表示LabVIEW定義的特殊類型的。在第三方的DLL中不會使用到數組參數作為輸出值時,要記得為輸出的數組數開辟空間。開辟數據空間的方法有兩種:第一種方法,創建一個長度滿足要求的數組,作為初始值傳遞給參數,輸出數的數據就會被放置在輸入數組的所在的內存空間內。第二種方法是直接在參數配置面板上進行設置。在Minimum size中寫入一個固定的數值,LabVIEW就會按此大小為輸出的數組開辟空間。在 Minimum size 中選擇函數的其它數值參數,而不是固定數值。這樣LabVIEW會按照當時被選擇的參數值的大小來開辟空間。字符串與使用與數組是非常類似的,實際上在C語言中字符串就是一個I8數組。 在NI軟件的安裝路徑下打開當前使用版本的LabVIEW文件夾,通過 examples\dll\data passing\Call NativeCode.llb找到簡單數據類型在LabVIEW與C之間的對應關系。部分常見關系見表1。 <ignore_js_op>技術分享圖片

5.jpg (39.05 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:23 上傳

<ignore_js_op>技術分享圖片

6.jpg (19.95 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:23 上傳

<ignore_js_op>技術分享圖片

7.jpg (33.51 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:23 上傳

<ignore_js_op>技術分享圖片

8.jpg (45.04 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:23 上傳

表1 數據類型對比   第三頁用於為DLL設置一些回調函數,可以使用這些回調函數在特定的情形下完成初始化、清理資源等工作(圖5)。 <ignore_js_op>技術分享圖片

9.jpg (15.24 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:24 上傳

圖5 設置回調函數   如果為Reserve選擇了一個回調函數,那麽當一個新的線程開始調用這個DLL時,這個回調函數首先被調用。可以利用這個函數為新線程使用到的數據做初始化工作。線程在使用完這個DLL之後,它會去調用Unreserve中指定的回調函數。Abort中指定的函數用於VI非正常結束時被調用,也就是讓一個程序在運行完前停止。這些回調函數的原型在Prototype for these procedures中列出,必須要由DLL的開發者按照特定的格式實現。如果使用的DLL不是專為LabVIEW設計的,一般不會包含這樣的回調函數。   第四頁是錯誤處理方式,用戶可根據需要選擇相應的錯誤檢查級別。   另外還需要註意的是,C語言中的struct在LabVIEW中可以使用cluster來表示,但有時需要作出相應的調整。這是因為在C語言中,struct的字節對齊是可以進行設置的,這就決定了其各元素的存放地址的可變性。C語言中的對字節對齊數可通過#pragma pack指令或在工程屬性中進行指定。而在LabVIEW的cluster中,所有元素只能是1字節對齊的,所以如果要和C語言中非1字節對齊的struct對應,需要做出一些調整。比如,對於C語言中2字節對齊的struct,第一個元素如果是I8型的,在LabVIEW的cluster中第一個元素對應不變,但不能緊挨著放第二個元素,必須留一個無意義的空位。C語言的struct其實也是如此,只不過沒有表現出來。所以為了方便,如果自己用C語言生成DLL文件供LabVIEW調用最好將struct都設為1字節對齊。C語言的struct中可以嵌套數組,但是這和LabVIEW中含有數組元素的cluster是不一樣的,LabVIEW中需要將數組中的元素都拆開放入cluster中。   如果C語言的struct中含有一個指針,LabVIEW中的cluster只能用一個U32數值(32位系統上,64位系統上使用U64)來表示指針的地址,而不能將指針所指向的內容放到Cluster中去。如果聲明的是指向struct的指針,才能在LabVIEW中使用cluster與之對應。CLN節點的配置面板中,沒有一個專門命名的“struct”或者“cluster”參數類型,應選擇“Adapt to Type”就可以了。如果參數的類型就是結構而非指針,考慮到C函數參數的壓棧順序,把一個結構體作為參數傳給函數,相當於把結構中每個元素分別作為參數傳遞給函數。圖6為C語言中struct和LabVIEW中cluster的部分匹配圖。 <ignore_js_op>技術分享圖片

10.jpg (20.07 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:24 上傳

圖6 struct和cluster匹配 LabVIEW打包DLL文件 我們接下來學習如何使用LabVIEW來打包一個DLL文件。   首先我們編寫一個名為Scale.vi的程序,功能很簡單就是對輸入的數據乘上10,然後再輸出(圖7)。 <ignore_js_op>技術分享圖片

11.jpg (18.08 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:24 上傳

圖7 scale.vi   必須在任務管理器中才能生成.dll文件。所以我們首先建立一個project,過程如下: 點擊File>>New Project: <ignore_js_op>技術分享圖片

12.jpg (20.14 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:24 上傳

圖8 生成新項目   接著彈出是否將該VI添加到新項目的對話框: <ignore_js_op>技術分享圖片

13.jpg (13.71 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:24 上傳

圖9 是否添加VI到新建項目   選擇Add,生成新的項目管理器,將其保存在需要的路徑下: <ignore_js_op>技術分享圖片

14.jpg (16.51 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:24 上傳

圖10 項目管理器   右鍵單擊項目瀏覽器窗口中的Build Specifications,在快捷菜單中選擇New>>Shared Library(DLL),彈出對DLL文件進行設置的對話框。點擊Category>>Information,根據自己需求修改Build specification name和Target filename: <ignore_js_op>技術分享圖片

15.jpg (16.02 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:25 上傳

圖11 Information頁面   點擊Source Files>>Project Files>> Scale.vi>> ,彈出對話框,直接用默認值,點擊OK: <ignore_js_op>技術分享圖片

16.jpg (18.16 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:25 上傳

圖12 Define VI Prototype   點擊Destination>> Scale.dll,點擊 ,可選擇需要保存的路徑。然後再點擊Support Directory,這是指明了DLL支持文件的路徑(比如數據文件之類的放在哪個文件夾),選擇默認即可: <ignore_js_op>技術分享圖片

17.jpg (14.52 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:25 上傳

圖13 Destination頁面   Category中的Source Files可供用戶對打包VI的屬性和密碼做一些設置;Advanced和Additional Exclusions可以做一些高級的設置,這些均按默認值即可。Version Information可讓用戶填寫版本號、名稱、版權、公司等信息: <ignore_js_op>技術分享圖片

18.jpg (19.1 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:25 上傳

圖14 Version Information 點擊Run-Time Languages,可對支持語言進行選擇,默認即可。點擊Preview>>Generate Preview,可以預覽到結果: <ignore_js_op>技術分享圖片

19.jpg (16.45 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:25 上傳

圖15 預覽生成 點擊Build,彈出生成狀態對話框: <ignore_js_op>技術分享圖片

20.jpg (13.28 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:25 上傳

圖16 生成狀態框 點擊Done,生成完成,打開DLL文件保存的路徑查看: <ignore_js_op>技術分享圖片

21.jpg (28 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:26 上傳

圖17 DLL文件保存路徑 LabVIEW調用DLL文件   LabVIEW可以方便地調用DLL文件,這些DLL文件可以是其他編譯工具,如VC,生成的。   LabVIEW可以直接通過CLN節點來調用DLL文件,以前面生成的Scale.dll文件為例。現有一個內部定時連續采集程序,通過調用該DLL文件,使讀取的值為實際采集值的10倍(圖18)。 <ignore_js_op>技術分享圖片

22.jpg (14.89 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:26 上傳

圖18 連續采集程序 方法一   在程序框圖放入Call Library Function Node,雙擊彈出對話框。在Function頁面的Library name or path中給入生成的Scale.dll文件的路徑,Function name選擇Scale,其他選項默認。 <ignore_js_op>技術分享圖片

23.jpg (21.43 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:26 上傳

圖19 Function頁面   由於是LabVIEW生成的DLL文件,在Parameters頁面不需要做改動,但是由於VI還有一路輸出,所以還需要添加一個參數y,作為DLL文件的輸出。   如果是C語言等非LabVIEW生成的DLL函數,需要將retuen type的type選項和Data type選項改成函數定義的參數類型,對於函數裏輸入的參數也都需要自行添加。Callbacks和Error Checking則不需要改動。 <ignore_js_op>技術分享圖片

24.jpg (25.39 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:26 上傳

圖20 Parameters頁面   點擊“OK”,將生成的CLN的輸入段連接到DAQmx Read.vi,return type輸出連接到波形圖表上,即可實現采集值放大10倍的功能。 <ignore_js_op>技術分享圖片

25.jpg (15.98 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:26 上傳

圖21 完成後的程序 方法二 LabVIEW中還有一種方法可以調用DLL文件,在VI的選項欄,依次選擇Tools——Import——Shared Library(.dll),彈出Import Shared Library對話框。 <ignore_js_op>技術分享圖片

26.jpg (33.08 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:27 上傳

圖22 生成Import Shared Library對話框   選擇Create VIs for a shared library,點擊Next,在Shared Library(.dll) Files中輸入Scale.dll文件的路徑,Head(.h) File裏填寫頭文件的路徑。 <ignore_js_op>技術分享圖片

27.jpg (15.83 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:27 上傳

圖23 選擇DLL文件路徑和頭文件路徑   點擊Next,如果DLL文件中依賴其他的一些DLL文件,需要在Include Paths中填寫這些文件的路徑。其他選項可以根據客戶需求設置,一般默認即可。這樣一直點擊Next到最後,選擇Open the generated library,點擊Finish。這樣可以生成一個.lvlib格式的庫文件,裏面包含了Scale.vi,這是將調用該DLL文件的方法封裝好的VI,只留下輸入和輸出接口,方便運用到LabVIEW的程序中。直接將Scale.vi拖放到剛才的連續采集中即可完成方法一的功能。 <ignore_js_op>技術分享圖片

28.jpg (14.56 KB, 下載次數: 0)

下載附件 保存到相冊

2015-2-12 11:27 上傳

圖24 完成的程序 VC調用LabVIEW生成的DLL文件   剛才介紹了LabVIEW調用DLL文件的方法,使用VC調用LabVIEW生成的DLL文件也很簡單。還是以之前生成Scale 的DLL文件為例,不同的是采集電壓程序使用的是C語言的例程,但和LavVIEW實現的功能相同。   首先將先前生成Scale DLL文件時,路徑下所有的文件全部復制粘帖到C語言例程的文件夾下。打開連續采集程序,點擊狀態欄的Project——Settings,在Project Settings對話框中加載入Scale.lib的靜態鏈接庫。   在程序中鍵入#include "Scale.h",以便引入該DLL函數。下面是C程序的代碼,功能是有限點采集電壓,通過Scale.dll文件實現采樣值放大10倍的功能。加粗部分是因為調用DLL文件所做的改動。
  1 #include
  2 #include "NIDAQmx.h"
  3 #include "Scale.h"
  4 
  5 #define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else
  6 
  7 
  8 
  9 int main(void)
 10 
 11 {
 12 
 13 int32 error=0;
 14 
 15 TaskHandle taskHandle=0;
 16 
 17 int32 read;
 18 
 19 float64 data[1000];
 20 
 21 char errBuff[2048]={\0};
 22 
 23 int i=0;
 24 
 25 double x10=0;
 26 
 27 
 28 
 29 
 30 
 31 /*********************************************/
 32 
 33 // DAQmx Configure Code
 34 
 35 /*********************************************/
 36 
 37 DAQmxErrChk (DAQmxCreateTask("",&taskHandle));
 38 
 39 DAQmxErrChk (DAQmxCreateAIVoltageChan(taskHandle,"Dev1/ai0"/*Config correct device*/,"",DAQmx_Val_Cfg_Default,-10.0,10.0,DAQmx_Val_Volts,NULL));//
 40 
 41 DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle,"",10000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000));
 42 
 43 
 44 
 45 /*********************************************/
 46 
 47 // DAQmx Start Code
 48 
 49 /*********************************************/
 50 
 51 DAQmxErrChk (DAQmxStartTask(taskHandle));
 52 
 53 
 54 
 55 /*********************************************/
 56 
 57 // DAQmx Read Code
 58 
 59 /*********************************************/
 60 
 61 DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,1000,10.0,DAQmx_Val_GroupByChannel,data,1000,&read,NULL));
 62 
 63 
 64 
 65 printf("Acquired %d points\n",read);
 66 
 67 
 68 
 69 for(i=0;i<1000;i++){
 70 
 71 Scale(data, &x10);
 72 
 73 printf("the %d Value is : %f \n",i,x10);
 74 
 75 
 76 
 77 }
 78 
 79 Error:
 80 
 81 if( DAQmxFailed(error) )
 82 
 83 DAQmxGetExtendedErrorInfo(errBuff,2048);
 84 
 85 if( taskHandle!=0 ) {
 86 
 87 /*********************************************/
 88 
 89 // DAQmx Stop Code
 90 
 91 /*********************************************/
 92 
 93 DAQmxStopTask(taskHandle);
 94 
 95 DAQmxClearTask(taskHandle);
 96 
 97 }
 98 
 99 if( DAQmxFailed(error) )
100 
101 printf("DAQmx Error: %s\n",errBuff);
102 
103 printf("End of program, press Enter key to quit\n");
104 
105 getchar();
106 
107 return 0;
108 
109 }

所以,使用LabVIEW不僅可以方便地調用各種編譯軟件生成的DLL文件,自己也能生成DLL文件供其他編譯軟件調用。這樣,用戶在編寫大型項目時更加靈活,也為熟悉C語言的工程師提供了巨大的方便。本文只對LabVIEW和VC相互調用DLL文件做了簡單的介紹,很多高級功能和技巧,用戶可以在實際運用中逐漸掌握。

LabVIEW如何方便地調用DLL文件