Difference between revisions of "NI-DAQmx and NI-DAQmx Base examples"

From Free Pascal wiki
Jump to navigationJump to search
(→‎INTRODUCTION: Updated content; OSX->macOS; fixed typos; added categories)
 
(71 intermediate revisions by 4 users not shown)
Line 3: Line 3:
 
== INTRODUCTION ==
 
== INTRODUCTION ==
  
National Instruments produce a wide range of DAQ cards, which generally used for acquiring a generating signals. [http://www.ni.com/data-acquisition/multifunction/]
+
National Instruments produce a wide range of [http://www.ni.com/data-acquisition/multifunction/ DAQ cards], which are generally used for acquiring and generating signals.  
These cards usually have a few numbers of analog inputs/outputs, digital inputs/ouputs, counters and frequency generator with hardware/software timing. Exiting of feature (type, number, parameters) on card depends on card type.
 
  
NIDAQmxBase.pas and NIDAQmx.pas are provided pascal bindings to National Instruments libraries and enabled control NI DAQ cards from program writing on FreePascal.
+
These cards usually have a few analog inputs/outputs, digital inputs/outputs, counters and a frequency generator with hardware/software timing. Exact features (type, number, parameters) depends on the card type.
  
'''What National Instruments Hardware are supported'''
+
NIDAQmxBase.pas and NIDAQmx.pas are provided pascal bindings to National Instruments libraries and enable control of NI DAQ cards from programs written in Free Pascal.
  
Supported hardware list by NI-DAQmx and NI-DAQ Driver for different operation system [http://www.ni.com/white-paper/6910/en/] 
+
=== What National Instruments Hardware is supported ===
  
'''NI-DAQmxBase library'''
+
[http://www.ni.com/white-paper/6910/en/ Supported hardware list] by NI-DAQmx and NI-DAQ Driver for different operating systems.   
  
NI-DAQmxBase library or driver is multiplatform library for Linux, Windows and MacOS X, but doesn't implement all device features. For example, digital input/output ports speed is limited by computer speed ~100kHz, because DMA data tranfer is not supported.
+
=== NI-DAQmxBase library ===
  
Download library for Linux [http://www.ni.com/download/ni-daqmx-base-14.0/5054/en/], Windows [http://www.ni.com/download/ni-daqmx-base-3.7/4281/en/], MacOS X [http://www.ni.com/download/ni-daqmx-base-3.7/4272/en/].
+
NI-DAQmxBase library or driver is multiplatform library for Windows (Windows XP 32 bit, Windows 7 32/64 bit, Windows Vista 32/64 bit, Windows 8 32/64 bit), macOS 32/64 bit and Linux 32/64 bit (SUSE, Scientific Linux, RedHat, CentOS), but doesn't implement all device features. For example, digital input/output ports speed is limited by computer speed ~100kHz, because DMA data transfer is not supported.
Read readme.txt file to find the list of supported hardware and hardware features.
 
  
'''NI-DAQmx library'''
+
Download library [https://www.ni.com/en-au/support/downloads/drivers/download.ni-daqmx-base.html from here].
 +
Read [http://download.ni.com/support/softlib/multifunction_daq/nidaqmxbase/15.0/windows/readme.htm readme file] to find the list of supported hardware and hardware features.
  
Actual (newest) NI-DAQmx library is available only for Windows today.  
+
<syntaxhighlight lang="text">
 +
  Latest Linux version 15.0 supports 64-bit OS, but you still need to install some 32-bit library.  
 +
 
 +
  LIST OF LIBRARIES:
  
Download it there [http://www.ni.com/download/ni-daqmx-14.1/4953/en/]
+
  compat-libstdc++.i686
 +
  expat.i686
 +
  glibc.i686
 +
  glibc-devel.i686
 +
  libdrm.i686
 +
  libgcc.i686
 +
  libselinux.i686
 +
  libstdc++.i686
 +
  libX11.i686
 +
  libXau.i686
 +
  libxcb.i686
 +
  libXdamage.i686
 +
  libXext.i686
 +
  libXinerama.i686
 +
  libXfixes.i686
 +
  libXxf86vm.i686
 +
  mesa-dri-drivers.i686
 +
  mesa-libGL.i686
 +
  nss-softokn-freebl.i686
 +
  zlib.i686
 +
</syntaxhighlight>
  
NI-DAQmx version 8.0.2 is also available for Linux 32-bit. You can use it with enterprise RHEL 5,6 distribution or with it clones CentOS 5,6 and Scientific Linux 5,6 or you can use it with old version Linux distribution with kernel 2.6.x.
+
=== NI-DAQmx library ===
  
Download it there [http://www.ni.com/download/ni-daqmx-8.0.2/2322/en/]
+
The NI-DAQmx library is only available for Windows 7 (SP1) 32/64 bit, Windows 8.1 32/64 bit, Windows 10 32/64 bit, Windows Embedded Standard 7 (SP1), Windows Server 2008 R2 (SP1) 32/64 bit). [https://www.ni.com/en-au/support/downloads/drivers/download.ni-daqmx.html Download here)]
  
Read readme.txt file to find the list of supported hardware and hardware features.
+
Read [http://download.ni.com/support/softlib/multifunction_daq/nidaqmx/9.0/readme.html readme file] to find the list of supported hardware and hardware features.
 +
 
 +
[[Category:Hardware]]
 +
[[Category:FPC in Science and Technology]]
 +
 
 +
==HOW TO IDENTIFY PRESENT HARDWARE ==
 +
 
 +
To get list of devices present in your system Under Linux operation system use
 +
1) '''nilsdev''' utility with NIDAQmx driver installed,
 +
2) '''lsdaq''' utility with NIDAQmxBase driver installed.
 +
 
 +
Under Windows use '''NIMAX''' utility to get device list or set device alias etc.
 +
 
 +
==Library documentation==
 +
You can find description of functions and properties in NI-DAQmx and NI-DAQmx Base C reference Help:
 +
* [http://digital.ni.com/manuals.nsf/websearch/934F66A25EB3831586257AFD00741B13?OpenDocument&seen=1 NI-DAQmx]
 +
* [http://digital.ni.com/manuals.nsf/websearch/C4B5B92E74F160C6862574560065F8BC NI-DAQmx Base]
  
 
== PASCAL bindings ==
 
== PASCAL bindings ==
  
Your can download pascal bindings nidaqmxbase.pas and nidaqmx.pas in this forum thread [http://forum.lazarus.freepascal.org/index.php/topic,7894.msg161883.html#msg161883]
+
Your can download pascal bindings nidaqmxbase.pas and nidaqmx.pas in this forum thread [http://forum.lazarus.freepascal.org/index.php/topic,7894.msg161883.html#msg161883] or as a [http://sourceforge.net/p/lazmer/code/HEAD/tree/trunk/daqlibs/ part of the LazMer] project.
  
 
==FUNCTION CALLING==
 
==FUNCTION CALLING==
Line 39: Line 77:
 
<syntaxhighlight lang="text">
 
<syntaxhighlight lang="text">
 
1. Create task: DAQmxCreateTask
 
1. Create task: DAQmxCreateTask
2. Channel create: DAQmxCreateDIChan
+
2. Channel create:  
 +
  a)DAQmxCreateDIChan/DAQmxCreateDOChan (digital input(s)/output(s))
 +
  b)DAQmxCreateAIVoltageChan/DAQmxCreateAOVoltageChan (analog input(s)/output(s))
 
3. Set timing if you need hardware timimg: DAQmxCfgSamplClkTiming
 
3. Set timing if you need hardware timimg: DAQmxCfgSamplClkTiming
 
4. Start task: DAQmxStartTask
 
4. Start task: DAQmxStartTask
5. Read or write data from/to channel: DAQmxReadDigitalU32 or DAQmxWriteDigitalU32
+
5. Read or write data from/to channel:  
 +
  a)read data from digital port: DAQmxReadDigitalU8(8-bit port),DAQmxReadDigitalU32 (32-bit port),
 +
  b)write data to digital port:  DAQmxWriteDigitalU8(8-bit port),DAQmxWriteDigitalU32 (32-bit port),
 +
  c)read data from analog input(s): DAQmxReadAnalogF64,
 +
  d)write data to analog output(s): DAQmxWriteAnalogF64.
 
6. Do job
 
6. Do job
 
7. End of program - stop and clear task: DAQmxStopTask and DAQmxClearTask
 
7. End of program - stop and clear task: DAQmxStopTask and DAQmxClearTask
  
 
For error handling create function like ErrorCheck.
 
For error handling create function like ErrorCheck.
 +
</syntaxhighlight>
 +
 +
from '''nidaqmxbase.pas'''  as follow
 +
<syntaxhighlight lang="text">
 +
1. Create task: DAQmxBaseCreateTask
 +
2. Channel create:
 +
  a)DAQmxBaseCreateDIChan/DAQmxBaseCreateDOChan (digital input(s)/output(s))
 +
  b)DAQmxBaseCreateAIVoltageChan/DAQmxBaseCreateAOVoltageChan (analog input(s)/output(s))
 +
3. Set timing if you need hardware timimg: DAQmxBaseCfgSamplClkTiming
 +
4. Start task: DAQmxBaseStartTask
 +
5. Read or write data from/to channel:
 +
  a)read data from digital port: DAQmxBaseReadDigitalU8(8-bit port),DAQmxBaseReadDigitalU32 (32-bit port),
 +
  b)write data to digital port:  DAQmxBaseWriteDigitalU8(8-bit port),DAQmxBaseWriteDigitalU32 (32-bit port),
 +
  c)read data from analog input(s): DAQmxBaseReadAnalogF64,
 +
  d)write data to analog output(s): DAQmxBaseWriteAnalogF64.
 +
6. Do job
 +
7. End of program - stop and clear task: DAQmxBaseStopTask and DAQmxBaseClearTask
 +
 +
For error handling create function like ErrorCheck.
 +
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="text">
 +
Probably, some examples need to add @ before variable, which use as function parameter!!!
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 317: Line 385:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
====Continuosly acquire samples from three analog inputs====
+
====Continuously acquire samples from three analog inputs====
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 397: Line 465:
 
Output example
 
Output example
 
<syntaxhighlight lang="text">
 
<syntaxhighlight lang="text">
aquired number of samples: 1000                                 
+
acquired number of samples: 1000                                 
 
aquired number of samples: 2000                                 
 
aquired number of samples: 2000                                 
aquired number of samples: 3000                                 
+
acquired number of samples: 3000                                 
aquired number of samples: 4000                                 
+
acquired number of samples: 4000                                 
aquired number of samples: 5000                                 
+
acquired number of samples: 5000                                 
aquired number of samples: 6000                                 
+
acquired number of samples: 6000                                 
aquired number of samples: 7000                                 
+
acquired number of samples: 7000                                 
aquired number of samples: 8000                                 
+
acquired number of samples: 8000                                 
aquired number of samples: 9000                                 
+
acquired number of samples: 9000                                 
aquired number of samples: 10000
+
acquired number of samples: 10000
  
 
Value of first 10 samples of last 1000 samples for each channel
 
Value of first 10 samples of last 1000 samples for each channel
Line 423: Line 491:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
====Analog output software controlled====
+
====Start acquisition on analog input by digital trigger====
 +
This example demonstrates how to start acquisition by digital trigger.
  
====Analog output hardware controlled====
+
<syntaxhighlight lang="pascal">
 +
program aidigtrig;
  
===DIGITAL INPUTS/OUTPUTS===
+
{$mode objfpc}{$H+}
  
Most of DAQ cards have two types of digital ports (input/output): correlated and static. Static ports are software timed, correlated are software and hardware timed by the connection of external clock or internally for example couter output signal ('''/Dev1/Ctr0InternalOutput''' - couter0 as clock ). Check the documention to find it, for example NI-PCI6250 have three 8-bit ports: port0 - correlated, port1,port2 - static; NI-PCI6224 two ports: 32-bit port0 - correlated, 8-bit port1 - static.
+
uses
 
 
To control 8-bit and 32-bit use an appropriate function '''DAQmxReadDigitalU8''', '''DAQmxWriteDigitalU8''' and '''DAQmxReadDigitalU8''', '''DAQmxWriteDigitalU8'''.
 
 
 
''Different behaviour of collerated port0, when it sets as input, occured under Linux and Windows: software timed works only under Windows, with external clock works under Windows and Linux!!!''
 
 
 
====Software timed digital input ====
 
 
 
To check it, connected +5V(depend on hardware) to one of available port pins.
 
 
 
<syntaxhighlight lang="pascal">
 
program diport;
 
 
 
{$mode objfpc}{$H+}
 
 
 
uses
 
 
   {$IFDEF UNIX}{$IFDEF UseCThreads}
 
   {$IFDEF UNIX}{$IFDEF UseCThreads}
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmx,SysUtils,StrUtils
+
   Classes,nidaqmx,crt
 
   { you can add units after this };
 
   { you can add units after this };
 
var
 
var
   DITaskHandle:TaskHandle;
+
  AITaskHandle:TaskHandle;
   data:array [0..9] of byte;
+
   channel:string = 'Dev1/ai0';
 +
  SampleRate:double = 10000;
 +
  SamplePerChannel:longint = 1000;
 +
   PretriggerSamples: longint= 100; //MUST be > 2
 
   reads:longint = 0;
 
   reads:longint = 0;
   totalreads:longint = 0;
+
   i:longint;
   i:longint ;
+
   data:array of double;
{************Error handling procedure *****************************************
+
procedure ErrorCheck(AError:longint;ATaskHandle:longint);
      Example:
+
var
  ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
+
  errBuffer:array[0..2048] of char;
 
+
begin
  *******************************************************************************}
+
  //get error description
 
+
  if Aerror<>0 then begin
  procedure ErrorCheck(AError:longint;ATaskHandle:longint);
+
    DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
  var
+
    writeln(ErrBuffer);
    errBuffer:array[0..2048] of char;
 
  begin
 
    //get error description
 
    if Aerror<>0 then begin
 
      DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
 
      writeln(PChar(@ErrBuffer[0]));
 
 
     //stop and cleat task
 
     //stop and cleat task
 
     if Assigned(@ATaskHandle) then begin
 
     if Assigned(@ATaskHandle) then begin
Line 475: Line 527:
 
       DAQmxClearTask(ATaskHandle);
 
       DAQmxClearTask(ATaskHandle);
 
     end;
 
     end;
     //stop program
+
     //stop acquisition
 +
    writeln('Program stoped');
 
     Halt;
 
     Halt;
    end;
 
 
   end;
 
   end;
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
+
end;
 +
 
 
begin
 
begin
  //task create
+
    //set buffer length
  ErrorCheck(DAQmxCreateTask('',@DITaskHandle),DITaskHandle);
+
    SetLength(data,SamplePerChannel);
  //digital input port create
+
    //create take
  ErrorCheck(DAQmxCreateDIChan(DITaskHandle,'Dev1/port1','',DAQmx_Val_ChanForAllLines),DITaskHandle);
+
    DAQmxCreateTask('',@AITaskHandle);
  //Start Task
+
    //create ai channel
  ErrorCheck(DAQmxStartTask(DITaskHandle),DITaskHandle);
+
    ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,@channel[1],'',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,Nil),AITaskHandle);
  //read 10 samples from 8-bit digital port (for example NI PCI-6250 card port1(pins P1.0-P1.7))
+
    //configure sample clock
  //for 32-bit digital port use DAQmxReadDigitalU32 function
+
    ErrorCheck(DAQmxCfgSampClkTiming(AITaskHandle,'',SampleRate,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,SamplePerChannel),AITaskHandle);
  ErrorCheck(DAQmxReadDigitalU8(DITaskHandle,10,10.0,DAQmx_Val_GroupByChannel,@data,10,@reads,Nil),DITaskHandle);
+
    //configure triger with 100 pretriggered samples
  writeln('number of readed samples: ',reads);
+
    ErrorCheck(DAQmxCfgDigEdgeRefTrig(AITaskHandle,'/Dev1/PFI0',DAQmx_Val_Rising,PretriggerSamples),AITaskHandle);
  for i:=0 to 9 do writeln('data [',i,'] = %',IntToBin(data[i],8));
+
    //start task
  //stop and clear task
+
    ErrorCheck(DAQmxStartTask(AITaskHandle),AITaskHandle);
  if DITaskHandle<>0 then begin
+
    //acquire data
    DAQmxStopTask(DITaskHandle);
+
    writeln('Press any key to stop acquisition');
    DAQmxClearTask(DITaskHandle);
+
    i := 0;
  end;
+
    repeat
end.
+
      ErrorCheck(DAQmxReadAnalogF64(AITaskHandle,SamplePerChannel,10.0,DAQmx_Val_GroupByChannel,@data[0],Length(data),@reads,Nil),AITaskHandle);
</syntaxhighlight>
+
      i := i + reads;
 
+
      writeln('Number of acquired samples: ', i);
Output example: +5V connected to pin P1.2 port1 on NI-PCI6250 card.
+
    until keypressed;
<syntaxhighlight lang="text">
+
    //show last readed number of samples
number of readed samples: 10
+
    for i:=Low(data) to High(data) do writeln('data[',i,'] = ', data[i]:4:2);
data [0] = %00000100
+
 
data [1] = %00000100
+
    //stop and clear task
data [2] = %00000100
+
    if Assigned(@AITaskHandle) then begin
data [3] = %00000100
+
      DAQmxStopTask(AITaskHandle);
data [4] = %00000100
+
      DAQmxClearTask(AITaskHandle);
data [5] = %00000100
+
    end;
data [6] = %00000100
+
end.                    
data [7] = %00000100
+
</syntaxhighlight>
data [8] = %00000100
+
 
data [9] = %00000100
+
====Analog output software controlled====
</syntaxhighlight>
+
This example demonstrates sinusoidal waveform generation with software timed control analog output.
 
+
 
====Hardware timed digital input====
+
<syntaxhighlight lang="pascal">
 
+
program aochansw;
This example shows using of counter output signal as a clock for digital inputs port for hardware timed acquire data on digital inputs. This feature is supported only for correlated digital port. In this example 8-bit port0 on NI-PCI6250 card were used to check this function.  
+
 
 
+
{$mode objfpc}{$H+}
To check it, connected +5V(depend on hardware) to one of available pins on correlated digital port.
 
<syntaxhighlight lang="pascal">
 
