Academic Company Events NI Developer Zone Support Solutions Products & Services Contact NI MyNI

Document Type: Tutorial
NI Supported: Yes
Publish Date: Sep 6, 2006


Feedback


Yes No

Related Links - Developer Zone

Related Links - Products and Services

Writing 16-Bit Delphi Applications Using NI-488.2 Software

3 ratings | 2.67 out of 5
Print

Overview

Borland’s Delphi (version 1.0), one of the latest visual programming languages, uses Rapid Application Development (RAD) tools. With RAD tools, one can quickly and easily create Windows applications. Delphi is based on Object Pascal and is combined with a native-code compiler. Delphi is capable of accessing dynamic link libraries (DLLs), which makes it easy to interface to NI-488.2 software. This document explains how to access the NI-488.2 DLL from a Delphi application.

A Delphi application can access the NI-488.2 dynamic link library (gpib.dll) by using the direct entry functions. There are three options that you can use to accomplish this. One option is to implicitly load the library, which is outlined in the section called Writing an NI-488 or NI-488.2 Application Using Implicit Loading. Another option is to explicitly load the GPIB library using LoadLibrary, which is outlined in the section called called Writing an NI-488 or NI-488.2 Application Using Explicit Loading. The third option is to purchase the Turbo Pascal Language Interface for Windows (Part Number 776559-02). The language interface uses the implicit loading of a DLL method. How to add the .PAS module from the language interface to your project is outlined in the section called Using the Turbo Pascal Language Interface for Windows in Your Application.

Writing an NI-488 or NI-488.2 Application Using Implicit Loading

A 16-bit Delphi application can access the NI-488.2 dynamic link library (gpib.dll) by using the direct entry functions. The functions are identical to the NI-488 and NI-488.2 calls, except for the following two differences:
  • You must preface each function name by the characters DLL. For example, instead of using the NI-488 function ibwrt, use the direct entry function DLLibwrt.
  • The number of arguments taken by each function is increased by three. The last three parameters are, in order, a pointer to the ibsta variable, a pointer to the iberr variable, and a pointer to the ibcntl variable. Your application must declare its own ibsta, iberr, and ibcntl variables to use the direct entry functions.

This section discusses items you should include in your application along with examples.

Items to Include
Include the declarations for the GPIB global status variables in the var section of your Pascal unit module as shown below:

(* NI-488.2 global status variables *)
ibsta  : integer;
iberr  : integer;
ibcntl : longint;

Include the declarations for the GPIB functions in the implementation section of your Pascal unit module. Refer to Reference 1 for the format for the NI-488.2 and NI-488 direct entry prototypes. The prototypes are located in the Windows Format section under the Direct Entry with C listing. To convert from the C-style parameters (shown in the manual) to Delphi-style parameters, refer to the table below:


C-Style DeclarationDelphi-Style DeclarationDescription
Addr4882_t numnum : integerShort integer variable passed by value
Addr4882_t _far list[ ]type
AddrList = array[0..31] of integer
var results : AddrList
Array of short integers
char _far *udnameudname : PCharString passed by reference (e.g., for ibbna and ibfind calls)
char _far *buffervar num : byteUnsigned byte variable passed by reference
(e.g., for ibrpp and ibrsp calls)
int numnum : integerInteger variable passed by value
int *numvar num : integerInteger variable passed by reference
int _far *ibstavar ibsta : integerShort integer variable passed by reference
long numnum : longintLong integer variable passed by value
long _far *ibcntlvar ibcntl : longintLong integer variable passed by reference
short _far results[ ]type
ResultsList = array[0..31] of integer
var results : ResultsList
Array of short integers
short _far *numvar num : integerShort integer variable passed by reference
unsigned short numnum : wordUnsigned short integer variable passed by value
void _far *buffervar bufferString passed by reference


For functions that return an integer value, such as ibdev, the declaration includes the name of the call to the DLL, followed by the list of function parameters, as described in Reference 1, along with the three GPIB global variables, the type identifier of the function, and the far and external directives for the imported gpib.dll function. Below is an example of how to declare the ibdev function:

function DLLibdev(ud:          integer;
                  pad:         integer;
                  sad:         integer;
                  tmo:         integer;
                  eot:         integer;
                  eos:         integer;
                  var ibsta:  integer;
                  var iberr:  integer;
                  var ibcntl: longint)  :  integer;
                  far;  external  'GPIB';

