Difference between revisions of "NI-DAQmx and NI-DAQmx Base examples"
Line 894: | Line 894: | ||
'''NI PXIe-6612 (Windows only)''' | '''NI PXIe-6612 (Windows only)''' | ||
+ | |||
'''NI USB-6356 (Windows only)''' | '''NI USB-6356 (Windows only)''' | ||
Revision as of 10:27, 17 December 2014
INTRODUCTION
National Instruments produce a wide range of DAQ cards, which generally used for acquiring a generating signals. [1] 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.
What National Instruments Hardware are supported
Supported hardware list by NI-DAQmx and NI-DAQ Driver for different operation system [2]
NI-DAQmxBase library
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 transfer is not supported.
Download library for Linux, Windows and MacOS X. Read readme.txt file to find the list of supported hardware and hardware features.
NI-DAQmx library
Actual (newest) NI-DAQmx library is available only for Windows today. (download)
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. (download)
Read readme.txt file to find the list of supported hardware and hardware features.
PASCAL bindings
Your can download pascal bindings nidaqmxbase.pas and nidaqmx.pas in this forum thread [3]
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: DAQmxCreateDIChan
3. Set timing if you need hardware timimg: DAQmxCfgSamplClkTiming
4. Start task: DAQmxStartTask
5. Read or write data from/to channel: DAQmxReadDigitalU32 or DAQmxWriteDigitalU32
6. Do job
7. End of program - stop and clear task: DAQmxStopTask and DAQmxClearTask
For error handling create function like ErrorCheck.
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
aquired number of samples: 1000
aquired number of samples: 2000
aquired number of samples: 3000
aquired number of samples: 4000
aquired number of samples: 5000
aquired number of samples: 6000
aquired number of samples: 7000
aquired number of samples: 8000
aquired number of samples: 9000
aquired 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|
Analog output software controlled
Analog output hardware controlled
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 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.
To control 8-bit and 32-bit 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 were 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 PXIe-6612 (Windows only)
NI USB-6356 (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 are tested under Scientific Linux 6.4, Mageia 2 32-bit and should work under Windows (need test) and MacOS (need test) on cards:
- NI PCI-6250
- NI PCI-6224