program diporttimed;
 
 
 
{$mode objfpc}{$H+}
 
  
 
uses
 
uses
Line 529: Line 577:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmx,SysUtils,StrUtils
+
   Classes,Crt,SysUtils,nidaqmx
 
   { you can add units after this };
 
   { you can add units after this };
 
var
 
var
   DITaskHandle,CtrTaskHandle:TaskHandle;
+
   AOTaskHandle:TaskHandle;
   data:array [0..9] of byte;
+
  //data writted to analog output
   reads:longint = 0;
+
   data:array [0..999] of double;
   totalreads:longint = 0;
+
   writtensamples:integer;
  i:longint ;
+
   i:integer;
{************Error handling procedure *****************************************
+
 
      Example:
+
{************Error handling procedure *****************************************
  ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
+
    Example:
 +
ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
 +
*******************************************************************************}
 +
procedure ErrorCheck(AError:longint;ATaskHandle:longint);
 +
var
 +
  errBuffer:array[0..2048] of char;
 +
begin
 +
  //get error description
 +
  if Aerror<>0 then begin
 +
    DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
 +
    writeln(PChar(@ErrBuffer[0]));
 +
  //stop and cleat task
 +
  if Assigned(@ATaskHandle) then begin
 +
    DAQmxStopTask(ATaskHandle);
 +
    DAQmxClearTask(ATaskHandle);
 +
  end;
 +
  //stop program
 +
  Halt;
 +
  end;
 +
end;
  
   *******************************************************************************}
+
begin
 +
   //prepare data for analog output
 +
  //sin waveform
 +
  for i:=Low(data) to High(data) do data[i]:=9.95*sin(i*2.0*Pi/1000.0);
 +
  //create task
 +
  DAQmxCreateTask('',@AOTaskHandle);
 +
  //configure analog output channel
 +
  ErrorCheck(DAQmxCreateAOVoltageChan(AOTaskHandle,'Dev1/ao0','',-10.0,10.0,DAQmx_Val_Volts,Nil),AOTaskHandle);
 +
  //start task
 +
  ErrorCheck(DAQmxStartTask(AOTaskHandle),AOTaskHandle);
 +
 
 +
  writeln('Press any key to stop generation');
 +
  //continuosly waveform generation
 +
  //if you call task start function (DAQmxStartTask)
 +
  //before output write function (for example DAQmxWriteAnalogScalarF64)
 +
  //set AutoStart parameter to 1
 +
  //if output function berofe start AutoStart = 0
 +
  i:=0;
 +
  repeat
 +
    sleep(1);
 +
    ErrorCheck(DAQmxWriteAnalogScalarF64(AOTaskHandle,1,10.0,data[i],Nil),AOTaskHandle);
 +
    inc(i);
 +
    if i >=1000 then i:=0;
 +
  until keypressed;
  
   procedure ErrorCheck(AError:longint;ATaskHandle:longint);
+
   //stop and clear task
  var
+
  if Assigned(@AOTaskHandle) then begin
    errBuffer:array[0..2048] of char;
+
    DAQmxStopTask(AOTaskHandle);
  begin
+
    DAQmxClearTask(AOTaskHandle);
    //get error description
 
    if Aerror<>0 then begin
 
      DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
 
      writeln(PChar(@ErrBuffer[0]));
 
    //stop and cleat task
 
    if Assigned(@ATaskHandle) then begin
 
      DAQmxStopTask(ATaskHandle);
 
      DAQmxClearTask(ATaskHandle);
 
    end;
 
    //stop program
 
    Halt;
 
    end;
 
 
   end;
 
   end;
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
+
end.                                 
begin
+
</syntaxhighlight>
  {******CREATE COUNTER OUTPUT TO USE IT AS CLOCK FOR DIGITAL PORT INPUTS******
+
 
  *******INTERNALLY CONNECTED ON M-SERIES as /Dev1/Ctr0InternalOutput**********}
+
====Analog output hardware controlled====
  //create couter task
+
This example demonstrates how to generate finite number of samples on analog output channel.
  ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
+
 
  //create counter output channel
+
<syntaxhighlight lang="pascal">
  //Frequency 1000 Hz, duty 0.5
+
program aochannel;
  ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,1000,0.5),CtrTaskHandle);
+
 
  //timing 1000 samples per second
+
{$mode objfpc}{$H+}
  ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
 
  //start counter task
 
  ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
 
  
   //digital input task create
+
uses
   ErrorCheck(DAQmxCreateTask('Digital input task',@DITaskHandle),DITaskHandle);
+
   {$IFDEF UNIX}{$IFDEF UseCThreads}
   //digital input port create