For procedures, such as the NI-488.2 calls, the declaration includes the name of the call to the DLL, followed by the list of function parameters, as described in Reference 1, along with the three GPIB global variables, and the far and external directives for the imported gpib.dll call. Below is an example of how to declare the SendIFC procedure:

procedure DLLSendIFC(boardID:     integer;
                      var ibsta:  integer;
                      var iberr:  integer;
                      var ibcntl: longint);
                      far; external 'GPIB';

In the const section of your application, you can set up mnemonics for the Status Word Conditions and Error Codes as found in the Appendixes of Reference 1. These constants can be used in your application to help check which bits are set in the GPIB global variables, ibsta and iberr. Below is an example of how to declare them:

const
  (* GPIB Status Word Conditions.                                   *)
   ERR   = $8000;      (* Error detected                            *)
   TIMO  = $4000;      (* Timeout                                   *)
   EEND  = $2000;      (* EOI or EOS detected                       *)
   SRQI  = $1000;      (* SRQ detected by CIC                       *)
   RQS   = $800;       (* Device needs service                      *)
   SPOLL = $400;       (* Board has been serially polled            *)
   EVENT = $200;       (* An event has occurred                     *)
   CMPL  = $100;       (* I/O completed                             *)
   LOK   = $80;        (* Local lockout state                       *)
   REM   = $40;        (* Remote state                              *)
   CIC   = $20;        (* Controller-in-Charge                      *)
   ATN   = $10;        (* Attention asserted                        *)
   TACS  = $8;         (* Talker active                             *)
   LACS  = $4;         (* Listener active                           *)
   DTAS  = $2;         (* Device trigger state                      *)
   DCAS  = $1;         (* Device clear state                        *)
  (* Error messages returned in global variable IBERR:              *)
   EDVR  =  0;         (* System error                              *)
   ECIC  =  1;         (* Function requires GPIB board to be CIC    *)
   ENOL  =  2;         (* Write function detected no Listeners      *)
   EADR  =  3;          (* Interface board not addressed correctly  *)
   EARG  =  4;         (* Invalid argument to function call         *)
   ESAC  =  5;         (* Function requires GPIB board to be SAC    *)
   EABO  =  6;         (* I/O operation aborted                     *)
   ENEB  =  7;         (* Non-existent interface board              *)
   EDMA  =  8;         (* Error performing DMA                      *)
   EOIP  = 10;         (* I/O operation started before previous     *)
                       (* operation completed                       *)
   ECAP  = 11;         (* No capability for intended operation      *)
   EFSO  = 12;         (* File system operation error               *)
   EBUS  = 14;         (* Command error during device call          *)
   ESTB  = 15;         (* Serial poll status byte lost              *)
   ESRQ  = 16;         (* SRQ remains asserted                      *)
   ETAB  = 20;         (* The return buffer is full                 *)
   ELCK  = 21;         (* Address or board is locked                *)

Accessing the GPIB Calls and Variables
The code below illustrates how to call a function or a procedure and access the status variable from within your application:

dev := DLLibdev(0, 1, 0, 13, 1, 0, ibsta, iberr, ibcntl);
if (ibsta and ERR) <> 0 then
  gpiberr('ibdev Error');
DLLSendIFC(0, ibsta, iberr, ibcntl);
if (ibsta and ERR) <> 0 then
  gpiberr('SendIFC Error');

Sample Programs Using Implicit Loading
The Download section of our GPIB Web site includes two sample programs that illustrate how to make direct entry calls to interface to a multimeter. Please see the related link below.
See Also:
GPIB Web site

Writing an NI-488 or NI-488.2 Application Using Explicit Loading


A 16-bit Delphi application can access the NI-488.2 dynamic link library (gpib.dll) by using the direct entry functions. The functions are identical to the NI-488 and NI-488.2 calls, except for the following difference:
  • The number of arguments taken by each function is increased by three. The last three parameters are, in order, a pointer to the ibsta variable, a pointer to the iberr variable, and a pointer to the ibcntl variable. Your application must declare its own ibsta, iberr, and ibcntl variables to use the direct entry functions.

This section discusses items you should include in your application along with examples.

Items to Include
Include the declarations for the GPIB global status variables in the var section of your Pascal unit module as shown below:

