Difference between revisions of "NI-DAQmx and NI-DAQmx Base examples"
Line 804: | Line 804: | ||
====Event counting==== | ====Event counting==== | ||
− | < | + | <syntaxhighlight lang="pascal"> |
− | </ | + | 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. | ||
+ | |||
+ | </syntaxhighlight> | ||
[[Category:Hardware]] | [[Category:Hardware]] |
Revision as of 18:17, 18 November 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 tranfer is not supported.
Download library for Linux [3], Windows [4], MacOS X [5]. 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 it there [6]
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 it there [7]
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 [8]
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 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
Continually acquire samples from 3 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 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.
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
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.