+
   cthreads,
   ErrorCheck(DAQmxCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
+
   {$ENDIF}{$ENDIF}
   //timing use counter output as clock source internally connected
+
   Classes,nidaqmx
  //as /Dev1/Ctr0InternalOutput
+
   { you can add units after this };
  ErrorCheck(DAQmxCfgSampClkTiming(DITaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000),DITaskHandle);
+
 
  //Start digital input Task
+
var
   ErrorCheck(DAQmxStartTask(DITaskHandle),DITaskHandle);
+
   AOTaskHandle:TaskHandle;
   //read 10 samples from 8-bit digital port for example correlated port0
+
   //data writted to analog output
   //for 32-bit digital port use DAQmxReadDigitalU32 function
+
   data:array [0..3999] of double;
  ErrorCheck(DAQmxReadDigitalU8(DITaskHandle,10,10.0,DAQmx_Val_GroupByChannel,@data,10,@reads,Nil),DITaskHandle);
+
   writtensamples:integer;
   writeln('number of readed samples: ',reads);
+
   i:integer;
   for i:=0 to 9 do writeln('data [',i,'] = %',IntToBin(data[i],8));
 
  //stop and clear task
 
  DAQmxStopTask(DITaskHandle);
 
  DAQmxClearTask(DITaskHandle);
 
  DAQmxStopTask(CtrTaskHandle);
 
  DAQmxClearTask(CtrTaskHandle);  
 
end.
 
</syntaxhighlight>
 
  
Output example: +5V connected to pin P0.5 on port0 on NI-PCI6250 card.  
+
{************Error handling procedure *****************************************
<syntaxhighlight lang="text">
+
    Example:
number of readed samples: 10
+
ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
data [0] = %00100000
 
data [1] = %00100000
 
data [2] = %00100000
 
data [3] = %00100000
 
data [4] = %00100000
 
data [5] = %00100000
 
data [6] = %00100000
 
data [7] = %00100000
 
data [8] = %00100000
 
data [9] = %00100000
 
</syntaxhighlight>
 
  
====Software controlled digital output====
+
*******************************************************************************}
  
To check it connect digital output(s) to oscilloscope or to card analog input.
+
procedure ErrorCheck(AError:longint;ATaskHandle:longint);
 
 
<syntaxhighlight lang="pascal">
 
program doportlpi;
 
 
 
{$mode objfpc}{$H+}
 
 
 
uses
 
  {$IFDEF UNIX}{$IFDEF UseCThreads}
 
  cthreads,
 
  {$ENDIF}{$ENDIF}
 
  Classes,nidaqmx,SysUtils,StrUtils
 
  { you can add units after this };
 
 
var
 
var
   DOTaskHandle:TaskHandle;
+
   errBuffer:array[0..2048] of char;
  data: byte;
+
begin
  written:longint = 0;
+
  //get error description
{************Error handling procedure *****************************************
+
  if Aerror<>0 then begin
      Example:
+
    DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
+
    writeln(PChar(@ErrBuffer[0]));
 +
  //stop and cleat task
 +
   if Assigned(@ATaskHandle) then begin
 +
    DAQmxStopTask(ATaskHandle);
 +
    DAQmxClearTask(ATaskHandle);
 +
  end;
 +
  //stop program
 +
  Halt;
 +
  end;
 +
end;
  
  *******************************************************************************}
+
{*********************MAIN PROGRAM*********************************************
 
+
}
   procedure ErrorCheck(AError:longint;ATaskHandle:longint);
+
begin
   var
+
   //prepare data for analog output
    errBuffer:array[0..2048] of char;
+
  for i:=Low(data) to High(data) do data[i]:= 5.0*i/4000.0;
   begin
+
  //create task
    //get error description
+
  DAQmxCreateTask('',@AOTaskHandle);
    if Aerror<>0 then begin
+
   //configure analog output channel
      DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
+
  ErrorCheck(DAQmxCreateAOVoltageChan(AOTaskHandle,'Dev1/ao0','',-10.0,10.0,DAQmx_Val_Volts,Nil),AOTaskHandle);
      writeln(PChar(@ErrBuffer[0]));
+
  //configure clock
    //stop and cleat task
+
  ErrorCheck(DAQmxCfgSampClkTiming(AOTaskHandle,'',1000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,4000),AOTaskHandle);
    if Assigned(@ATaskHandle) then begin
+
   //write data to buffer
      DAQmxStopTask(ATaskHandle);
+
  ErrorCheck(DAQmxWriteAnalogF64(AOTaskHandle,4000,0,10.0,DAQmx_Val_GroupByChannel,data,@writtensamples,Nil),AOTaskHandle);
      DAQmxClearTask(ATaskHandle);
+
  //start task
    end;
+
  ErrorCheck(DAQmxStartTask(AOTaskHandle),AOTaskHandle);
    //stop program
+
  //wait until all samples are generated
    Halt;
+
  ErrorCheck(DAQmxWaitUntilTaskDone(AOTaskHandle,10.0),AOTaskHandle);
    end;
+
  //stop and clear task
 +
  if Assigned(@AOTaskHandle) then begin
 +
    DAQmxStopTask(AOTaskHandle);
 +
    DAQmxClearTask(AOTaskHandle);
 
   end;
 
   end;
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
+
end.
begin
+
</syntaxhighlight>
  //task create
+
 
  ErrorCheck(DAQmxCreateTask('',@DOTaskHandle),DOTaskHandle);
+
===DIGITAL INPUTS/OUTPUTS===
  //digital input port create
+
 
  ErrorCheck(DAQmxCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
+
Most of DAQ cards have two types of digital ports (input/output): correlated and static. Static ports are software timed, correlated are software or hardware timed by the external or internal clock for example couter output signal ('''/Dev1/Ctr0InternalOutput''' - couter0 as clock ). Check the documention to find it, for example NI-PCI6250 have three 8-bit ports: port0 - correlated, port1,port2 - static; NI-PCI6224 two ports: 32-bit port0 - correlated, 8-bit port1 - static.
  //task start
 
  //no need to start task
 
  ErrorCheck(DAQmxStartTask(DOTaskHandle),DOTaskHandle);
 
  //for 32-bit digital port use DAQmxReadDigitalU32 function
 
  //set 1 on all lines of digital port
 
  //change data:=0 to set 0 or use DAQmxResetDevice function to
 
  data:=0;
 
  ErrorCheck(DAQmxWriteDigitalU8(DOTaskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,@data,@written,Nil),DOTaskHandle);
 
  //use DAQmxResetDevice function here to set signal on Low state
 
  writeln('number of written samples: ',written);
 
  //stop and clear task
 
  if DOTaskHandle<>0 then begin
 
    DAQmxStopTask(DOTaskHandle);
 
    DAQmxClearTask(DOTaskHandle);
 
  end;
 
end.
 
  
</syntaxhighlight>
+
Read/Write data from/to 8-bit and 32-bit digital port use an appropriate function '''DAQmxReadDigitalU8''', '''DAQmxWriteDigitalU8''' and '''DAQmxReadDigitalU32''', '''DAQmxWriteDigitalU32'''.
  
====Hardware timed digital outputs with counter output used as source clock====
+
''Different behaviour of collerated port0, when it sets as input, occured under Linux and Windows: software timed works only under Windows, with external clock works under Windows and Linux!!!''
  
To check it connect digital output(s) to oscilloscope or to card analog input.
+
====Software timed digital input ====
<syntaxhighlight lang="pascal">
+
 
program doporttimed;
+
To check it, connected +5V(depend on hardware) to one of available port pins.
 +
 
 +
<syntaxhighlight lang="pascal">
 +
program diport;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 690: Line 733:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmx,SysUtils,StrUtils,Crt
+
   Classes,nidaqmx,SysUtils,StrUtils
 
   { you can add units after this };
 
   { you can add units after this };
 
var
 
var
   DOTaskHandle,CtrTaskHandle:TaskHandle;
+
   DITaskHandle:TaskHandle;
   data:array[0..7] of byte = (1,2,4,8,16,32,64,128);
+
   data:array [0..9] of byte;
   written:longint = 0;
+
  reads:longint = 0;
 +
   totalreads:longint = 0;
 +
  i:longint ;
 
{************Error handling procedure *****************************************
 
{************Error handling procedure *****************************************
 
       Example:
 
       Example:
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
+
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
  
 
   *******************************************************************************}
 
   *******************************************************************************}
Line 721: Line 766:
 
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
 
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
 
begin
 
begin
  {******CREATE COUNTER OUTPUT TO USE IT AS CLOCK FOR DIGITAL PORT OUTPUTS******
+
   //task create
  *******INTERNALLY CONNECTED ON M-SERIES as /Dev1/Ctr0InternalOutput**********}
+
   ErrorCheck(DAQmxCreateTask('',@DITaskHandle),DITaskHandle);
   //create couter task
+
   //digital input port create
   ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
+
   ErrorCheck(DAQmxCreateDIChan(DITaskHandle,'Dev1/port1','',DAQmx_Val_ChanForAllLines),DITaskHandle);
   //create counter output channel
+
  //Start Task
  //Frequency 1000 Hz, duty 0.5
+
  ErrorCheck(DAQmxStartTask(DITaskHandle),DITaskHandle);
   ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
+
  //read 10 samples from 8-bit digital port (for example NI PCI-6250 card port1(pins P1.0-P1.7))
   //timing 1000 samples per second
+
   //for 32-bit digital port use DAQmxReadDigitalU32 function
   ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
+
   ErrorCheck(DAQmxReadDigitalU8(DITaskHandle,10,10.0,DAQmx_Val_GroupByChannel,@data,10,@reads,Nil),DITaskHandle);
   //start task
+
  writeln('number of readed samples: ',reads);
   //start counter task
+
   for i:=0 to 9 do writeln('data [',i,'] = %',IntToBin(data[i],8));
   ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
+
   //stop and clear task
 +
   if DITaskHandle<>0 then begin
 +
    DAQmxStopTask(DITaskHandle);
 +
    DAQmxClearTask(DITaskHandle);
 +
  end;
 +
end.
 +
</syntaxhighlight>
  
  //task create
+
Output example: +5V connected to pin P1.2 port1 on NI-PCI6250 card.
  ErrorCheck(DAQmxCreateTask('',@DOTaskHandle),DOTaskHandle);
+
<syntaxhighlight lang="text">
  //digital input port create
+
number of readed samples: 10
  ErrorCheck(DAQmxCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
+
data [0] = %00000100
  //timing
+
data [1] = %00000100
  //frequency 1000Hz
+
data [2] = %00000100
  ErrorCheck(DAQmxCfgSampClkTiming(DOTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),DOTaskHandle);
+
data [3] = %00000100
  //for 32-bit digital port use DAQmxWriteDigitalU32 function
+
data [4] = %00000100
  //function sets to start task automaticly 3-rd parameter
+
data [5] = %00000100
  //write 8 samples
+
data [6] = %00000100
  ErrorCheck(DAQmxWriteDigitalU8(DOTaskHandle,8,1,10.0,DAQmx_Val_GroupByChannel,data,@written,Nil),DOTaskHandle);
+
data [7] = %00000100
  writeln('number of written samples: ',written);
+
data [8] = %00000100
  //stop and clear task
+
data [9] = %00000100
  DAQmxStopTask(DOTaskHandle);
 
  DAQmxClearTask(DOTaskHandle);
 
  DAQmxStopTask(CtrTaskHandle);
 
  DAQmxClearTask(CtrTaskHandle);
 
end.
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===COUNTER INPUTS/OUTPUTS===
+
====Hardware timed digital input====
 +
 
 +
This example shows using of counter output signal as a clock for digital inputs port for hardware timed acquire data on digital inputs. This feature is supported only for correlated digital port. In this example 8-bit port0 on NI-PCI6250 card is used to check this function.
  
====Pulse generation====
+
To check it, connected +5V(depend on hardware) to one of available pins on correlated digital port.
This example demonstrates pwm generaton with frequency 1000Hz and duty circle 0.5.
 
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
program doporttimed;
+
program diporttimed;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 767: Line 814:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmx,SysUtils,StrUtils,Crt
+
   Classes,nidaqmx,SysUtils,StrUtils
 
   { you can add units after this };
 
   { you can add units after this };
 
var
 
var
CtrTaskHandle:TaskHandle;
+
  DITaskHandle,CtrTaskHandle:TaskHandle;
{************Error handling procedure *****************************************
+
  data:array [0..9] of byte;
 +
  reads:longint = 0;
 +
  totalreads:longint = 0;
 +
  i:longint ;
 +
{************Error handling procedure *****************************************
 
       Example:
 
       Example:
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
+
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
  
 
   *******************************************************************************}
 
   *******************************************************************************}
Line 796: Line 847:
 
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
 
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
 
begin
 
begin
 +
  {******CREATE COUNTER OUTPUT TO USE IT AS CLOCK FOR DIGITAL PORT INPUTS******
 +
  *******INTERNALLY CONNECTED ON M-SERIES as /Dev1/Ctr0InternalOutput**********}
 
   //create couter task
 
   //create couter task
 
   ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
 
   ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
 
   //create counter output channel
 
   //create counter output channel
 
   //Frequency 1000 Hz, duty 0.5
 
   //Frequency 1000 Hz, duty 0.5
   ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
+
   ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,1000,0.5),CtrTaskHandle);
 
   //timing 1000 samples per second
 
   //timing 1000 samples per second
 
   ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
 
   ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
   //start task
+
   //start counter task
 
   ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
 
   ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
 
+
 
   writeln('Press any key to stop generation');
+
  //digital input task create
   repeat
+
  ErrorCheck(DAQmxCreateTask('Digital input task',@DITaskHandle),DITaskHandle);
   until keypressed;
+
  //digital input port create
    
+
  ErrorCheck(DAQmxCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
 +
  //timing use counter output as clock source internally connected
 +
  //as /Dev1/Ctr0InternalOutput
 +
  ErrorCheck(DAQmxCfgSampClkTiming(DITaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000),DITaskHandle);
 +
  //Start digital input Task
 +
  ErrorCheck(DAQmxStartTask(DITaskHandle),DITaskHandle);
 +
  //read 10 samples from 8-bit digital port for example correlated port0
 +
  //for 32-bit digital port use DAQmxReadDigitalU32 function
 +
  ErrorCheck(DAQmxReadDigitalU8(DITaskHandle,10,10.0,DAQmx_Val_GroupByChannel,@data,10,@reads,Nil),DITaskHandle);
 +
   writeln('number of readed samples: ',reads);
 +
  for i:=0 to 9 do writeln('data [',i,'] = %',IntToBin(data[i],8));
 +
   //stop and clear task
 +
   DAQmxStopTask(DITaskHandle);
 +
   DAQmxClearTask(DITaskHandle);
 
   DAQmxStopTask(CtrTaskHandle);
 
   DAQmxStopTask(CtrTaskHandle);
   DAQmxClearTask(CtrTaskHandle);
+
   DAQmxClearTask(CtrTaskHandle);  
 
end.
 
end.
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
====Event counting====
+
Output example: +5V connected to pin P0.5 on port0 on NI-PCI6250 card.
In this example first counter(Dev1/ctr0) is configurated as counter output for frequency generation, second (Dev1/ctr1) as counter input for pulse counting. First couter also used as clock source for second one.  
+
<syntaxhighlight lang="text">
 +
number of readed samples: 10
 +
data [0] = %00100000
 +
data [1] = %00100000
 +
data [2] = %00100000
 +
data [3] = %00100000
 +
data [4] = %00100000
 +
data [5] = %00100000
 +
data [6] = %00100000
 +
data [7] = %00100000
 +
data [8] = %00100000
 +
data [9] = %00100000
 +
</syntaxhighlight>
 +
 
 +
====Software controlled digital output====
 +
 
 +
To check it connect digital output(s) to oscilloscope or to card analog input.
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
program eventcounting;
+
program doportlpi;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 828: Line 909:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmx,SysUtils,StrUtils,Crt
+
   Classes,nidaqmx,SysUtils,StrUtils
 
   { you can add units after this };
 
   { you can add units after this };
 
var
 
var
   CtrOutTaskHandle,CtrInTaskHandle:TaskHandle;
+
   DOTaskHandle:TaskHandle;
  reads:cardinal=0;
+
   data: byte;
   data:array [0..999] of longint;
+
   written:longint = 0;
   i:longint;
 
 
{************Error handling procedure *****************************************
 
{************Error handling procedure *****************************************
 
       Example:
 
       Example:
Line 840: Line 920:
  
 
   *******************************************************************************}
 
   *******************************************************************************}
 +
 
   procedure ErrorCheck(AError:longint;ATaskHandle:longint);
 
   procedure ErrorCheck(AError:longint;ATaskHandle:longint);
 
   var
 
   var
Line 859: Line 940:
 
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
 
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
 
begin
 
begin
  {****************CREATE COUNTER OUTPUT***************************************}
+
   //task create
   //create couter output task
+
   ErrorCheck(DAQmxCreateTask('',@DOTaskHandle),DOTaskHandle);
   ErrorCheck(DAQmxCreateTask('Counter output task',@CtrOutTaskHandle),CtrOutTaskHandle);
+
   //digital input port create
   //create counter output channel
+
   ErrorCheck(DAQmxCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
  //Frequency 1000 Hz, duty 0.5
+
   //task start
   ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrOutTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrOutTaskHandle);
+
   //no need to start task
   //timing 1000 samples per second
+
   ErrorCheck(DAQmxStartTask(DOTaskHandle),DOTaskHandle);
  ErrorCheck(DAQmxCfgImplicitTiming(CtrOutTaskHandle,DAQmx_Val_ContSamps,1000),CtrOutTaskHandle);
+
   //for 32-bit digital port use DAQmxReadDigitalU32 function
   //start counter output task
+
   //set 1 on all lines of digital port
   ErrorCheck(DAQmxStartTask(CtrOutTaskHandle),CtrOutTaskHandle);
+
   //change data:=0 to set 0 or use DAQmxResetDevice function to
 
+
   data:=0;
   {*****************CREATE COUNTER INPUT***************************************}
+
   ErrorCheck(DAQmxWriteDigitalU8(DOTaskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,@data,@written,Nil),DOTaskHandle);
   //create couter output task
+
  //use DAQmxResetDevice function here to set signal on Low state
  ErrorCheck(DAQmxCreateTask('Counter input task',@CtrInTaskHandle),CtrInTaskHandle);
+
   writeln('number of written samples: ',written);
   //create input counter for pulse counting
+
   //stop and clear task
   ErrorCheck(DAQmxCreateCICountEdgesChan(CtrInTaskHandle,'Dev1/ctr1','',DAQmx_Val_Rising,0,DAQmx_Val_CountUp),CtrInTaskHandle);
+
   if DOTaskHandle<>0 then begin
  //timing
+
    DAQmxStopTask(DOTaskHandle);
   ErrorCheck(DAQmxCfgSampClkTiming(CtrInTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),CtrInTaskHandle);
+
    DAQmxClearTask(DOTaskHandle);
  //start counter input task
+
   end;
   ErrorCheck(DAQmxStartTask(CtrInTaskHandle),CtrInTaskHandle);
+
end.
   //counting pulses
+
 
   ErrorCheck(DAQmxReadCounterU32(CtrIntaskHandle,1000,10.0,@data,1000,@reads,Nil),CtrIntaskHandle);
+
</syntaxhighlight>
  writeln('acquired samples: ',reads);
 
   for i:=0 to 10 do writeln('sample[',i,'] = ',data[i]);
 
  
  //stop and clear tasks
+
====Hardware timed digital outputs with counter output used as source clock====
  DAQmxStopTask(CtrInTaskHandle);
 
  DAQmxClearTask(CtrInTaskHandle);
 
  DAQmxStopTask(CtrOutTaskHandle);
 
  DAQmxClearTask(CtrOutTaskHandle);
 
end.
 
</syntaxhighlight>
 
  
===TESTED HARDWARE===
+
To check it connect digital output(s) to oscilloscope or to card analog input.
Examples were tested under Linux 32-bit (kernel 2.6.32) NI-DAQmx 8.0.2 and Windows 7 32-bit NI-DAQmx 14 on cards:
 
 
 
'''NI PCI-6250'''
 
 
 
'''NI PXIe-6612 (Windows only)'''
 
==NI-DAQxmxBase examples==
 
Generally, NI-DAQmxBase is a light version of NI-DAQmx, but this library is '''multiplatform'''. You can use it under all supported operation systems without modification of NI-DAQmxBase function call.
 
 
 
'''Read readme file to check card supported features!!!'''
 
===DEVICE INFO===
 
Functions, which provide device and channel information, are not implemented in this library, yet.
 
 
 
===ANALOG INPUTS/OUTPUTS===
 
====Acquire finite number of samples from one analog channel====
 
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
program aichannel;
+
program doporttimed;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 916: Line 975:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmxbase;
+
   Classes,nidaqmx,SysUtils,StrUtils,Crt
   { you can add units after this }
+
   { you can add units after this };
 
var
 
var
  AITaskHandle: PTaskHandle;
+
  DOTaskHandle,CtrTaskHandle:TaskHandle;
  NiBool:Pnibool;
+
  data:array[0..7] of byte = (1,2,4,8,16,32,64,128);
  reads:longint=0;
+
  written:longint = 0;
  i:byte;
+
{************Error handling procedure *****************************************
   data:array [1..1000] of double;
+
      Example:
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
+
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
var
+
 
  errBuffer:array[0..2048] of char;
+
  *******************************************************************************}
   errMessage:string;
+
 
begin
+
  procedure ErrorCheck(AError:longint;ATaskHandle:longint);
  //get error description
+
  var
  if DAQmxFailed(AError) = niTrue then begin
+
    errBuffer:array[0..2048] of char;
    DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
+
   begin
    writeln(ErrBuffer);
+
    //get error description
  //stop and cleat task
+
    if Aerror<>0 then begin
  if Assigned(ATaskHandle) then begin
+
      DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
       DAQmxBaseStopTask(ATaskHandle);
+
      writeln(PChar(@ErrBuffer[0]));
       DAQmxBaseClearTask(ATaskHandle);
+
    //stop and cleat task
  end;
+
    if Assigned(@ATaskHandle) then begin
  //stop program
+
       DAQmxStopTask(ATaskHandle);
  Halt;
+
       DAQmxClearTask(ATaskHandle);
 +
    end;
 +
    //stop program
 +
    Halt;
 +
    end;
 
   end;
 
   end;
end;
+
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
 
 
 
begin
 
begin
   //create task
+
  {******CREATE COUNTER OUTPUT TO USE IT AS CLOCK FOR DIGITAL PORT OUTPUTS******
   ErrorCheck(DAQmxBaseCreateTask ('', AITaskHandle),AITaskHandle);
+
  *******INTERNALLY CONNECTED ON M-SERIES as /Dev1/Ctr0InternalOutput**********}
   //create analog input channel
+
   //create couter task
   ErrorCheck(DAQmxBaseCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','', DAQmx_Val_RSE,-10, 10,DAQmx_Val_Volts,''),AITaskHandle);
+
   ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
 +
   //create counter output channel
 +
  //Frequency 1000 Hz, duty 0.5
 +
   ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
 +
  //timing 1000 samples per second
 +
  ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
 +
  //start task
 +
  //start counter task
 +
  ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
 +
 
 +
  //task create
 +
  ErrorCheck(DAQmxCreateTask('',@DOTaskHandle),DOTaskHandle);
 +
  //digital input port create
 +
  ErrorCheck(DAQmxCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
 
   //timing
 
   //timing
   //clock frequency 1000 Hz, sample rate 1000 per second
+
   //frequency 1000Hz
  //if you use more than one active channel, generally sample rate = clock frequency/(active analog channles*10);
+
   ErrorCheck(DAQmxCfgSampClkTiming(DOTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),DOTaskHandle);
   ErrorCheck(DAQmxBaseCfgSampClkTiming (AITaskHandle,'OnboardClock',1000,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000),AITaskHandle);
+
   //for 32-bit digital port use DAQmxWriteDigitalU32 function
   //start task
+
  //function sets to start task automaticly 3-rd parameter
  ErrorCheck(DAQmxBaseStartTask(AITaskHandle),AITaskHandle);
+
   //write 8 samples
   //read 1000 samples
+
   ErrorCheck(DAQmxWriteDigitalU8(DOTaskHandle,8,1,10.0,DAQmx_Val_GroupByChannel,data,@written,Nil),DOTaskHandle);
   ErrorCheck(DAQmxBaseReadAnalogF64 (AITaskHandle, 1000, 10.0,DAQmx_Val_GroupByChannel,data,1000,reads,NIBool^),AITaskHandle);
+
   writeln('number of written samples: ',written);
  //acquired sample number
 
   writeln(reads,' samples were acqiured');
 
  //show value of first ten samples
 
  for i:=1 to 10 do writeln('sample[',i,'] = ',data[i]:4:2,' V');
 
 
   //stop and clear task
 
   //stop and clear task
   DAQmxBaseStopTask(AITaskHandle);
+
   DAQmxStopTask(DOTaskHandle);
   DAQmxBaseClearTask(AITaskHandle);
+
   DAQmxClearTask(DOTaskHandle);
 +
  DAQmxStopTask(CtrTaskHandle);
 +
  DAQmxClearTask(CtrTaskHandle);
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
Output example +5V connected to pin 68 on NI PCI-6250
+
 
<syntaxhighlight lang="text">
+
===COUNTER INPUTS/OUTPUTS===
1000 samples were acqiured
+
 
sample[1] = 5.07 V
+
====Pulse generation====
sample[2] = 5.06 V
+
This example demonstrates pwm generaton with frequency 1000Hz and duty circle 0.5.
sample[3] = 5.06 V
 
sample[4] = 5.06 V
 
sample[5] = 5.06 V
 
sample[6] = 5.06 V
 
sample[7] = 5.06 V
 
sample[8] = 5.06 V
 
sample[9] = 5.06 V
 
sample[10] = 5.07 V
 
</syntaxhighlight>
 
 
 
====Continuously acquire samples from three analog inputs====
 
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
program ai3contacq;
+
program doporttimed;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 990: Line 1,052:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmxbase;
+
   Classes,nidaqmx,SysUtils,StrUtils,Crt
   { you can add units after this }
+
   { you can add units after this };
 
var
 
var
  AITaskHandle: PTaskHandle;
+
CtrTaskHandle:TaskHandle;
  NiBool:Pnibool;
+
{************Error handling procedure *****************************************
  reads:longint=0;
+
      Example:
  totalreads:longint=0;
+
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
  i:byte;
+
 
  data:array of double;
+
   *******************************************************************************}
   acqnumsamples:longint;
 
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 
var
 
  errBuffer:array[0..2048] of char;
 
  errMessage:string;
 
begin
 
  //get error description
 
  if DAQmxFailed(AError) = niTrue then begin
 
    DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
 
    writeln(ErrBuffer);
 
  //stop and cleat task
 
  if Assigned(ATaskHandle) then begin
 
      DAQmxBaseStopTask(ATaskHandle);
 
      DAQmxBaseClearTask(ATaskHandle);
 
  end;
 
  //stop program
 
  Halt;
 
   end;
 
end;
 
  
begin
+
   procedure ErrorCheck(AError:longint;ATaskHandle:longint);
   //enter number of total samples for each channel to be acquired
+
   var
  write('Enter a number of samples for each channel to be acquired: ');
+
    errBuffer:array[0..2048] of char;
  readln(acqnumsamples);
+
   begin
  //Set buffer size = length of data array:=number of active channels * sample per channel
+
    //get error description
  Setlength(data,3*1000);
+
    if Aerror<>0 then begin
   //create task
+
      DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
  ErrorCheck(DAQmxBaseCreateTask ('', AITaskHandle),AITaskHandle);
+
      writeln(PChar(@ErrBuffer[0]));
  //create analog input channel - 3 active analog inputs
+
    //stop and cleat task
  ErrorCheck(DAQmxBaseCreateAIVoltageChan(AITaskHandle,'Dev1/ai0:2','', DAQmx_Val_RSE,-10, 10,DAQmx_Val_Volts,''),AITaskHandle);
+
    if Assigned(@ATaskHandle) then begin
   //timing
+
      DAQmxStopTask(ATaskHandle);
  //clock frequency 10000 Hz, sample rate 1000 per second
+
      DAQmxClearTask(ATaskHandle);
  //if you use more than one active channel, generally sample rate = clock frequency/(active analog channles*10);
+
    end;
  ErrorCheck(DAQmxBaseCfgSampClkTiming (AITaskHandle,'OnboardClock',10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),AITaskHandle);
+
    //stop program
  //start task
+
    Halt;
  ErrorCheck(DAQmxBaseStartTask(AITaskHandle),AITaskHandle);
+
     end;
  //read samples
 
  while totalreads<acqnumsamples do begin
 
    ErrorCheck(DAQmxBaseReadAnalogF64(AITaskHandle, 1000, 10.0, DAQmx_Val_GroupByChannel,data,Length(data),reads,NIBool^),AITaskHandle);
 
    totalreads:=totalreads+reads;
 
    writeln('total samples readed for each channel: ',totalreads);
 
    //show first five values for each channel
 
     for i:=0 to 5 do writeln('chan1[',i,'] = ',data[i]:4:2,' V ','chan2[',i,'] = ',data[i+1000]:4:2,' V ','chan3[',i,'] = ',data[i+2000]:4:2,' V ');
 
 
   end;
 
   end;
   //stop and clear task
+
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
   DAQmxBaseStopTask(AITaskHandle);
+
begin
   DAQmxBaseClearTask(AITaskHandle);
+
   //create couter task
end.
+
   ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
</syntaxhighlight>
+
   //create counter output channel
Output example +5V connected to pin 68 on NI PCI-6250
+
  //Frequency 1000 Hz, duty 0.5
<syntaxhighlight lang="text">
+
  ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
Enter a number of samples for each channel to be acquired: 2000
+
  //timing 1000 samples per second
total samples readed for each channel: 1000
+
  ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
chan1[0] = 5.07 V chan2[0] = 0.00 V chan3[0] = 0.03 V
+
  //start task
chan1[1] = 5.06 V chan2[1] = -0.00 V chan3[1] = 0.03 V
+
  ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
chan1[2] = 5.07 V chan2[2] = -0.00 V chan3[2] = 0.02 V
+
 
chan1[3] = 5.07 V chan2[3] = -0.00 V chan3[3] = 0.02 V
+
  writeln('Press any key to stop generation');
chan1[4] = 5.06 V chan2[4] = -0.00 V chan3[4] = 0.02 V
+
  repeat
chan1[5] = 5.06 V chan2[5] = -0.00 V chan3[5] = 0.01 V
+
  until keypressed; 
total samples readed for each channel: 2000
+
 
chan1[0] = 5.06 V chan2[0] = -0.00 V chan3[0] = -0.02 V
+
  DAQmxStopTask(CtrTaskHandle);
chan1[1] = 5.07 V chan2[1] = -0.00 V chan3[1] = -0.02 V
+
  DAQmxClearTask(CtrTaskHandle);
chan1[2] = 5.06 V chan2[2] = -0.00 V chan3[2] = -0.02 V
+
end.
chan1[3] = 5.07 V chan2[3] = -0.00 V chan3[3] = -0.02 V
+
 
chan1[4] = 5.06 V chan2[4] = -0.00 V chan3[4] = -0.02 V
 
chan1[5] = 5.06 V chan2[5] = -0.00 V chan3[5] = -0.02 V
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===DIGITAL INPUTS/OUTPUTS===
+
====Event counting====
Read readme file to check supported card features by NI-DAQmxBase.
+
In this example first counter(Dev1/ctr0) is configurated as counter output for frequency generation, second (Dev1/ctr1) as counter input for pulse counting. First counter also used as clock source for second one.  
 
 
In case of M-series cards, correlated digital input/output is limited to about 100kHz, because DMA data transfer is not supported.
 
  
====Software timed digital input====
 
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
program diport;
+
program eventcounting;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 1,082: Line 1,113:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmxbase,StrUtils
+
   Classes,nidaqmx,SysUtils,StrUtils,Crt
 
   { you can add units after this };
 
   { you can add units after this };
 
var
 
var
   DITaskHandle:PTaskHandle;
+
   CtrOutTaskHandle,CtrInTaskHandle:TaskHandle;
   NiBool:Pnibool;
+
   reads:cardinal=0;
   data:byte;
+
   data:array [0..999] of longint;
   reads:longint=0;
+
   i:longint;
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
+
{************Error handling procedure *****************************************
var
+
      Example:
  errBuffer:array[0..2048] of char;
+
  ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
begin
+
 
  //get error description
+
  *******************************************************************************}
  if DAQmxFailed(AError) = niTrue then begin
+
  procedure ErrorCheck(AError:longint;ATaskHandle:longint);
    DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
+
  var
    writeln(ErrBuffer);
+
    errBuffer:array[0..2048] of char;
  //stop and cleat task
+
  begin
  if Assigned(ATaskHandle) then begin
+
    //get error description
       DAQmxBaseStopTask(ATaskHandle);
+
    if Aerror<>0 then begin
       DAQmxBaseClearTask(ATaskHandle);
+
      DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
  end;
+
      writeln(PChar(@ErrBuffer[0]));
  //stop program
+
    //stop and cleat task
  Halt;
+
    if Assigned(@ATaskHandle) then begin
  end;
+
       DAQmxStopTask(ATaskHandle);
end;
+
       DAQmxClearTask(ATaskHandle);
 +
    end;
 +
    //stop program
 +
    Halt;
 +
    end;
 +
  end;
 +
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
 
begin
 
begin
   //create task
+
  {****************CREATE COUNTER OUTPUT***************************************}
   ErrorCheck(DAQmxBaseCreateTask('', DITaskHandle),DITaskHandle);
+
   //create couter output task
   //create digital input port
+
   ErrorCheck(DAQmxCreateTask('Counter output task',@CtrOutTaskHandle),CtrOutTaskHandle);
   ErrorCheck(DAQmxBaseCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
+
   //create counter output channel
   //start task
+
  //Frequency 1000 Hz, duty 0.5
   ErrorCheck(DAQmxBaseStartTask(DITaskHandle),DITaskHandle);
+
   ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrOutTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrOutTaskHandle);
   //read dat form port
+
  //timing 1000 samples per second
   //use DAQmxBaseReadDigitalU8 for 8 bit port
+
  ErrorCheck(DAQmxCfgImplicitTiming(CtrOutTaskHandle,DAQmx_Val_ContSamps,1000),CtrOutTaskHandle);
   //use DAQmxBaseReadDigitalU32 for 32 bit port
+
   //start counter output task
   ErrorCheck(DAQmxBaseReadDigitalU8(DITaskHandle,1,10.0,DAQmx_Val_GroupByChannel,data,1,reads,NiBool^),DITaskHandle);
+
   ErrorCheck(DAQmxStartTask(CtrOutTaskHandle),CtrOutTaskHandle);
   writeln('digital port value %',IntToBin(data,8));
+
 
   //stop and clear task
+
  {*****************CREATE COUNTER INPUT***************************************}
   DAQmxBaseStopTask(DITaskHandle);
+
   //create couter output task
   DAQmxBaseClearTask(DITaskHandle);
+
  ErrorCheck(DAQmxCreateTask('Counter input task',@CtrInTaskHandle),CtrInTaskHandle);
 +
   //create input counter for pulse counting
 +
   ErrorCheck(DAQmxCreateCICountEdgesChan(CtrInTaskHandle,'Dev1/ctr1','',DAQmx_Val_Rising,0,DAQmx_Val_CountUp),CtrInTaskHandle);
 +
  //timing
 +
  ErrorCheck(DAQmxCfgSampClkTiming(CtrInTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),CtrInTaskHandle);
 +
  //start counter input task
 +
  ErrorCheck(DAQmxStartTask(CtrInTaskHandle),CtrInTaskHandle);
 +
  //counting pulses
 +
   ErrorCheck(DAQmxReadCounterU32(CtrIntaskHandle,1000,10.0,@data,1000,@reads,Nil),CtrIntaskHandle);
 +
   writeln('acquired samples: ',reads);
 +
  for i:=0 to 10 do writeln('sample[',i,'] = ',data[i]);
 +
 
 +
   //stop and clear tasks
 +
  DAQmxStopTask(CtrInTaskHandle);
 +
  DAQmxClearTask(CtrInTaskHandle);
 +
   DAQmxStopTask(CtrOutTaskHandle);
 +
   DAQmxClearTask(CtrOutTaskHandle);
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
Output example: +5V connected to line 1 of 8-bit digital port
 
<syntaxhighlight lang="text">
 
digital port value %00000010
 
</syntaxhighlight>
 
  
====Hardware timed digital input====
+
===TESTED HARDWARE===
 +
Examples were tested under Linux 32-bit (kernel 2.6.32) NI-DAQmx 8.0.2 and Windows 7 32-bit NI-DAQmx 14 on cards:
 +
 
 +
* '''NI PCI-6250'''
 +
* '''NI PCI-6224'''
 +
 
 +
* '''NI PXIe-6612 (Windows only)'''
 +
 
 +
* '''NI USB-6356 (Windows only)'''
 +
 
 +
* '''NI USB-6003 (Windows only)'''
 +
 
 +
==NI-DAQxmxBase examples==
 +
Generally, NI-DAQmxBase is a light version of NI-DAQmx, but this library is '''multiplatform'''. You can use it under all supported operation systems without modification of NI-DAQmxBase function call.
 +
 
 +
'''Read readme file to check card supported features!!!'''
 +
===DEVICE INFO===
 +
Functions, which provide device and channel information, are not implemented in this library, yet.
 +
 
 +
===ANALOG INPUTS/OUTPUTS===
 +
====Acquire finite number of samples from one analog channel====
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
program diporthwtimed;
+
program aichannel;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 1,138: Line 1,207:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmxbase,StrUtils
+
   Classes,nidaqmxbase;
   { you can add units after this };
+
   { you can add units after this }
 
var
 
var
  DITaskHandle,CtrTaskHandle:PTaskHandle;
+
  AITaskHandle: PTaskHandle;
  NiBool:Pnibool;
+
  NiBool:Pnibool;
  data:array of byte;
+
  reads:longint=0;
  reads:longint=0;
+
  i:byte;
  i:longint;
+
  data:array [1..1000] of double;
 
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 
var
 
var
 
   errBuffer:array[0..2048] of char;
 
   errBuffer:array[0..2048] of char;
 +
  errMessage:string;
 
begin
 
begin
 
   //get error description
 
   //get error description
Line 1,163: Line 1,233:
 
   end;
 
   end;
 
end;
 
end;
 +
 
begin
 
begin
 
+
   //create task
  {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
+
   ErrorCheck(DAQmxBaseCreateTask ('', AITaskHandle),AITaskHandle);
   //create counter task
+
   //create analog input channel
   ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
+
   ErrorCheck(DAQmxBaseCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','', DAQmx_Val_RSE,-10, 10,DAQmx_Val_Volts,''),AITaskHandle);
   //create counter output channel
 
  //Frequency 10000 Hz, duty 0.5
 
   ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
 
 
   //timing
 
   //timing
   //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
+
   //clock frequency 1000 Hz, sample rate 1000 per second
  ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
+
   //if you use more than one active channel, generally sample rate = clock frequency/(active analog channles*10);
  //start counter task
+
   ErrorCheck(DAQmxBaseCfgSampClkTiming (AITaskHandle,'OnboardClock',1000,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000),AITaskHandle);
  ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
 
 
 
 
 
  {*******************HW TIMED DIGITAL INPUT***********************************
 
  **********LIMITED TO 10kHz,DMA IS NOT IMPLEMENTED****************************}
 
  //configure buffer for 1000 samples
 
  SetLength(data,1000);
 
   //create task
 
  ErrorCheck(DAQmxBaseCreateTask('', DITaskHandle),DITaskHandle);
 
  //create digital input port
 
  ErrorCheck(DAQmxBaseCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
 
  //timing frequency 10000Hz, 1000 sample per channel
 
   ErrorCheck(DAQmxBaseCfgSampClkTiming(DITaskHandle,'/Dev1/Ctr0InternalOutput',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,10000),DITaskHandle);
 
 
   //start task
 
   //start task
   ErrorCheck(DAQmxBaseStartTask(DITaskHandle),DITaskHandle);
+
   ErrorCheck(DAQmxBaseStartTask(AITaskHandle),AITaskHandle);
   //read dat form port
+
   //read 1000 samples
  //use DAQmxBaseReadDigitalU8 for 8 bit port
+
   ErrorCheck(DAQmxBaseReadAnalogF64 (AITaskHandle, 1000, 10.0,DAQmx_Val_GroupByChannel,data,1000,reads,NIBool^),AITaskHandle);
  //use DAQmxBaseReadDigitalU32 for 32 bit port
+
  //acquired sample number
   ErrorCheck(DAQmxBaseReadDigitalU8(DITaskHandle,10000,10.0,DAQmx_Val_GroupByChannel,data,10000,reads,NiBool^),DITaskHandle);
+
   writeln(reads,' samples were acqiured');
   writeln(reads,' samples were readed');
+
   //show value of first ten samples
   //show first 10 samples
+
   for i:=1 to 10 do writeln('sample[',i,'] = ',data[i]:4:2,' V');
   for i:=0 to 9 do writeln('sample[',i,'] = %',IntToBin(data[i],8));
 
 
   //stop and clear task
 
   //stop and clear task
   DAQmxBaseStopTask(DITaskHandle);
+
   DAQmxBaseStopTask(AITaskHandle);
   DAQmxBaseClearTask(DITaskHandle);
+
   DAQmxBaseClearTask(AITaskHandle);
  DAQmxBaseStopTask(CtrTaskHandle);
 
  DAQmxBaseClearTask(CtrTaskHandle);
 
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
 
+
Output example +5V connected to pin 68 on NI PCI-6250
Output example: +5V connected to line 1 of 8-bit digital port, executed with time command under Linux.
 
 
<syntaxhighlight lang="text">
 
<syntaxhighlight lang="text">
10000 samples were readed                                     
+
1000 samples were acqiured
sample[0] = %00000010                                         
+
sample[1] = 5.07 V
sample[1] = %00000010                                         
+
sample[2] = 5.06 V
sample[2] = %00000010
+
sample[3] = 5.06 V
sample[3] = %00000010
+
sample[4] = 5.06 V
sample[4] = %00000010
+
sample[5] = 5.06 V
sample[5] = %00000010
+
sample[6] = 5.06 V
sample[6] = %00000010
+
sample[7] = 5.06 V
sample[7] = %00000010
+
sample[8] = 5.06 V
sample[8] = %00000010
+
sample[9] = 5.06 V
sample[9] = %00000010
+
sample[10] = 5.07 V
 
 
real    0m4.483s
 
user    0m4.261s
 
sys    0m0.100s
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
====Software timed digital output====
+
====Continuously acquire samples from three analog inputs====
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
program doport;
+
program ai3contacq;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 1,234: Line 1,281:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes,nidaqmxbase,StrUtils,SysUtils
+
   Classes,nidaqmxbase;
   { you can add units after this };
+
   { you can add units after this }
 
var
 
var
  DOTaskHandle,CtrTaskHandle:PTaskHandle;
+
  AITaskHandle: PTaskHandle;
  NiBool:Pnibool;
+
  NiBool:Pnibool;
  data: byte;
+
  reads:longint=0;
  written:longint=0;
+
  totalreads:longint=0;
  i:longint;
+
  i:byte;
 +
  data:array of double;
 +
  acqnumsamples:longint;
 
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 
var
 
var
 
   errBuffer:array[0..2048] of char;
 
   errBuffer:array[0..2048] of char;
 +
  errMessage:string;
 
begin
 
begin
 
   //get error description
 
   //get error description
Line 1,259: Line 1,309:
 
   end;
 
   end;
 
end;
 
end;
 +
 
begin
 
begin
   //write data to buffer, produce digital waveform on all port lines
+
   //enter number of total samples for each channel to be acquired
   data:=255;
+
  write('Enter a number of samples for each channel to be acquired: ');
 +
  readln(acqnumsamples);
 +
   //Set buffer size = length of data array:=number of active channels * sample per channel
 +
  Setlength(data,3*1000);
 
   //create task
 
   //create task
   ErrorCheck(DAQmxBaseCreateTask('', DOTaskHandle),DOTaskHandle);
+
   ErrorCheck(DAQmxBaseCreateTask ('', AITaskHandle),AITaskHandle);
   //create digital input port
+
   //create analog input channel - 3 active analog inputs
   ErrorCheck(DAQmxBaseCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
+
   ErrorCheck(DAQmxBaseCreateAIVoltageChan(AITaskHandle,'Dev1/ai0:2','', DAQmx_Val_RSE,-10, 10,DAQmx_Val_Volts,''),AITaskHandle);
   //use DAQmxBaseWriteDigitalU8 for 8 bit port
+
   //timing
   //use DAQmxBaseWriteDigitalU32 for 32 bit port
+
   //clock frequency 10000 Hz, sample rate 1000 per second
   //set third parametr to 1 to enable autostart or set to 0 and use DAQmxBaseStartTask before
+
   //if you use more than one active channel, generally sample rate = clock frequency/(active analog channles*10);
  //set digital "1"
+
   ErrorCheck(DAQmxBaseCfgSampClkTiming (AITaskHandle,'OnboardClock',10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),AITaskHandle);
   writeln('set digital 1 on all port lines');
+
   //start task
   writeln('sleep 10s');
+
  ErrorCheck(DAQmxBaseStartTask(AITaskHandle),AITaskHandle);
   ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
+
   //read samples
  sleep(10000);
+
  while totalreads<acqnumsamples do begin
  writeln(written,' samples were written');
+
    ErrorCheck(DAQmxBaseReadAnalogF64(AITaskHandle, 1000, 10.0, DAQmx_Val_GroupByChannel,data,Length(data),reads,NIBool^),AITaskHandle);
  //set digital "0"
+
    totalreads:=totalreads+reads;
  writeln('set digital 0 on all port lines');
+
    writeln('total samples readed for each channel: ',totalreads);
  writeln('sleep 10s');
+
    //show first five values for each channel
  sleep(10000);
+
    for i:=0 to 5 do writeln('chan1[',i,'] = ',data[i]:4:2,' V ','chan2[',i,'] = ',data[i+1000]:4:2,' V ','chan3[',i,'] = ',data[i+2000]:4:2,' V ');
  ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
+
   end;
   writeln(written,' samples were written');
 
 
   //stop and clear task
 
   //stop and clear task
   DAQmxBaseStopTask(DOTaskHandle);
+
   DAQmxBaseStopTask(AITaskHandle);
   DAQmxBaseClearTask(DOTaskHandle);
+
   DAQmxBaseClearTask(AITaskHandle);
  DAQmxBaseStopTask(CtrTaskHandle);
 
  DAQmxBaseClearTask(CtrTaskHandle);
 
 
end.
 
end.
 +
</syntaxhighlight>
 +
Output example +5V connected to pin 68 on NI PCI-6250
 +
<syntaxhighlight lang="text">
 +
Enter a number of samples for each channel to be acquired: 2000
 +
total samples readed for each channel: 1000
 +
chan1[0] = 5.07 V chan2[0] = 0.00 V chan3[0] = 0.03 V
 +
chan1[1] = 5.06 V chan2[1] = -0.00 V chan3[1] = 0.03 V
 +
chan1[2] = 5.07 V chan2[2] = -0.00 V chan3[2] = 0.02 V
 +
chan1[3] = 5.07 V chan2[3] = -0.00 V chan3[3] = 0.02 V
 +
chan1[4] = 5.06 V chan2[4] = -0.00 V chan3[4] = 0.02 V
 +
chan1[5] = 5.06 V chan2[5] = -0.00 V chan3[5] = 0.01 V
 +
total samples readed for each channel: 2000
 +
chan1[0] = 5.06 V chan2[0] = -0.00 V chan3[0] = -0.02 V
 +
chan1[1] = 5.07 V chan2[1] = -0.00 V chan3[1] = -0.02 V
 +
chan1[2] = 5.06 V chan2[2] = -0.00 V chan3[2] = -0.02 V
 +
chan1[3] = 5.07 V chan2[3] = -0.00 V chan3[3] = -0.02 V
 +
chan1[4] = 5.06 V chan2[4] = -0.00 V chan3[4] = -0.02 V
 +
chan1[5] = 5.06 V chan2[5] = -0.00 V chan3[5] = -0.02 V
 
</syntaxhighlight>
 
</syntaxhighlight>
  
====Hardware timed digital output====
+
===DIGITAL INPUTS/OUTPUTS===
<syntaxhighlight lang="pascal">
+
Read readme file to check supported card features by NI-DAQmxBase.
program doporthwtimed;
+
 
 +
In case of M-series cards, correlated digital input/output is limited to about 100kHz, because DMA data transfer is not supported.
 +
 
 +
====Software timed digital input====
 +
<syntaxhighlight lang="pascal">
 +
program diport;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 1,302: Line 1,376:
 
   { you can add units after this };
 
   { you can add units after this };
 
var
 
var
   DOTaskHandle,CtrTaskHandle:PTaskHandle;
+
   DITaskHandle:PTaskHandle;
 
   NiBool:Pnibool;
 
   NiBool:Pnibool;
   data:array of byte;
+
   data:byte;
   written:longint=0;
+
   reads:longint=0;
  i:longint;
 
 
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 
var
 
var
Line 1,325: Line 1,398:
 
end;
 
end;
 
begin
 
begin
   {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
+
  //create task
   //create counter task
+
  ErrorCheck(DAQmxBaseCreateTask('', DITaskHandle),DITaskHandle);
   ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
+
  //create digital input port
   //create counter output channel
+
  ErrorCheck(DAQmxBaseCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
   //Frequency 10000 Hz, duty 0.5
+
  //start task
   ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
+
  ErrorCheck(DAQmxBaseStartTask(DITaskHandle),DITaskHandle);
   //timing
+
  //read dat form port
   //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
+
  //use DAQmxBaseReadDigitalU8 for 8 bit port
   ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
+
  //use DAQmxBaseReadDigitalU32 for 32 bit port
   //start counter task
+
  ErrorCheck(DAQmxBaseReadDigitalU8(DITaskHandle,1,10.0,DAQmx_Val_GroupByChannel,data,1,reads,NiBool^),DITaskHandle);
   ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
+
  writeln('digital port value %',IntToBin(data,8));
 +
  //stop and clear task
 +
  DAQmxBaseStopTask(DITaskHandle);
 +
  DAQmxBaseClearTask(DITaskHandle);
 +
end.
 +
</syntaxhighlight>
 +
Output example: +5V connected to line 1 of 8-bit digital port
 +
<syntaxhighlight lang="text">
 +
digital port value %00000010
 +
</syntaxhighlight>
 +
 
 +
====Hardware timed digital input====
 +
<syntaxhighlight lang="pascal">
 +
program diporthwtimed;
 +
 
 +
{$mode objfpc}{$H+}
 +
 
 +
uses
 +
  {$IFDEF UNIX}{$IFDEF UseCThreads}
 +
  cthreads,
 +
  {$ENDIF}{$ENDIF}
 +
  Classes,nidaqmxbase,StrUtils
 +
  { you can add units after this };
 +
var
 +
  DITaskHandle,CtrTaskHandle:PTaskHandle;
 +
  NiBool:Pnibool;
 +
  data:array of byte;
 +
  reads:longint=0;
 +
  i:longint;
 +
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 +
var
 +
  errBuffer:array[0..2048] of char;
 +
begin
 +
  //get error description
 +
  if DAQmxFailed(AError) = niTrue then begin
 +
    DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
 +
    writeln(ErrBuffer);
 +
  //stop and cleat task
 +
  if Assigned(ATaskHandle) then begin
 +
      DAQmxBaseStopTask(ATaskHandle);
 +
      DAQmxBaseClearTask(ATaskHandle);
 +
  end;
 +
  //stop program
 +
  Halt;
 +
  end;
 +
end;
 +
begin
 +
 
 +
   {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
 +
   //create counter task
 +
   ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
 +
   //create counter output channel
 +
   //Frequency 10000 Hz, duty 0.5
 +
   ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
 +
   //timing
 +
   //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
 +
   ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
 +
   //start counter task
 +
   ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
 +
 
 +
 
 
   {*******************HW TIMED DIGITAL INPUT***********************************
 
   {*******************HW TIMED DIGITAL INPUT***********************************
 
   **********LIMITED TO 10kHz,DMA IS NOT IMPLEMENTED****************************}
 
   **********LIMITED TO 10kHz,DMA IS NOT IMPLEMENTED****************************}
   //configure buffer for 1000 samples
+
  //configure buffer for 1000 samples
   SetLength(data,1000);
+
  SetLength(data,1000);
   //write data to buffer, produce digital waveform on all port lines
+
  //create task
   for i:=0 to 999 do if (i mod 2 = 0) then data[i]:=255;
+
  ErrorCheck(DAQmxBaseCreateTask('', DITaskHandle),DITaskHandle);
   //create task
+
  //create digital input port
   ErrorCheck(DAQmxBaseCreateTask('', DOTaskHandle),DOTaskHandle);
+
  ErrorCheck(DAQmxBaseCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
   //create digital input port
+
  //timing frequency 10000Hz, 1000 sample per channel
   ErrorCheck(DAQmxBaseCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
+
  ErrorCheck(DAQmxBaseCfgSampClkTiming(DITaskHandle,'/Dev1/Ctr0InternalOutput',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,10000),DITaskHandle);
   //timing frequency 10000Hz, 1000 sample per channel
+
  //start task
   ErrorCheck(DAQmxBaseCfgSampClkTiming(DOTaskHandle,'/Dev1/Ctr0InternalOutput',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),DOTaskHandle);
+
  ErrorCheck(DAQmxBaseStartTask(DITaskHandle),DITaskHandle);
   //use DAQmxBaseWriteDigitalU8 for 8 bit port
+
  //read dat form port
   //use DAQmxBaseWriteDigitalU32 for 32 bit port
+
  //use DAQmxBaseReadDigitalU8 for 8 bit port
   //set third parametr to 1 to enable autostart or set to 0 and use DAQmxBaseStartTask before
+
  //use DAQmxBaseReadDigitalU32 for 32 bit port
   ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
+
  ErrorCheck(DAQmxBaseReadDigitalU8(DITaskHandle,10000,10.0,DAQmx_Val_GroupByChannel,data,10000,reads,NiBool^),DITaskHandle);
   writeln(written,' samples were written');
+
  writeln(reads,' samples were readed');
   //stop and clear task
+
  //show first 10 samples
   DAQmxBaseStopTask(DOTaskHandle);
+
  for i:=0 to 9 do writeln('sample[',i,'] = %',IntToBin(data[i],8));
   DAQmxBaseClearTask(DOTaskHandle);
+
  //stop and clear task
   DAQmxBaseStopTask(CtrTaskHandle);
+
  DAQmxBaseStopTask(DITaskHandle);
   DAQmxBaseClearTask(CtrTaskHandle);
+
  DAQmxBaseClearTask(DITaskHandle);
end.
+
  DAQmxBaseStopTask(CtrTaskHandle);
</syntaxhighlight>
+
  DAQmxBaseClearTask(CtrTaskHandle);
 
+
end.
===COUNTER INPUTS/OUTPUTS===
+
</syntaxhighlight>
Counter input of M-series cards is limited to computer speed.
+
 
 +
Output example: +5V connected to line 1 of 8-bit digital port, executed with time command under Linux.
 +
<syntaxhighlight lang="text">
 +
10000 samples were readed                                     
 +
sample[0] = %00000010                                         
 +
sample[1] = %00000010                                         
 +
sample[2] = %00000010
 +
sample[3] = %00000010
 +
sample[4] = %00000010
 +
sample[5] = %00000010
 +
sample[6] = %00000010
 +
sample[7] = %00000010
 +
sample[8] = %00000010
 +
sample[9] = %00000010
 +
 
 +
real    0m4.483s
 +
user    0m4.261s
 +
sys    0m0.100s
 +
</syntaxhighlight>
 +
 
 +
====Software timed digital output====
 +
<syntaxhighlight lang="pascal">
 +
program doport;
 +
 
 +
{$mode objfpc}{$H+}
 +
 
 +
uses
 +
  {$IFDEF UNIX}{$IFDEF UseCThreads}
 +
  cthreads,
 +
  {$ENDIF}{$ENDIF}
 +
  Classes,nidaqmxbase,StrUtils,SysUtils
 +
  { you can add units after this };
 +
var
 +
  DOTaskHandle,CtrTaskHandle:PTaskHandle;
 +
  NiBool:Pnibool;
 +
  data: byte;
 +
  written:longint=0;
 +
  i:longint;
 +
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 +
var
 +
  errBuffer:array[0..2048] of char;
 +
begin
 +
  //get error description
 +
  if DAQmxFailed(AError) = niTrue then begin
 +
    DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
 +
    writeln(ErrBuffer);
 +
  //stop and cleat task
 +
  if Assigned(ATaskHandle) then begin
 +
      DAQmxBaseStopTask(ATaskHandle);
 +
      DAQmxBaseClearTask(ATaskHandle);
 +
  end;
 +
  //stop program
 +
  Halt;
 +
  end;
 +
end;
 +
begin
 +
  //write data to buffer, produce digital waveform on all port lines
 +
  data:=255;
 +
  //create task
 +
  ErrorCheck(DAQmxBaseCreateTask('', DOTaskHandle),DOTaskHandle);
 +
  //create digital input port
 +
  ErrorCheck(DAQmxBaseCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
 +
  //use DAQmxBaseWriteDigitalU8 for 8 bit port
 +
  //use DAQmxBaseWriteDigitalU32 for 32 bit port
 +
  //set third parametr to 1 to enable autostart or set to 0 and use DAQmxBaseStartTask before
 +
  //set digital "1"
 +
  writeln('set digital 1 on all port lines');
 +
  writeln('sleep 10s');
 +
  ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
 +
  sleep(10000);
 +
  writeln(written,' samples were written');
 +
  //set digital "0"
 +
  writeln('set digital 0 on all port lines');
 +
  writeln('sleep 10s');
 +
  sleep(10000);
 +
  ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
 +
  writeln(written,' samples were written');
 +
  //stop and clear task
 +
  DAQmxBaseStopTask(DOTaskHandle);
 +
  DAQmxBaseClearTask(DOTaskHandle);
 +
  DAQmxBaseStopTask(CtrTaskHandle);
 +
  DAQmxBaseClearTask(CtrTaskHandle);
 +
end.
 +
</syntaxhighlight>
 +
 
 +
====Hardware timed digital output====
 +
Digital output generation frequency is limited to ~100kHz, because DMA is not supported by the driver .
 +
<syntaxhighlight lang="pascal">
 +
program doporthwtimed;
 +
 
 +
{$mode objfpc}{$H+}
 +
 
 +
uses
 +
  {$IFDEF UNIX}{$IFDEF UseCThreads}
 +
  cthreads,
 +
  {$ENDIF}{$ENDIF}
 +
  Classes,nidaqmxbase,StrUtils
 +
  { you can add units after this };
 +
var
 +
  DOTaskHandle,CtrTaskHandle:PTaskHandle;
 +
  NiBool:Pnibool;
 +
  data:array of byte;
 +
  written:longint=0;
 +
  i:longint;
 +
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 +
var
 +
  errBuffer:array[0..2048] of char;
 +
begin
 +
  //get error description
 +
  if DAQmxFailed(AError) = niTrue then begin
 +
    DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
 +
    writeln(ErrBuffer);
 +
  //stop and cleat task
 +
  if Assigned(ATaskHandle) then begin
 +
      DAQmxBaseStopTask(ATaskHandle);
 +
      DAQmxBaseClearTask(ATaskHandle);
 +
  end;
 +
  //stop program
 +
  Halt;
 +
  end;
 +
end;
 +
begin
 +
  {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
 +
  //create counter task
 +
  ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
 +
  //create counter output channel
 +
  //Frequency 10000 Hz, duty 0.5
 +
  ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
 +
  //timing
 +
  //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
 +
  ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
 +
  //start counter task
 +
  ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
 +
  {*******************HW TIMED DIGITAL INPUT***********************************
 +
  **********LIMITED TO 10kHz,DMA IS NOT IMPLEMENTED****************************}
 +
   //configure buffer for 1000 samples
 +
   SetLength(data,1000);
 +
   //write data to buffer, produce digital waveform on all port lines
 +
   for i:=0 to 999 do if (i mod 2 = 0) then data[i]:=255;
 +
   //create task
 +
   ErrorCheck(DAQmxBaseCreateTask('', DOTaskHandle),DOTaskHandle);
 +
   //create digital input port
 +
   ErrorCheck(DAQmxBaseCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
 +
   //timing frequency 10000Hz, 1000 sample per channel
 +
   ErrorCheck(DAQmxBaseCfgSampClkTiming(DOTaskHandle,'/Dev1/Ctr0InternalOutput',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),DOTaskHandle);
 +
   //use DAQmxBaseWriteDigitalU8 for 8 bit port
 +
   //use DAQmxBaseWriteDigitalU32 for 32 bit port
 +
   //set third parametr to 1 to enable autostart or set to 0 and use DAQmxBaseStartTask before
 +
   ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
 +
   writeln(written,' samples were written');
 +
   //stop and clear task
 +
   DAQmxBaseStopTask(DOTaskHandle);
 +
   DAQmxBaseClearTask(DOTaskHandle);
 +
   DAQmxBaseStopTask(CtrTaskHandle);
 +
   DAQmxBaseClearTask(CtrTaskHandle);
 +
end.
 +
</syntaxhighlight>
 +
 
 +
===COUNTER INPUTS/OUTPUTS===
 +
Counter input of M-series cards is limited to computer speed.
 +
====COUNTER OUTPUT====
 +
Counter output can be timed by software or hardware.
 +
 
 +
Example demontrate how to use couter ouput as frequency generator(clock signal for other hardware) or as basic pwm regulation.
 +
 
 +
In this example counter output is hardware timed.
 +
<syntaxhighlight lang="pascal">
 +
program ctrout;
 +
 
 +
{$mode objfpc}{$H+}
 +
 
 +
uses
 +
  {$IFDEF UNIX}{$IFDEF UseCThreads}
 +
  cthreads,
 +
  {$ENDIF}{$ENDIF}
 +
  Classes,nidaqmxbase,StrUtils,SysUtils
 +
  { you can add units after this };
 +
var
 +
  CtrTaskHandle:PTaskHandle;
 +
  NiBool:Pnibool;
 +
  data:array of byte;
 +
  reads:longint=0;
 +
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 +
var
 +
  errBuffer:array[0..2048] of char;
 +
begin
 +
  //get error description
 +
  if DAQmxFailed(AError) = niTrue then begin
 +
    DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
 +
    writeln(ErrBuffer);
 +
  //stop and cleat task
 +
  if Assigned(ATaskHandle) then begin
 +
      DAQmxBaseStopTask(ATaskHandle);
 +
      DAQmxBaseClearTask(ATaskHandle);
 +
  end;
 +
  //stop program
 +
  Halt;
 +
  end;
 +
end;
 +
begin
 +
 
 +
  {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
 +
  //create counter task
 +
  ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
 +
  //create counter output channel
 +
  //Frequency 10000 Hz, duty 0.5
 +
  ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
 +
  //timing
 +
  //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
 +
  ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
 +
  //start counter task
 +
  ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
 +
  //generate frequency signal for 10 seconds
 +
  sleep(10000);
 +
  DAQmxBaseStopTask(CtrTaskHandle);
 +
  DAQmxBaseClearTask(CtrTaskHandle);
 +
end.
 +
</syntaxhighlight>
 +
 
 +
====COUNTER INPUT====
 +
Counter input is only software operated. It is limited by hardware driver.
 +
<syntaxhighlight lang="pascal">
 +
program ctrin;
 +
 
 +
{$mode objfpc}{$H+}
 +
 
 +
uses
 +
  {$IFDEF UNIX}{$IFDEF UseCThreads}
 +
  cthreads,
 +
  {$ENDIF}{$ENDIF}
 +
  Classes,nidaqmxbase,StrUtils,SysUtils,Crt
 +
  { you can add units after this };
 +
var
 +
  CtrInTaskHandle:PTaskHandle;
 +
  NiBool:Pnibool;
 +
  data:dword=0;
 +
  reads:longint=0;
 +
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
 +
var
 +
  errBuffer:array[0..2048] of char;
 +
begin
 +
  //get error description
 +
  if DAQmxFailed(AError) = niTrue then begin
 +
    DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
 +
    writeln(ErrBuffer);
 +
  //stop and cleat task
 +
  if Assigned(ATaskHandle) then begin
 +
      DAQmxBaseStopTask(ATaskHandle);
 +
      DAQmxBaseClearTask(ATaskHandle);
 +
  end;
 +
  //stop program
 +
  Halt;
 +
  end;
 +
end;
 +
begin
 +
  {*****************CREATE COUNTER INPUT***************************************}
 +
  //create couter input task
 +
  ErrorCheck(DAQmxBaseCreateTask('Counter input task',CtrInTaskHandle),CtrInTaskHandle);
 +
  //create input counter for pulse counting
 +
  ErrorCheck(DAQmxBaseCreateCICountEdgesChan(CtrInTaskHandle,'Dev1/ctr1','',DAQmx_Val_Rising,0,DAQmx_Val_CountUp),CtrInTaskHandle);
 +
  //timing
 +
  //ErrorCheck(DAQmxBaseCfgSampClkTiming(CtrInTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),CtrInTaskHandle);
 +
  //start counter input task
 +
  ErrorCheck(DAQmxBaseStartTask(CtrInTaskHandle),CtrInTaskHandle);
 +
  //counting pulses
 +
  writeln('press any key to stop counting');
 +
  repeat
 +
    ErrorCheck(DAQmxBaseReadCounterU32(CtrIntaskHandle,1,10.0,data,1,reads,NiTrue),CtrIntaskHandle);
 +
    writeln('counter value: ',data);
 +
  until keypressed;
 +
  //clear and stop task
 +
  DAQmxBaseStopTask(CtrInTaskHandle);
 +
  DAQmxBaseClearTask(CtrInTaskHandle);
 +
end.
 +
</syntaxhighlight>
 +
 
 +
===TESTED HARDWARE===
 +
Examples were tested under Scientific Linux 6.4, Mageia 2 32-bit and Windows 32-bit and should work under MacOS ('''need test''') on cards:
 +
* '''NI PCI-6250'''
 +
* '''NI PCI-6224'''
 +
* '''NI USB-6356''' (Windows only)
  
===TESTED HARDWARE===
 
 
[[Category:Hardware]]
 
[[Category:Hardware]]
 +
[[Category:Measuring and Instrumentation]]

Latest revision as of 11:31, 23 December 2019

INTRODUCTION

National Instruments produce a wide range of DAQ cards, which are generally used for acquiring and generating signals.

These cards usually have a few analog inputs/outputs, digital inputs/outputs, counters and a frequency generator with hardware/software timing. Exact features (type, number, parameters) depends on the card type.

NIDAQmxBase.pas and NIDAQmx.pas are provided pascal bindings to National Instruments libraries and enable control of NI DAQ cards from programs written in Free Pascal.

What National Instruments Hardware is supported

Supported hardware list by NI-DAQmx and NI-DAQ Driver for different operating systems.

NI-DAQmxBase library

NI-DAQmxBase library or driver is multiplatform library for Windows (Windows XP 32 bit, Windows 7 32/64 bit, Windows Vista 32/64 bit, Windows 8 32/64 bit), macOS 32/64 bit and Linux 32/64 bit (SUSE, Scientific Linux, RedHat, CentOS), but doesn't implement all device features. For example, digital input/output ports speed is limited by computer speed ~100kHz, because DMA data transfer is not supported.

Download library from here. Read readme file to find the list of supported hardware and hardware features.

  Latest Linux version 15.0 supports 64-bit OS, but you still need to install some 32-bit library. 
  
  LIST OF LIBRARIES:

  compat-libstdc++.i686
  expat.i686
  glibc.i686
  glibc-devel.i686
  libdrm.i686
  libgcc.i686
  libselinux.i686
  libstdc++.i686
  libX11.i686
  libXau.i686
  libxcb.i686
  libXdamage.i686
  libXext.i686
  libXinerama.i686
  libXfixes.i686
  libXxf86vm.i686
  mesa-dri-drivers.i686
  mesa-libGL.i686
  nss-softokn-freebl.i686
  zlib.i686

NI-DAQmx library

The NI-DAQmx library is only available for Windows 7 (SP1) 32/64 bit, Windows 8.1 32/64 bit, Windows 10 32/64 bit, Windows Embedded Standard 7 (SP1), Windows Server 2008 R2 (SP1) 32/64 bit). Download here)

Read readme file to find the list of supported hardware and hardware features.

HOW TO IDENTIFY PRESENT HARDWARE

To get list of devices present in your system Under Linux operation system use

1) nilsdev utility with NIDAQmx driver installed,
2) lsdaq utility with NIDAQmxBase driver installed.

Under Windows use NIMAX utility to get device list or set device alias etc.

Library documentation

You can find description of functions and properties in NI-DAQmx and NI-DAQmx Base C reference Help:

PASCAL bindings

Your can download pascal bindings nidaqmxbase.pas and nidaqmx.pas in this forum thread [1] or as a part of the LazMer project.

FUNCTION CALLING

Generally, when you need to acquire or gerenate data, call functions from nidaqmx.pas as follow

1. Create task: DAQmxCreateTask
2. Channel create: 
   a)DAQmxCreateDIChan/DAQmxCreateDOChan (digital input(s)/output(s)) 
   b)DAQmxCreateAIVoltageChan/DAQmxCreateAOVoltageChan (analog input(s)/output(s))
3. Set timing if you need hardware timimg: DAQmxCfgSamplClkTiming
4. Start task: DAQmxStartTask
5. Read or write data from/to channel: 
   a)read data from digital port: DAQmxReadDigitalU8(8-bit port),DAQmxReadDigitalU32 (32-bit port),
   b)write data to digital port:  DAQmxWriteDigitalU8(8-bit port),DAQmxWriteDigitalU32 (32-bit port), 
   c)read data from analog input(s): DAQmxReadAnalogF64,
   d)write data to analog output(s): DAQmxWriteAnalogF64.
6. Do job
7. End of program - stop and clear task: DAQmxStopTask and DAQmxClearTask

For error handling create function like ErrorCheck.

from nidaqmxbase.pas as follow

1. Create task: DAQmxBaseCreateTask
2. Channel create: 
   a)DAQmxBaseCreateDIChan/DAQmxBaseCreateDOChan (digital input(s)/output(s)) 
   b)DAQmxBaseCreateAIVoltageChan/DAQmxBaseCreateAOVoltageChan (analog input(s)/output(s))
3. Set timing if you need hardware timimg: DAQmxBaseCfgSamplClkTiming
4. Start task: DAQmxBaseStartTask
5. Read or write data from/to channel: 
   a)read data from digital port: DAQmxBaseReadDigitalU8(8-bit port),DAQmxBaseReadDigitalU32 (32-bit port),
   b)write data to digital port:  DAQmxBaseWriteDigitalU8(8-bit port),DAQmxBaseWriteDigitalU32 (32-bit port), 
   c)read data from analog input(s): DAQmxBaseReadAnalogF64,
   d)write data to analog output(s): DAQmxBaseWriteAnalogF64.
6. Do job
7. End of program - stop and clear task: DAQmxBaseStopTask and DAQmxBaseClearTask

For error handling create function like ErrorCheck.
 Probably, some examples need to add @ before variable, which use as function parameter!!!

NI-DAQmx examples

DEVICE INFO

Get device list

You can check device list names using NI MAX program under Windows or nilsdev utility under Linux.

program devicelist;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx,SysUtils
  { you can add units after this };
var
  devicenames:array of Char;
  infostr:string;
  DeviceNamesList:TStringList;
  buffersize:longint;
  product_type:array of char;
  devserialnum,is_simulated:longint;
  is_simulated_str:string;
  i:byte;
begin
  DeviceNamesList:=TStringList.Create;
  try
     {**************************************************************************
                      Get device names present in the system
     **************************************************************************}
     //get buffer size or length of string of device list
     buffersize:=DAQmxGetSystemInfoAttribute(DAQmx_Sys_DevNames,devicenames[0],[0]);
     //set array of Char lenght
     if Buffersize<>0 then begin
       writeln('-------------------------------------------------------------');
       writeln('|Device name | Product Type | # Serial number | Is Simulated?');
       writeln('-------------------------------------------------------------');
       SetLength(devicenames,buffersize);
       //get the device list
       DAQmxGetSystemInfoAttribute(DAQmx_Sys_DevNames,devicenames[0],[buffersize]);
       //convert it to string: names are separated by comma
       SetString(infostr,PChar(@devicenames[0]),buffersize);
       //add names to TStringList
       DeviceNamesList.CommaText:=infostr;
       {************************************************************************
                              Get Product info
        ***********************************************************************}
       for i:=0 to DeviceNamesList.Count-1 do begin
          //get buffer size or length of string of product type
          buffersize:=DAQmxGetDeviceAttribute(@DeviceNamesList.Strings[i][1],DAQmx_Dev_ProductType,Nil);
          //set lenght of array of char
          SetLength(product_type,buffersize);
          //get product type info
          DAQmxGetDeviceAttribute(@DeviceNamesList.Strings[i][1],DAQmx_Dev_ProductType,product_type[0],[buffersize]);
          {***********************************************************************
                            Get Serial Number
          **********************************************************************}
          DAQmxGetDeviceAttribute(@DeviceNamesList.Strings[i][1],DAQmx_Dev_SerialNum,devserialnum,[1]);
          //DeviceInfoGrid.Cells[3,i+1]:=IntToHex(devserialnum,8);
          {***********************************************************************
                             Is simulated?
          ***********************************************************************}
          DAQmxGetDeviceAttribute(@DeviceNamesList.Strings[i][1],DAQmx_Dev_IsSimulated,is_simulated,[1]);
          if is_simulated = 0 then is_simulated_str:='No'
          else is_simulated_str:='Yes';
          //Show info
          writeln('| ',DeviceNamesList.Strings[i],' | ',PChar(@product_type[0]),' | $',IntToHex(devserialnum,8),' |',is_simulated_str);
      end;
  end
  else writeln('any device found');
  finally
     DeviceNamesList.Free;
  end;
end.

Output example

-------------------------------------------------------------
|Device name | Product Type | # Serial number | Is Simulated?
-------------------------------------------------------------
| Dev1 | PCI-6250 | $018D0B90 |No

Get channel names

program chaninfo;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx
  { you can add units after this };
var
  buffersize,infotype:longint;
  channelnames:array of char;
  MsgChannelNames:array [0..255] of char;
  MsgNoChannelsText:array [0..255] of char;
  channeltype:byte;
  DeviceName:string;
begin
 {**********INPUT Device name and interested channel type **********************
  **********WITHOUT CHEKING IF DEVICE EXITS IN THE SYSTEM**********************}
  write('Enter device name, for example Dev1, Dev2 etc.: ');
  readln(Devicename);
  writeln('0 - analog inputs');
  writeln('1 - analog outputs');
  writeln('2 - digital inputs');
  writeln('3 - digital outputs');
  writeln('4 - counter inputs');
  writeln('5 - counter outputs');
  write('choose the number of required channel type:');
  readln(channeltype);
  {**********CHANNEL TYPE CHOSEN**********************************************}
  case channeltype of
  {********************ANALOG INPUTS NAMES*************************************}
  0: begin
      infotype:=DAQmx_Dev_AI_PhysicalChans;
      MsgChannelNames:='Analog input names';
      MsgNoChannelsText:='There are no analog inputs';
  end;
  {********************ANALOG OUTPUTS NAMES************************************}
  1: begin
      infotype:=DAQmx_Dev_AO_PhysicalChans;
      MsgChannelNames:='Analog output names';
      MsgNoChannelsText:='There are no analog outputs';
  end;
  {********************DIGITAL INPUT PORTS NAMES*******************************}
  2: begin
      infotype:=DAQmx_Dev_DI_Ports;
      MsgChannelNames:='Digital input ports';
      MsgNoChannelsText:='There are no digital input ports';
  end;
  {********************DIGITAL OUTPUT PORTS NAMES******************************}
  3:begin
     infotype:=DAQmx_Dev_DO_Ports;
     MsgChannelNames:='Digital output ports';
     MsgNoChannelsText:='There are no digital output ports';
  end;
  {********************COUNTER INPUT  NAMES******************************}
  4:begin
     infotype:= DAQmx_Dev_CI_PhysicalChans;
     MsgChannelNames:='Digital counter inputs';
     MsgNoChannelsText:='There are no counter inputs ';
  end;
  {********************COUNTER OUTPUT  NAMES******************************}
  5:begin
     infotype:= DAQmx_Dev_CO_PhysicalChans;
     MsgChannelNames:='Digital counter outputs';
     MsgNoChannelsText:='There are no counter outputs ';
  end;
 end;
{************GET CHANNEL NAMES*********************************************}
 if (channeltype>=0) and (channeltype<6) then begin
         //get buffer size or length of channelnames
         buffersize:=DAQmxGetDeviceAttribute(@DeviceName[1],infotype,Nil);
         if buffersize<>0 then begin
           SetLength(channelnames,buffersize);
           //get analog channel names separated by comma
           DAQmxGetDeviceAttribute(@DeviceName[1],infotype,channelnames[0],[buffersize]);
           //show info
           writeln(MsgChannelNames+': '+PChar(@channelnames[0]));
         end
         else writeln(MsgNoChannelsText);
  end;
end.

Output example

Enter device name, for example Dev1, Dev2 etc.: Dev1
0 - analog inputs                                   
1 - analog outputs                                  
2 - digital inputs                                  
3 - digital outputs                                 
4 - counter inputs                                  
5 - counter outputs                                 
choose the number of required channel type:0        
Analog input names: Dev1/ai0, Dev1/ai1, Dev1/ai2, Dev1/ai3, Dev1/ai4, Dev1/ai5, Dev1/ai6, Dev1/ai7, Dev1/ai8, Dev1/ai9, Dev1/ai10, Dev1/ai11, Dev1/ai12, Dev1/ai13, Dev1/ai14, Dev1/ai15

ANALOG INPUTS/OUTPUTS

Acquire finite number of samples from one analog input

program aichan;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, nidaqmx
  { you can add units after this };
var
  AITaskHandle:TaskHandle;
  data:array[1..1000] of double;
  reads,i:longint;

{************Error handling procedure *****************************************
    Example:
 ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);

*******************************************************************************}