(* NI-488.2 global status variables *)
ibsta  : integer;
iberr  : integer;
ibcntl : logint;

Include the type declarations for the GPIB functions in the type section of your Pascal unit module. See Reference 1 for the format for the NI-488.2 and NI-488 direct entry prototypes. The prototypes are located in the Windows Format section under the Direct Entry with C listing. To convert from the C-style parameters (shown in the manual) to Delphi-style parameters, refer to the conversion table.

For functions that return an integer value, such as ibdev, the declared calls are followed by the list of parameters, as described in Reference 1, along with the three GPIB global variables and the type identifier of the function. Below is an example of how to declare the ibdev function:

TDLLibdev = function (ud:          integer;
                      pad:         integer;
                      sad:         integer;
                      tmo:         integer;
                      eot:         integer;
                      eos:         integer;
                      var ibsta:  integer;
                      var iberr:  integer;
                      var ibcntl: longint)  :  integer;

For procedures, such as the NI-488.2 calls, the declared calls are followed by the list of parameters, as described in Reference 1, along with the three GPIB global variables. Below is an example of how to declare the SendIFC procedure:

TDLLSendIFC = procedure (boardID:     integer;
                         var ibsta:  integer;
                         var iberr:  integer;
                         var ibcntl: longint);

Below is an example of how to declare the calls in the var section:

DLLibdev   : TDLLibdev;
DLLSendIFC : TDLLSendIFC;

You also need a handle to the GPIB library. Below is an example of how to declare it in the var section of your application:

GpibLib : THandle;

In the const section of your application, you can set up mnemonics for the Status Word Conditions and Error Codes as found in the Appendixes of Reference 1. These constants can be used in your application to help check which bits are set in the GPIB global variables, ibsta and iberr. Below is an example of how to declare them:

const
   (* GPIB Status Word Conditions.*)
   ERR   = $8000;             (* Error detected                         *)
   TIMO  = $4000;             (* Timeout                                *)
   EEND  = $2000;             (* EOI or EOS detected                    *)
   SRQI  = $1000;             (* SRQ detected by CIC                    *)
   RQS   = $800;              (* Device needs service                   *)
   SPOLL = $400;              (* Board has been serially polled         *)
   EVENT = $200;              (* An event has occurred                  *)
   CMPL  = $100;              (* I/O completed                          *)
   LOK   = $80;               (* Local lockout state                    *)
   REM   = $40;               (* Remote state                           *)
   CIC   = $20;               (* Controller-in-Charge                   *)
   ATN   = $10;               (* Attention asserted                     *)
   TACS  = $8;                (* Talker active                          *)
   LACS  = $4;                (* Listener active                        *)
   DTAS  = $2;                (* Device trigger state                   *)
   DCAS  = $1;                (* Device clear state                     *)
   (* Error messages returned in global variable IBERR:                 *)
   EDVR =  0;                 (* System error                           *)
   ECIC =  1;                 (* Function requires GPIB board to be CIC  *)
   ENOL =  2;                 (* Write function detected no Listeners   *)
   EADR =  3;                 (* Interface board not addressed correctly *)
   EARG =  4;                 (* Invalid argument to function call      *)
   ESAC =  5;                 (* Function requires GPIB board to be SAC  *)
   EABO =  6;                 (* I/O operation aborted                  *)


ENEB =  7;                 (* Non-existent interface board           *)
EDMA =  8;                 (* Error performing DMA                   *)
EOIP = 10;                 (* I/O operation started before previous   *)
                           (* operation completed                    *)
ECAP = 11;                 (* No capability for intended operation    *)
EFSO = 12;                 (* File system operation error            *)
EBUS = 14;                 (* Command error during device call       *)
ESTB = 15;                 (* Serial poll status byte lost           *)
ESRQ = 16;                 (* SRQ remains asserted                   *)
ETAB = 20;                 (* The return buffer is full              *)
ELCK = 21;                 (* Address or board is locked             *)

Loading the GPIB.DLL Library
In your application, you need to load the GPIB library (gpib.dll). The following code fragment illustrates how to call the LoadLibrary function and check for an error:

GpibLib := LoadLibrary('GPIB.DLL');
If GpibLib = 0 Then
  begin
     (* Report an error here. *)
  end;