procedure ErrorCheck(AError:longint;ATaskHandle:longint);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if Aerror<>0 then begin
     DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
     writeln(PChar(@ErrBuffer[0]));
   //stop and cleat task
   if Assigned(@ATaskHandle) then begin
     DAQmxStopTask(ATaskHandle);
     DAQmxClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;
{*********************MAIN PROGRAM*********************************************
 ******************* without error handling************************************}
begin
  //create task
  DAQmxCreateTask('',@AITaskHandle);
  //create analog input channel Dev1/ai0 (activate it)
  //voltage range -10 - 10
  DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL);
  //set timing
  //Sample rate = 10000 (10 kHz), sample per channel =1000
  //acquire finite samples (1000 samples) defined by DAQmx_Val_FiniteSamps
  DAQmxCfgSampClkTiming(AITaskHandle,'OnboardClock',10000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000);
  //start task
  DAQmxStartTask(AITaskHandle);
  //acquire 1000 samples
  DAQmxReadAnalogF64(AITaskHandle,1000,10.0,DAQmx_Val_GroupByChannel,@data[1],1000,@reads,NIL);
  //show first 10 samples
  writeln(reads,' samples were acquired');
  writeln('');
  writeln('Value of first 10 samples');
  for i:=1 to 10 do writeln('sample[',i,'] = ',data[i]:4:2,' V');
  //stop and clear task
  DAQmxStopTask(AITaskHandle);
  DAQmxClearTask(AITaskHandle);
end.

Output example

1000 samples were acquired

Value of first 10 samples
sample[1] = 0.23 V
sample[2] = 0.23 V
sample[3] = 0.23 V
sample[4] = 0.23 V
sample[5] = 0.23 V
sample[6] = 0.23 V
sample[7] = 0.23 V
sample[8] = 0.23 V
sample[9] = 0.23 V
sample[10] = 0.23 V

Continuously acquire samples from three analog inputs

program multiaichannel;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, nidaqmx,crt
  { you can add units after this };
var
  AITaskHandle:TaskHandle;
  data:array of double;
  reads:longint;
  totalsamplereads:longint=0;
  i:longint;

{************Error handling procedure *****************************************
    Example:
 ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);

*******************************************************************************}

procedure ErrorCheck(AError:longint;ATaskHandle:longint);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if Aerror<>0 then begin
     DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
     writeln(PChar(@ErrBuffer[0]));
   //stop and cleat task
   if Assigned(@ATaskHandle) then begin
     DAQmxStopTask(ATaskHandle);
     DAQmxClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;
{*********************MAIN PROGRAM*********************************************
 ******************* without error handling************************************}
begin
  //Set buffer size for data acquiring, sample per channel 1000
  //buffer size(data -array variable) = 3 channel * 1000 samples per channel
  Setlength(data,3*1000);
  //create task
  DAQmxCreateTask('',@AITaskHandle);
  //create analog input channel Dev1/ai0:2 (activate 3 channels)
  //voltage range -10 - 10
  DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0:2','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL);
  //set timing
  //Sample rate = 10000 (10 kHz), sample per channel =1000
  //acquire finite samples (1000 samples) defined by DAQmx_Val_Cont_Samps
  DAQmxCfgSampClkTiming(AITaskHandle,'OnboardClock',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000);
  //start task
  DAQmxStartTask(AITaskHandle);
  //acquire 10000 samples for each channel
  while totalsamplereads<10000 do begin
    //1000- sample rate, 3000 - buffer size(data -array variable) = 3 channel * 1000 samples per channel
    DAQmxReadAnalogF64(AITaskHandle,1000,10.0,DAQmx_Val_GroupByChannel,@data[0],3000,@reads,NIL);
    totalsamplereads:=totalsamplereads+reads;
    writeln('aquired number of samples: ',totalsamplereads);
  end;
  //show first 10 samples from last 1000 samples acquired from each channel
  writeln('');
  writeln('Value of first 10 samples of last 1000 samples for each channel');
  writeln('| chan0 |  chan1 |  chan2 | ');
  for i:= 0 to 9 do writeln('|',data[i]:5:2,' V| ',data[i+1000]:5:2,' V| ',data[i+2000]:5:2,' V|');
  //stop and clear task
  DAQmxStopTask(AITaskHandle);
  DAQmxClearTask(AITaskHandle);