Getting the Addresses
Next, your application needs to use GetProcAddress to get the addresses of the functions you need to use. You must preface each function by the characters “DLL”. For example, instead of using the NI-488 function ibwrt, use the direct entry function DLLibwrt. The following code fragment illustrates how to get the addresses of the pointers to the functions your application needs to use:

(* NI-488 calls *)
@DLLibdev := GetProcAddress(GpibLib, 'DLLibdev');
@DLLibonl := GetProcAddress(GpibLib, 'DLLibonl');

(* NI-488.2 call *)
@DLLSendIFC := GetProcAddress(GpibLib, 'DLLSendIFC');

If GetProcAddress fails, it returns a NIL pointer. The following code fragment illustrates how to verify that none of the calls to GetProcAddress failed:

If (@DLLibdev = NIL) or
   (@DLLibonl = NIL) then
    begin
       (* Report an error. *)
       FreeLibrary(GpibLib);   (* Free the library. *)
    end;

Accessing the GPIB Calls and Variables
The code below illustrates how to call a function or a procedure and access the status variable from within your application:

dev := DLLibdev(0, 1, 0, 13, 1, 0, ibsta, iberr, ibcntl);
if (ibsta and ERR) <> 0 then
  gpiberr('ibdev Error');

DLLSendIFC(0, ibsta, iberr, ibcntl);
if (ibsta and ERR) <> 0 then
  gpiberr('SendIFC Error');

Freeing the Library
Before exiting your application, you need to free gpib.dll with the following command:

FreeLibrary(GpibLib);

Sample Programs Using Explicit Loading
The Download section of our GPIB Web site includes two sample programs that illustrate how to make direct entry calls to interface to a multimeter. Please see the related link below.
See Also:
GPIB Web site

Using the Turbo Pascal Language Interface for Windows in Your Application


The main items of interest on the Turbo Pascal Language Interface for Windows diskette are a readme.doc, a tpwgpib.pas file, and two sample programs (devsamp.pas and samp4882.pas). The readme.doc file contains information about the required type declarations needed by a GPIB application. The information is located in the Creating Your Application Program section of the readme.doc. The tpwgpib.pas file contains the type definitions, various predefined constants, and NI-488.2 routine and NI-488 function prototypes. The sample programs (devsamp.pas and samp4882.pas) are for reference only. They can be expected to function only with a Fluke 45 Digital Multimeter. The devsamp.pas sample demonstrates how to make NI-488 function calls and the samp4882.pas sample demonstrates how to make NI-488.2 procedure calls.
  • For your first GPIB Delphi project, follow the steps below to add tpwgpib.pas to your project. When compiling a project, Delphi takes the tpwgpib.pas file and compiles it into a Delphi Compiled Unit called tpwgpib.dcu. The newly created tpwgpib.dcu can later be used in additional GPIB Delphi projects.

For your first GPIB Delphi project, to add tpwgpib.pas to your project and generate a tpwgpib.dcu, complete the following steps.
  1. Select File from the menu bar.
  2. In the Add to project dialog box that appears, select the appropriate directory from the Directories list box where tpwgpib.pas resides. Then select tpwgpib.pas from the File Name: list.
  3. In your application .PAS file, include the following item in the interface uses list: tpwgpib
  4. To compile the project, select Compile from the menu bar. Then select Build All from the list.
  5. To run the program, select Run from the menu bar. Next, select Run from the list.

For additional GPIB Delphi projects, include the tpwgpib.dcu module in your project by adding the item, tpwgpib,to the list in the interface uses clause of the .PAS unit of your project.

For more information about NI-488 or NI-488.2 calls, refer to the section called Windows Format C in Reference 1. To convert from the C-style parameters (shown in the manual) to Delphi-style parameters, refer to the conversion table.
3 ratings | 2.67 out of 5
Print

Reader Comments | Submit a comment »

 

Legal
This tutorial (this "tutorial") was developed by National Instruments ("NI"). Although technical support of this tutorial may be made available by National Instruments, the content in this tutorial may not be completely tested and verified, and NI does not guarantee its quality in any way or that NI will continue to support this content with each new revision of related products and drivers. THIS TUTORIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND AND SUBJECT TO CERTAIN RESTRICTIONS AS MORE SPECIFICALLY SET FORTH IN NI.COM'S TERMS OF USE (http://ni.com/legal/termsofuse/unitedstates/us/).