end.

Output example

acquired number of samples: 1000                                
aquired number of samples: 2000                                
acquired number of samples: 3000                                
acquired number of samples: 4000                                
acquired number of samples: 5000                                
acquired number of samples: 6000                                
acquired number of samples: 7000                                
acquired number of samples: 8000                                
acquired number of samples: 9000                                
acquired number of samples: 10000

Value of first 10 samples of last 1000 samples for each channel
| chan0 |  chan1 |  chan2 |
| 5.07 V|  5.07 V|  5.06 V|
| 5.07 V|  5.07 V|  5.06 V|
| 5.07 V|  5.06 V|  5.07 V|
| 5.06 V|  5.06 V|  5.07 V|
| 5.06 V|  5.07 V|  5.07 V|
| 5.07 V|  5.07 V|  5.06 V|
| 5.07 V|  5.07 V|  5.07 V|
| 5.06 V|  5.06 V|  5.07 V|
| 5.06 V|  5.06 V|  5.06 V|
| 5.07 V|  5.07 V|  5.06 V|

Start acquisition on analog input by digital trigger

This example demonstrates how to start acquisition by digital trigger.

program aidigtrig;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx,crt
  { you can add units after this };
var
   AITaskHandle:TaskHandle;
  channel:string = 'Dev1/ai0';
  SampleRate:double = 10000;
  SamplePerChannel:longint = 1000;
  PretriggerSamples: longint= 100; //MUST be > 2
  reads:longint = 0;
  i:longint;
  data:array of double;
procedure ErrorCheck(AError:longint;ATaskHandle:longint);
var
  errBuffer:array[0..2048] of char;
begin
  //get error description
  if Aerror<>0 then begin
     DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
     writeln(ErrBuffer);
     //stop and cleat task
     if Assigned(@ATaskHandle) then begin
       DAQmxStopTask(ATaskHandle);
       DAQmxClearTask(ATaskHandle);
     end;
     //stop acquisition
     writeln('Program stoped');
     Halt;
  end;
end;

begin
    //set buffer length
    SetLength(data,SamplePerChannel);
    //create take
    DAQmxCreateTask('',@AITaskHandle);
    //create ai channel
    ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,@channel[1],'',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,Nil),AITaskHandle);
    //configure sample clock
    ErrorCheck(DAQmxCfgSampClkTiming(AITaskHandle,'',SampleRate,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,SamplePerChannel),AITaskHandle);
    //configure triger with 100 pretriggered samples
    ErrorCheck(DAQmxCfgDigEdgeRefTrig(AITaskHandle,'/Dev1/PFI0',DAQmx_Val_Rising,PretriggerSamples),AITaskHandle);
    //start task
    ErrorCheck(DAQmxStartTask(AITaskHandle),AITaskHandle);
    //acquire data
    writeln('Press any key to stop acquisition');
    i := 0;
    repeat
      ErrorCheck(DAQmxReadAnalogF64(AITaskHandle,SamplePerChannel,10.0,DAQmx_Val_GroupByChannel,@data[0],Length(data),@reads,Nil),AITaskHandle);
      i := i + reads;
      writeln('Number of acquired samples: ', i);
    until keypressed;
    //show last readed number of samples
    for i:=Low(data) to High(data) do writeln('data[',i,'] = ', data[i]:4:2);

    //stop and clear task
    if Assigned(@AITaskHandle) then begin
      DAQmxStopTask(AITaskHandle);
      DAQmxClearTask(AITaskHandle);
    end;
end.

Analog output software controlled

This example demonstrates sinusoidal waveform generation with software timed control analog output.

program aochansw;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,Crt,SysUtils,nidaqmx
  { you can add units after this };
var
  AOTaskHandle:TaskHandle;
  //data writted to analog output
  data:array [0..999] of double;
  writtensamples:integer;
  i:integer;

 {************Error handling procedure *****************************************
    Example:
 ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
 *******************************************************************************}
procedure ErrorCheck(AError:longint;ATaskHandle:longint);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if Aerror<>0 then begin
     DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
     writeln(PChar(@ErrBuffer[0]));
   //stop and cleat task
   if Assigned(@ATaskHandle) then begin
     DAQmxStopTask(ATaskHandle);
     DAQmxClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;

begin
  //prepare data for analog output
  //sin waveform
  for i:=Low(data) to High(data) do data[i]:=9.95*sin(i*2.0*Pi/1000.0);
  //create task
  DAQmxCreateTask('',@AOTaskHandle);
  //configure analog output channel
  ErrorCheck(DAQmxCreateAOVoltageChan(AOTaskHandle,'Dev1/ao0','',-10.0,10.0,DAQmx_Val_Volts,Nil),AOTaskHandle);
  //start task
  ErrorCheck(DAQmxStartTask(AOTaskHandle),AOTaskHandle);

  writeln('Press any key to stop generation');
  //continuosly waveform generation
  //if you call task start function (DAQmxStartTask)
  //before output write function (for example DAQmxWriteAnalogScalarF64)
  //set AutoStart parameter to 1
  //if output function berofe start AutoStart = 0
  i:=0;
  repeat
    sleep(1);
    ErrorCheck(DAQmxWriteAnalogScalarF64(AOTaskHandle,1,10.0,data[i],Nil),AOTaskHandle);
    inc(i);
    if i >=1000 then i:=0;
  until keypressed;

  //stop and clear task
  if Assigned(@AOTaskHandle) then begin
    DAQmxStopTask(AOTaskHandle);
    DAQmxClearTask(AOTaskHandle);
  end;
end.

Analog output hardware controlled

This example demonstrates how to generate finite number of samples on analog output channel.

program aochannel;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx
  { you can add units after this };

var
  AOTaskHandle:TaskHandle;
  //data writted to analog output
  data:array [0..3999] of double;
  writtensamples:integer;
  i:integer;

 {************Error handling procedure *****************************************
    Example:
 ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);

*******************************************************************************}

procedure ErrorCheck(AError:longint;ATaskHandle:longint);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if Aerror<>0 then begin
     DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
     writeln(PChar(@ErrBuffer[0]));
   //stop and cleat task
   if Assigned(@ATaskHandle) then begin
     DAQmxStopTask(ATaskHandle);
     DAQmxClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;

{*********************MAIN PROGRAM*********************************************
 }
begin
  //prepare data for analog output
  for i:=Low(data) to High(data) do data[i]:= 5.0*i/4000.0;
  //create task
  DAQmxCreateTask('',@AOTaskHandle);
  //configure analog output channel
  ErrorCheck(DAQmxCreateAOVoltageChan(AOTaskHandle,'Dev1/ao0','',-10.0,10.0,DAQmx_Val_Volts,Nil),AOTaskHandle);
  //configure clock
  ErrorCheck(DAQmxCfgSampClkTiming(AOTaskHandle,'',1000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,4000),AOTaskHandle);
  //write data to buffer
  ErrorCheck(DAQmxWriteAnalogF64(AOTaskHandle,4000,0,10.0,DAQmx_Val_GroupByChannel,data,@writtensamples,Nil),AOTaskHandle);
  //start task
  ErrorCheck(DAQmxStartTask(AOTaskHandle),AOTaskHandle);
  //wait until all samples are generated
  ErrorCheck(DAQmxWaitUntilTaskDone(AOTaskHandle,10.0),AOTaskHandle);
  //stop and clear task
  if Assigned(@AOTaskHandle) then begin
    DAQmxStopTask(AOTaskHandle);
    DAQmxClearTask(AOTaskHandle);
  end;
end.

DIGITAL INPUTS/OUTPUTS

Most of DAQ cards have two types of digital ports (input/output): correlated and static. Static ports are software timed, correlated are software or hardware timed by the external or internal clock for example couter output signal (/Dev1/Ctr0InternalOutput - couter0 as clock ). Check the documention to find it, for example NI-PCI6250 have three 8-bit ports: port0 - correlated, port1,port2 - static; NI-PCI6224 two ports: 32-bit port0 - correlated, 8-bit port1 - static.

Read/Write data from/to 8-bit and 32-bit digital port use an appropriate function DAQmxReadDigitalU8, DAQmxWriteDigitalU8 and DAQmxReadDigitalU32, DAQmxWriteDigitalU32.

Different behaviour of collerated port0, when it sets as input, occured under Linux and Windows: software timed works only under Windows, with external clock works under Windows and Linux!!!

Software timed digital input

To check it, connected +5V(depend on hardware) to one of available port pins.

program diport;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx,SysUtils,StrUtils
  { you can add units after this };
var
  DITaskHandle:TaskHandle;
  data:array [0..9] of byte;
  reads:longint = 0;
  totalreads:longint = 0;
  i:longint ;
{************Error handling procedure *****************************************
      Example:
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);

  *******************************************************************************}

  procedure ErrorCheck(AError:longint;ATaskHandle:longint);
  var
    errBuffer:array[0..2048] of char;
  begin
     //get error description
     if Aerror<>0 then begin
       DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
       writeln(PChar(@ErrBuffer[0]));
     //stop and cleat task
     if Assigned(@ATaskHandle) then begin
       DAQmxStopTask(ATaskHandle);
       DAQmxClearTask(ATaskHandle);
     end;
     //stop program
     Halt;
    end;
  end;
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
begin
  //task create
  ErrorCheck(DAQmxCreateTask('',@DITaskHandle),DITaskHandle);
  //digital input port create
  ErrorCheck(DAQmxCreateDIChan(DITaskHandle,'Dev1/port1','',DAQmx_Val_ChanForAllLines),DITaskHandle);
  //Start Task
  ErrorCheck(DAQmxStartTask(DITaskHandle),DITaskHandle);
  //read 10 samples from 8-bit digital port (for example NI PCI-6250 card port1(pins P1.0-P1.7))
  //for 32-bit digital port use DAQmxReadDigitalU32 function
  ErrorCheck(DAQmxReadDigitalU8(DITaskHandle,10,10.0,DAQmx_Val_GroupByChannel,@data,10,@reads,Nil),DITaskHandle);
  writeln('number of readed samples: ',reads);
  for i:=0 to 9 do writeln('data [',i,'] = %',IntToBin(data[i],8));
  //stop and clear task
  if DITaskHandle<>0 then begin
    DAQmxStopTask(DITaskHandle);
    DAQmxClearTask(DITaskHandle);
  end;
end.

Output example: +5V connected to pin P1.2 port1 on NI-PCI6250 card.

number of readed samples: 10
data [0] = %00000100
data [1] = %00000100
data [2] = %00000100
data [3] = %00000100
data [4] = %00000100
data [5] = %00000100
data [6] = %00000100
data [7] = %00000100
data [8] = %00000100
data [9] = %00000100

Hardware timed digital input

This example shows using of counter output signal as a clock for digital inputs port for hardware timed acquire data on digital inputs. This feature is supported only for correlated digital port. In this example 8-bit port0 on NI-PCI6250 card is used to check this function.

To check it, connected +5V(depend on hardware) to one of available pins on correlated digital port.

program diporttimed;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx,SysUtils,StrUtils
  { you can add units after this };
var
  DITaskHandle,CtrTaskHandle:TaskHandle;
  data:array [0..9] of byte;
  reads:longint = 0;
  totalreads:longint = 0;
  i:longint ;
{************Error handling procedure *****************************************
      Example:
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);

  *******************************************************************************}

  procedure ErrorCheck(AError:longint;ATaskHandle:longint);
  var
    errBuffer:array[0..2048] of char;
  begin
     //get error description
     if Aerror<>0 then begin
       DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
       writeln(PChar(@ErrBuffer[0]));
     //stop and cleat task
     if Assigned(@ATaskHandle) then begin
       DAQmxStopTask(ATaskHandle);
       DAQmxClearTask(ATaskHandle);
     end;
     //stop program
     Halt;
    end;
  end;
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
begin
  {******CREATE COUNTER OUTPUT TO USE IT AS CLOCK FOR DIGITAL PORT INPUTS******
  *******INTERNALLY CONNECTED ON M-SERIES as /Dev1/Ctr0InternalOutput**********}
  //create couter task
  ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
  //create counter output channel
  //Frequency 1000 Hz, duty 0.5
  ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,1000,0.5),CtrTaskHandle);
  //timing 1000 samples per second
  ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
  //start counter task
  ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);

  //digital input task create
  ErrorCheck(DAQmxCreateTask('Digital input task',@DITaskHandle),DITaskHandle);
  //digital input port create
  ErrorCheck(DAQmxCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
  //timing use counter output as clock source internally connected
  //as /Dev1/Ctr0InternalOutput
  ErrorCheck(DAQmxCfgSampClkTiming(DITaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000),DITaskHandle);
  //Start digital input Task
  ErrorCheck(DAQmxStartTask(DITaskHandle),DITaskHandle);
  //read 10 samples from 8-bit digital port for example correlated port0 
  //for 32-bit digital port use DAQmxReadDigitalU32 function
  ErrorCheck(DAQmxReadDigitalU8(DITaskHandle,10,10.0,DAQmx_Val_GroupByChannel,@data,10,@reads,Nil),DITaskHandle);
  writeln('number of readed samples: ',reads);
  for i:=0 to 9 do writeln('data [',i,'] = %',IntToBin(data[i],8));
  //stop and clear task
  DAQmxStopTask(DITaskHandle);
  DAQmxClearTask(DITaskHandle);
  DAQmxStopTask(CtrTaskHandle);
  DAQmxClearTask(CtrTaskHandle); 
end.

Output example: +5V connected to pin P0.5 on port0 on NI-PCI6250 card.

number of readed samples: 10
data [0] = %00100000
data [1] = %00100000
data [2] = %00100000
data [3] = %00100000
data [4] = %00100000
data [5] = %00100000
data [6] = %00100000
data [7] = %00100000
data [8] = %00100000
data [9] = %00100000

Software controlled digital output

To check it connect digital output(s) to oscilloscope or to card analog input.

program doportlpi;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx,SysUtils,StrUtils
  { you can add units after this };
var
  DOTaskHandle:TaskHandle;
  data: byte;
  written:longint = 0;
{************Error handling procedure *****************************************
      Example:
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);

  *******************************************************************************}

  procedure ErrorCheck(AError:longint;ATaskHandle:longint);
  var
    errBuffer:array[0..2048] of char;
  begin
     //get error description
     if Aerror<>0 then begin
       DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
       writeln(PChar(@ErrBuffer[0]));
     //stop and cleat task
     if Assigned(@ATaskHandle) then begin
       DAQmxStopTask(ATaskHandle);
       DAQmxClearTask(ATaskHandle);
     end;
     //stop program
     Halt;
    end;
  end;
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
begin
  //task create
  ErrorCheck(DAQmxCreateTask('',@DOTaskHandle),DOTaskHandle);
  //digital input port create
  ErrorCheck(DAQmxCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
  //task start
  //no need to start task
  ErrorCheck(DAQmxStartTask(DOTaskHandle),DOTaskHandle);
  //for 32-bit digital port use DAQmxReadDigitalU32 function
  //set 1 on all lines of digital port
  //change data:=0 to set 0 or use DAQmxResetDevice function to
  data:=0;
  ErrorCheck(DAQmxWriteDigitalU8(DOTaskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,@data,@written,Nil),DOTaskHandle);
  //use DAQmxResetDevice function here to set signal on Low state
  writeln('number of written samples: ',written);
  //stop and clear task
  if DOTaskHandle<>0 then begin
    DAQmxStopTask(DOTaskHandle);
    DAQmxClearTask(DOTaskHandle);
  end;
end.

Hardware timed digital outputs with counter output used as source clock

To check it connect digital output(s) to oscilloscope or to card analog input.

program doporttimed;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx,SysUtils,StrUtils,Crt
  { you can add units after this };
var
  DOTaskHandle,CtrTaskHandle:TaskHandle;
  data:array[0..7] of byte = (1,2,4,8,16,32,64,128);
  written:longint = 0;
{************Error handling procedure *****************************************
      Example:
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);

  *******************************************************************************}

  procedure ErrorCheck(AError:longint;ATaskHandle:longint);
  var
    errBuffer:array[0..2048] of char;
  begin
     //get error description
     if Aerror<>0 then begin
       DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
       writeln(PChar(@ErrBuffer[0]));
     //stop and cleat task
     if Assigned(@ATaskHandle) then begin
       DAQmxStopTask(ATaskHandle);
       DAQmxClearTask(ATaskHandle);
     end;
     //stop program
     Halt;
    end;
  end;
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
begin
  {******CREATE COUNTER OUTPUT TO USE IT AS CLOCK FOR DIGITAL PORT OUTPUTS******
  *******INTERNALLY CONNECTED ON M-SERIES as /Dev1/Ctr0InternalOutput**********}
  //create couter task
  ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
  //create counter output channel
  //Frequency 1000 Hz, duty 0.5
  ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
  //timing 1000 samples per second
  ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
  //start task
  //start counter task
  ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);

  //task create
  ErrorCheck(DAQmxCreateTask('',@DOTaskHandle),DOTaskHandle);
  //digital input port create
  ErrorCheck(DAQmxCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
  //timing
  //frequency 1000Hz
  ErrorCheck(DAQmxCfgSampClkTiming(DOTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),DOTaskHandle);
  //for 32-bit digital port use DAQmxWriteDigitalU32 function
  //function sets to start task automaticly 3-rd parameter
  //write 8 samples
  ErrorCheck(DAQmxWriteDigitalU8(DOTaskHandle,8,1,10.0,DAQmx_Val_GroupByChannel,data,@written,Nil),DOTaskHandle);
  writeln('number of written samples: ',written);
  //stop and clear task
  DAQmxStopTask(DOTaskHandle);
  DAQmxClearTask(DOTaskHandle);
  DAQmxStopTask(CtrTaskHandle);
  DAQmxClearTask(CtrTaskHandle);
end.

COUNTER INPUTS/OUTPUTS

Pulse generation

This example demonstrates pwm generaton with frequency 1000Hz and duty circle 0.5.

program doporttimed;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx,SysUtils,StrUtils,Crt
  { you can add units after this };
var
 CtrTaskHandle:TaskHandle;
 {************Error handling procedure *****************************************
      Example:
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);

  *******************************************************************************}

  procedure ErrorCheck(AError:longint;ATaskHandle:longint);
  var
    errBuffer:array[0..2048] of char;
  begin
     //get error description
     if Aerror<>0 then begin
       DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
       writeln(PChar(@ErrBuffer[0]));
     //stop and cleat task
     if Assigned(@ATaskHandle) then begin
       DAQmxStopTask(ATaskHandle);
       DAQmxClearTask(ATaskHandle);
     end;
     //stop program
     Halt;
    end;
  end;
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
begin
  //create couter task
  ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
  //create counter output channel
  //Frequency 1000 Hz, duty 0.5
  ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
  //timing 1000 samples per second
  ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
  //start task
  ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
   
  writeln('Press any key to stop generation');
  repeat
  until keypressed;  
  
  DAQmxStopTask(CtrTaskHandle);
  DAQmxClearTask(CtrTaskHandle);
end.

Event counting

In this example first counter(Dev1/ctr0) is configurated as counter output for frequency generation, second (Dev1/ctr1) as counter input for pulse counting. First counter also used as clock source for second one.

program eventcounting;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmx,SysUtils,StrUtils,Crt
  { you can add units after this };
var
  CtrOutTaskHandle,CtrInTaskHandle:TaskHandle;
  reads:cardinal=0;
  data:array [0..999] of longint;
  i:longint;
{************Error handling procedure *****************************************
      Example:
   ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);

  *******************************************************************************}
  procedure ErrorCheck(AError:longint;ATaskHandle:longint);
  var
    errBuffer:array[0..2048] of char;
  begin
     //get error description
     if Aerror<>0 then begin
       DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
       writeln(PChar(@ErrBuffer[0]));
     //stop and cleat task
     if Assigned(@ATaskHandle) then begin
       DAQmxStopTask(ATaskHandle);
       DAQmxClearTask(ATaskHandle);
     end;
     //stop program
     Halt;
    end;
  end;
{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
begin
  {****************CREATE COUNTER OUTPUT***************************************}
  //create couter output task
  ErrorCheck(DAQmxCreateTask('Counter output task',@CtrOutTaskHandle),CtrOutTaskHandle);
  //create counter output channel
  //Frequency 1000 Hz, duty 0.5
  ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrOutTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrOutTaskHandle);
  //timing 1000 samples per second
  ErrorCheck(DAQmxCfgImplicitTiming(CtrOutTaskHandle,DAQmx_Val_ContSamps,1000),CtrOutTaskHandle);
  //start counter output task
  ErrorCheck(DAQmxStartTask(CtrOutTaskHandle),CtrOutTaskHandle);

  {*****************CREATE COUNTER INPUT***************************************}
  //create couter output task
  ErrorCheck(DAQmxCreateTask('Counter input task',@CtrInTaskHandle),CtrInTaskHandle);
  //create input counter for pulse counting
  ErrorCheck(DAQmxCreateCICountEdgesChan(CtrInTaskHandle,'Dev1/ctr1','',DAQmx_Val_Rising,0,DAQmx_Val_CountUp),CtrInTaskHandle);
  //timing
  ErrorCheck(DAQmxCfgSampClkTiming(CtrInTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),CtrInTaskHandle);
   //start counter input task
  ErrorCheck(DAQmxStartTask(CtrInTaskHandle),CtrInTaskHandle);
  //counting pulses
  ErrorCheck(DAQmxReadCounterU32(CtrIntaskHandle,1000,10.0,@data,1000,@reads,Nil),CtrIntaskHandle);
  writeln('acquired samples: ',reads);
  for i:=0 to 10 do writeln('sample[',i,'] = ',data[i]);

  //stop and clear tasks
  DAQmxStopTask(CtrInTaskHandle);
  DAQmxClearTask(CtrInTaskHandle);
  DAQmxStopTask(CtrOutTaskHandle);
  DAQmxClearTask(CtrOutTaskHandle);
end.

TESTED HARDWARE

Examples were tested under Linux 32-bit (kernel 2.6.32) NI-DAQmx 8.0.2 and Windows 7 32-bit NI-DAQmx 14 on cards:

  • NI PCI-6250
  • NI PCI-6224
  • NI PXIe-6612 (Windows only)
  • NI USB-6356 (Windows only)
  • NI USB-6003 (Windows only)

NI-DAQxmxBase examples

Generally, NI-DAQmxBase is a light version of NI-DAQmx, but this library is multiplatform. You can use it under all supported operation systems without modification of NI-DAQmxBase function call.

Read readme file to check card supported features!!!

DEVICE INFO

Functions, which provide device and channel information, are not implemented in this library, yet.

ANALOG INPUTS/OUTPUTS

Acquire finite number of samples from one analog channel

program aichannel;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmxbase;
  { you can add units after this }
var
   AITaskHandle: PTaskHandle;
   NiBool:Pnibool;
   reads:longint=0;
   i:byte;
   data:array [1..1000] of double;
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
var
  errBuffer:array[0..2048] of char;
  errMessage:string;
begin
   //get error description
   if DAQmxFailed(AError) = niTrue then begin
     DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
     writeln(ErrBuffer);
   //stop and cleat task
   if Assigned(ATaskHandle) then begin
       DAQmxBaseStopTask(ATaskHandle);
       DAQmxBaseClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;

begin
  //create task
  ErrorCheck(DAQmxBaseCreateTask ('', AITaskHandle),AITaskHandle);
  //create analog input channel
  ErrorCheck(DAQmxBaseCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','', DAQmx_Val_RSE,-10, 10,DAQmx_Val_Volts,''),AITaskHandle);
  //timing
  //clock frequency 1000 Hz, sample rate 1000 per second
  //if you use more than one active channel, generally sample rate = clock frequency/(active analog channles*10);
  ErrorCheck(DAQmxBaseCfgSampClkTiming (AITaskHandle,'OnboardClock',1000,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000),AITaskHandle);
  //start task
  ErrorCheck(DAQmxBaseStartTask(AITaskHandle),AITaskHandle);
  //read 1000 samples
  ErrorCheck(DAQmxBaseReadAnalogF64 (AITaskHandle, 1000, 10.0,DAQmx_Val_GroupByChannel,data,1000,reads,NIBool^),AITaskHandle);
  //acquired sample number
  writeln(reads,' samples were acqiured');
  //show value of first ten samples
  for i:=1 to 10 do writeln('sample[',i,'] = ',data[i]:4:2,' V');
  //stop and clear task
  DAQmxBaseStopTask(AITaskHandle);
  DAQmxBaseClearTask(AITaskHandle);
end.

Output example +5V connected to pin 68 on NI PCI-6250

1000 samples were acqiured
sample[1] = 5.07 V
sample[2] = 5.06 V
sample[3] = 5.06 V
sample[4] = 5.06 V
sample[5] = 5.06 V
sample[6] = 5.06 V
sample[7] = 5.06 V
sample[8] = 5.06 V
sample[9] = 5.06 V
sample[10] = 5.07 V

Continuously acquire samples from three analog inputs

program ai3contacq;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmxbase;
  { you can add units after this }
var
   AITaskHandle: PTaskHandle;
   NiBool:Pnibool;
   reads:longint=0;
   totalreads:longint=0;
   i:byte;
   data:array of double;
   acqnumsamples:longint;
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
var
  errBuffer:array[0..2048] of char;
  errMessage:string;
begin
   //get error description
   if DAQmxFailed(AError) = niTrue then begin
     DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
     writeln(ErrBuffer);
   //stop and cleat task
   if Assigned(ATaskHandle) then begin
       DAQmxBaseStopTask(ATaskHandle);
       DAQmxBaseClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;

begin
  //enter number of total samples for each channel to be acquired
  write('Enter a number of samples for each channel to be acquired: ');
  readln(acqnumsamples);
  //Set buffer size = length of data array:=number of active channels * sample per channel
  Setlength(data,3*1000);
  //create task
  ErrorCheck(DAQmxBaseCreateTask ('', AITaskHandle),AITaskHandle);
  //create analog input channel - 3 active analog inputs
  ErrorCheck(DAQmxBaseCreateAIVoltageChan(AITaskHandle,'Dev1/ai0:2','', DAQmx_Val_RSE,-10, 10,DAQmx_Val_Volts,''),AITaskHandle);
  //timing
  //clock frequency 10000 Hz, sample rate 1000 per second
  //if you use more than one active channel, generally sample rate = clock frequency/(active analog channles*10);
  ErrorCheck(DAQmxBaseCfgSampClkTiming (AITaskHandle,'OnboardClock',10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),AITaskHandle);
  //start task
  ErrorCheck(DAQmxBaseStartTask(AITaskHandle),AITaskHandle);
  //read samples
  while totalreads<acqnumsamples do begin
    ErrorCheck(DAQmxBaseReadAnalogF64(AITaskHandle, 1000, 10.0, DAQmx_Val_GroupByChannel,data,Length(data),reads,NIBool^),AITaskHandle);
    totalreads:=totalreads+reads;
    writeln('total samples readed for each channel: ',totalreads);
    //show first five values for each channel
    for i:=0 to 5 do writeln('chan1[',i,'] = ',data[i]:4:2,' V ','chan2[',i,'] = ',data[i+1000]:4:2,' V ','chan3[',i,'] = ',data[i+2000]:4:2,' V ');
  end;
  //stop and clear task
  DAQmxBaseStopTask(AITaskHandle);
  DAQmxBaseClearTask(AITaskHandle);
end.

Output example +5V connected to pin 68 on NI PCI-6250

Enter a number of samples for each channel to be acquired: 2000
total samples readed for each channel: 1000
chan1[0] = 5.07 V chan2[0] = 0.00 V chan3[0] = 0.03 V
chan1[1] = 5.06 V chan2[1] = -0.00 V chan3[1] = 0.03 V
chan1[2] = 5.07 V chan2[2] = -0.00 V chan3[2] = 0.02 V
chan1[3] = 5.07 V chan2[3] = -0.00 V chan3[3] = 0.02 V
chan1[4] = 5.06 V chan2[4] = -0.00 V chan3[4] = 0.02 V
chan1[5] = 5.06 V chan2[5] = -0.00 V chan3[5] = 0.01 V
total samples readed for each channel: 2000
chan1[0] = 5.06 V chan2[0] = -0.00 V chan3[0] = -0.02 V
chan1[1] = 5.07 V chan2[1] = -0.00 V chan3[1] = -0.02 V
chan1[2] = 5.06 V chan2[2] = -0.00 V chan3[2] = -0.02 V
chan1[3] = 5.07 V chan2[3] = -0.00 V chan3[3] = -0.02 V
chan1[4] = 5.06 V chan2[4] = -0.00 V chan3[4] = -0.02 V
chan1[5] = 5.06 V chan2[5] = -0.00 V chan3[5] = -0.02 V

DIGITAL INPUTS/OUTPUTS

Read readme file to check supported card features by NI-DAQmxBase.

In case of M-series cards, correlated digital input/output is limited to about 100kHz, because DMA data transfer is not supported.

Software timed digital input

program diport;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmxbase,StrUtils
  { you can add units after this };
var
  DITaskHandle:PTaskHandle;
  NiBool:Pnibool;
  data:byte;
  reads:longint=0;
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if DAQmxFailed(AError) = niTrue then begin
     DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
     writeln(ErrBuffer);
   //stop and cleat task
   if Assigned(ATaskHandle) then begin
       DAQmxBaseStopTask(ATaskHandle);
       DAQmxBaseClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;
begin
  //create task
  ErrorCheck(DAQmxBaseCreateTask('', DITaskHandle),DITaskHandle);
  //create digital input port
  ErrorCheck(DAQmxBaseCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
  //start task
  ErrorCheck(DAQmxBaseStartTask(DITaskHandle),DITaskHandle);
  //read dat form port
  //use DAQmxBaseReadDigitalU8 for 8 bit port
  //use DAQmxBaseReadDigitalU32 for 32 bit port
  ErrorCheck(DAQmxBaseReadDigitalU8(DITaskHandle,1,10.0,DAQmx_Val_GroupByChannel,data,1,reads,NiBool^),DITaskHandle);
  writeln('digital port value %',IntToBin(data,8));
  //stop and clear task
  DAQmxBaseStopTask(DITaskHandle);
  DAQmxBaseClearTask(DITaskHandle);
end.

Output example: +5V connected to line 1 of 8-bit digital port

digital port value %00000010

Hardware timed digital input

program diporthwtimed;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmxbase,StrUtils
  { you can add units after this };
var
  DITaskHandle,CtrTaskHandle:PTaskHandle;
  NiBool:Pnibool;
  data:array of byte;
  reads:longint=0;
  i:longint;
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if DAQmxFailed(AError) = niTrue then begin
     DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
     writeln(ErrBuffer);
   //stop and cleat task
   if Assigned(ATaskHandle) then begin
       DAQmxBaseStopTask(ATaskHandle);
       DAQmxBaseClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;
begin

  {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
  //create counter task
  ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
  //create counter output channel
  //Frequency 10000 Hz, duty 0.5
  ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
  //timing
  //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
  ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
  //start counter task
  ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);


  {*******************HW TIMED DIGITAL INPUT***********************************
  **********LIMITED TO 10kHz,DMA IS NOT IMPLEMENTED****************************}
  //configure buffer for 1000 samples
  SetLength(data,1000);
  //create task
  ErrorCheck(DAQmxBaseCreateTask('', DITaskHandle),DITaskHandle);
  //create digital input port
  ErrorCheck(DAQmxBaseCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
  //timing frequency 10000Hz, 1000 sample per channel
  ErrorCheck(DAQmxBaseCfgSampClkTiming(DITaskHandle,'/Dev1/Ctr0InternalOutput',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,10000),DITaskHandle);
  //start task
  ErrorCheck(DAQmxBaseStartTask(DITaskHandle),DITaskHandle);
  //read dat form port
  //use DAQmxBaseReadDigitalU8 for 8 bit port
  //use DAQmxBaseReadDigitalU32 for 32 bit port
  ErrorCheck(DAQmxBaseReadDigitalU8(DITaskHandle,10000,10.0,DAQmx_Val_GroupByChannel,data,10000,reads,NiBool^),DITaskHandle);
  writeln(reads,' samples were readed');
  //show first 10 samples
  for i:=0 to 9 do writeln('sample[',i,'] = %',IntToBin(data[i],8));
  //stop and clear task
  DAQmxBaseStopTask(DITaskHandle);
  DAQmxBaseClearTask(DITaskHandle);
  DAQmxBaseStopTask(CtrTaskHandle);
  DAQmxBaseClearTask(CtrTaskHandle);
end.

Output example: +5V connected to line 1 of 8-bit digital port, executed with time command under Linux.

10000 samples were readed                                      
sample[0] = %00000010                                          
sample[1] = %00000010                                          
sample[2] = %00000010
sample[3] = %00000010
sample[4] = %00000010
sample[5] = %00000010
sample[6] = %00000010
sample[7] = %00000010
sample[8] = %00000010
sample[9] = %00000010

real    0m4.483s
user    0m4.261s
sys     0m0.100s

Software timed digital output

program doport;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmxbase,StrUtils,SysUtils
  { you can add units after this };
var
  DOTaskHandle,CtrTaskHandle:PTaskHandle;
  NiBool:Pnibool;
  data: byte;
  written:longint=0;
  i:longint;
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if DAQmxFailed(AError) = niTrue then begin
     DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
     writeln(ErrBuffer);
   //stop and cleat task
   if Assigned(ATaskHandle) then begin
       DAQmxBaseStopTask(ATaskHandle);
       DAQmxBaseClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;
begin
  //write data to buffer, produce digital waveform on all port lines
  data:=255;
  //create task
  ErrorCheck(DAQmxBaseCreateTask('', DOTaskHandle),DOTaskHandle);
  //create digital input port
  ErrorCheck(DAQmxBaseCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
  //use DAQmxBaseWriteDigitalU8 for 8 bit port
  //use DAQmxBaseWriteDigitalU32 for 32 bit port
  //set third parametr to 1 to enable autostart or set to 0 and use DAQmxBaseStartTask before
  //set digital "1"
  writeln('set digital 1 on all port lines');
  writeln('sleep 10s');
  ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
  sleep(10000);
  writeln(written,' samples were written');
  //set digital "0"
  writeln('set digital 0 on all port lines');
  writeln('sleep 10s');
  sleep(10000);
  ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
  writeln(written,' samples were written');
  //stop and clear task
  DAQmxBaseStopTask(DOTaskHandle);
  DAQmxBaseClearTask(DOTaskHandle);
  DAQmxBaseStopTask(CtrTaskHandle);
  DAQmxBaseClearTask(CtrTaskHandle);
end.

Hardware timed digital output

Digital output generation frequency is limited to ~100kHz, because DMA is not supported by the driver .

program doporthwtimed;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmxbase,StrUtils
  { you can add units after this };
var
  DOTaskHandle,CtrTaskHandle:PTaskHandle;
  NiBool:Pnibool;
  data:array of byte;
  written:longint=0;
  i:longint;
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if DAQmxFailed(AError) = niTrue then begin
     DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
     writeln(ErrBuffer);
   //stop and cleat task
   if Assigned(ATaskHandle) then begin
       DAQmxBaseStopTask(ATaskHandle);
       DAQmxBaseClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;
begin
  {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
  //create counter task
  ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
  //create counter output channel
  //Frequency 10000 Hz, duty 0.5
  ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
  //timing
  //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
  ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
  //start counter task
  ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
  {*******************HW TIMED DIGITAL INPUT***********************************
  **********LIMITED TO 10kHz,DMA IS NOT IMPLEMENTED****************************}
  //configure buffer for 1000 samples
  SetLength(data,1000);
  //write data to buffer, produce digital waveform on all port lines
  for i:=0 to 999 do if (i mod 2 = 0) then data[i]:=255;
  //create task
  ErrorCheck(DAQmxBaseCreateTask('', DOTaskHandle),DOTaskHandle);
  //create digital input port
  ErrorCheck(DAQmxBaseCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
  //timing frequency 10000Hz, 1000 sample per channel
  ErrorCheck(DAQmxBaseCfgSampClkTiming(DOTaskHandle,'/Dev1/Ctr0InternalOutput',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),DOTaskHandle);
  //use DAQmxBaseWriteDigitalU8 for 8 bit port
  //use DAQmxBaseWriteDigitalU32 for 32 bit port
  //set third parametr to 1 to enable autostart or set to 0 and use DAQmxBaseStartTask before
  ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
  writeln(written,' samples were written');
  //stop and clear task
  DAQmxBaseStopTask(DOTaskHandle);
  DAQmxBaseClearTask(DOTaskHandle);
  DAQmxBaseStopTask(CtrTaskHandle);
  DAQmxBaseClearTask(CtrTaskHandle);
end.

COUNTER INPUTS/OUTPUTS

Counter input of M-series cards is limited to computer speed.

COUNTER OUTPUT

Counter output can be timed by software or hardware.

Example demontrate how to use couter ouput as frequency generator(clock signal for other hardware) or as basic pwm regulation.

In this example counter output is hardware timed.

program ctrout;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmxbase,StrUtils,SysUtils
  { you can add units after this };
var
  CtrTaskHandle:PTaskHandle;
  NiBool:Pnibool;
  data:array of byte;
  reads:longint=0;
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if DAQmxFailed(AError) = niTrue then begin
     DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
     writeln(ErrBuffer);
   //stop and cleat task
   if Assigned(ATaskHandle) then begin
       DAQmxBaseStopTask(ATaskHandle);
       DAQmxBaseClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;
begin

  {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
  //create counter task
  ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
  //create counter output channel
  //Frequency 10000 Hz, duty 0.5
  ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
  //timing
  //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
  ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
  //start counter task
  ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
  //generate frequency signal for 10 seconds
  sleep(10000);
  DAQmxBaseStopTask(CtrTaskHandle);
  DAQmxBaseClearTask(CtrTaskHandle);
end.

COUNTER INPUT

Counter input is only software operated. It is limited by hardware driver.

program ctrin;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,nidaqmxbase,StrUtils,SysUtils,Crt
  { you can add units after this };
var
  CtrInTaskHandle:PTaskHandle;
  NiBool:Pnibool;
  data:dword=0;
  reads:longint=0;
procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
var
  errBuffer:array[0..2048] of char;
begin
   //get error description
   if DAQmxFailed(AError) = niTrue then begin
     DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
     writeln(ErrBuffer);
   //stop and cleat task
   if Assigned(ATaskHandle) then begin
       DAQmxBaseStopTask(ATaskHandle);
       DAQmxBaseClearTask(ATaskHandle);
   end;
   //stop program
   Halt;
  end;
end;
begin
  {*****************CREATE COUNTER INPUT***************************************}
  //create couter input task
  ErrorCheck(DAQmxBaseCreateTask('Counter input task',CtrInTaskHandle),CtrInTaskHandle);
  //create input counter for pulse counting
  ErrorCheck(DAQmxBaseCreateCICountEdgesChan(CtrInTaskHandle,'Dev1/ctr1','',DAQmx_Val_Rising,0,DAQmx_Val_CountUp),CtrInTaskHandle);
  //timing
  //ErrorCheck(DAQmxBaseCfgSampClkTiming(CtrInTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),CtrInTaskHandle);
   //start counter input task
  ErrorCheck(DAQmxBaseStartTask(CtrInTaskHandle),CtrInTaskHandle);
  //counting pulses
  writeln('press any key to stop counting');
  repeat
    ErrorCheck(DAQmxBaseReadCounterU32(CtrIntaskHandle,1,10.0,data,1,reads,NiTrue),CtrIntaskHandle);
    writeln('counter value: ',data);
  until keypressed;
  //clear and stop task
  DAQmxBaseStopTask(CtrInTaskHandle);
  DAQmxBaseClearTask(CtrInTaskHandle);
end.

TESTED HARDWARE

Examples were tested under Scientific Linux 6.4, Mageia 2 32-bit and Windows 32-bit and should work under MacOS (need test) on cards:

  • NI PCI-6250
  • NI PCI-6224
  • NI USB-6356 (Windows only)