Sign in Join
Wiki copytemporary

NI-DAQmx and NI-DAQmx Base examples: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: NI-DAQmx and NI-DAQmx Base examples

OldNewLine
1+## INTRODUCTION
2+
3+National Instruments produce a wide range of [DAQ cards](http://www.ni.com/data-acquisition/multifunction/), which are generally used for acquiring and generating signals.
4+
5+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.
6+
7+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.
8+
9+### What National Instruments Hardware is supported
10+
11+[Supported hardware list](http://www.ni.com/white-paper/6910/en/) by NI-DAQmx and NI-DAQ Driver for different operating systems.
12+
13+### NI-DAQmxBase library
14+
15+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.
16+
17+Download library [from here](https://www.ni.com/en-au/support/downloads/drivers/download.ni-daqmx-base.html). Read [readme file](http://download.ni.com/support/softlib/multifunction_daq/nidaqmxbase/15.0/windows/readme.htm) to find the list of supported hardware and hardware features.
18+
19+```text
20+ Latest Linux version 15.0 supports 64-bit OS, but you still need to install some 32-bit library.
21+
22+ LIST OF LIBRARIES:
23+
24+ compat-libstdc++.i686
25+ expat.i686
26+ glibc.i686
27+ glibc-devel.i686
28+ libdrm.i686
29+ libgcc.i686
30+ libselinux.i686
31+ libstdc++.i686
32+ libX11.i686
33+ libXau.i686
34+ libxcb.i686
35+ libXdamage.i686
36+ libXext.i686
37+ libXinerama.i686
38+ libXfixes.i686
39+ libXxf86vm.i686
40+ mesa-dri-drivers.i686
41+ mesa-libGL.i686
42+ nss-softokn-freebl.i686
43+ zlib.i686
44+```
45+
46+### NI-DAQmx library
47+
48+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)](https://www.ni.com/en-au/support/downloads/drivers/download.ni-daqmx.html)
49+
50+Read [readme file](http://download.ni.com/support/softlib/multifunction_daq/nidaqmx/9.0/readme.html) to find the list of supported hardware and hardware features.
51+
52+## HOW TO IDENTIFY PRESENT HARDWARE
53+
54+To get list of devices present in your system Under Linux operation system use
55+
56+`1) `**`nilsdev`**` utility with NIDAQmx driver installed,`\
57+`2) `**`lsdaq`**` utility with NIDAQmxBase driver installed.`
58+
59+Under Windows use **NIMAX** utility to get device list or set device alias etc.
60+
61+## Library documentation
62+
63+You can find description of functions and properties in NI-DAQmx and NI-DAQmx Base C reference Help:
64+
65+- [NI-DAQmx](http://digital.ni.com/manuals.nsf/websearch/934F66A25EB3831586257AFD00741B13?OpenDocument&seen=1)
66+- [NI-DAQmx Base](http://digital.ni.com/manuals.nsf/websearch/C4B5B92E74F160C6862574560065F8BC)
67+
68+## PASCAL bindings
69+
70+Your can download pascal bindings nidaqmxbase.pas and nidaqmx.pas in this forum thread [1](http://forum.lazarus.freepascal.org/index.php/topic,7894.msg161883.html#msg161883) or as a [part of the LazMer](http://sourceforge.net/p/lazmer/code/HEAD/tree/trunk/daqlibs/) project.
71+
72+## FUNCTION CALLING
73+
74+Generally, when you need to acquire or gerenate data, call functions from **nidaqmx.pas** as follow
75+
76+```text
77+1. Create task: DAQmxCreateTask
78+2. Channel create:
79+ a)DAQmxCreateDIChan/DAQmxCreateDOChan (digital input(s)/output(s))
80+ b)DAQmxCreateAIVoltageChan/DAQmxCreateAOVoltageChan (analog input(s)/output(s))
81+3. Set timing if you need hardware timimg: DAQmxCfgSamplClkTiming
82+4. Start task: DAQmxStartTask
83+5. Read or write data from/to channel:
84+ a)read data from digital port: DAQmxReadDigitalU8(8-bit port),DAQmxReadDigitalU32 (32-bit port),
85+ b)write data to digital port: DAQmxWriteDigitalU8(8-bit port),DAQmxWriteDigitalU32 (32-bit port),
86+ c)read data from analog input(s): DAQmxReadAnalogF64,
87+ d)write data to analog output(s): DAQmxWriteAnalogF64.
88+6. Do job
89+7. End of program - stop and clear task: DAQmxStopTask and DAQmxClearTask
90+
91+For error handling create function like ErrorCheck.
92+```
93+
94+from **nidaqmxbase.pas** as follow
95+
96+```text
97+1. Create task: DAQmxBaseCreateTask
98+2. Channel create:
99+ a)DAQmxBaseCreateDIChan/DAQmxBaseCreateDOChan (digital input(s)/output(s))
100+ b)DAQmxBaseCreateAIVoltageChan/DAQmxBaseCreateAOVoltageChan (analog input(s)/output(s))
101+3. Set timing if you need hardware timimg: DAQmxBaseCfgSamplClkTiming
102+4. Start task: DAQmxBaseStartTask
103+5. Read or write data from/to channel:
104+ a)read data from digital port: DAQmxBaseReadDigitalU8(8-bit port),DAQmxBaseReadDigitalU32 (32-bit port),
105+ b)write data to digital port: DAQmxBaseWriteDigitalU8(8-bit port),DAQmxBaseWriteDigitalU32 (32-bit port),
106+ c)read data from analog input(s): DAQmxBaseReadAnalogF64,
107+ d)write data to analog output(s): DAQmxBaseWriteAnalogF64.
108+6. Do job
109+7. End of program - stop and clear task: DAQmxBaseStopTask and DAQmxBaseClearTask
110+
111+For error handling create function like ErrorCheck.
112+```
113+
114+```text
115+ Probably, some examples need to add @ before variable, which use as function parameter!!!
116+```
117+
118+## NI-DAQmx examples
119+
120+### DEVICE INFO
121+
122+#### Get device list
123+
124+You can check device list names using NI MAX program under Windows or nilsdev utility under Linux.
125+
126+``` pascal
127+program devicelist;
128+
129+{$mode objfpc}{$H+}
130+
131+uses
132+ {$IFDEF UNIX}{$IFDEF UseCThreads}
133+ cthreads,
134+ {$ENDIF}{$ENDIF}
135+ Classes,nidaqmx,SysUtils
136+ { you can add units after this };
137+var
138+ devicenames:array of Char;
139+ infostr:string;
140+ DeviceNamesList:TStringList;
141+ buffersize:longint;
142+ product_type:array of char;
143+ devserialnum,is_simulated:longint;
144+ is_simulated_str:string;
145+ i:byte;
146+begin
147+ DeviceNamesList:=TStringList.Create;
148+ try
149+ {**************************************************************************
150+ Get device names present in the system
151+ **************************************************************************}
152+ //get buffer size or length of string of device list
153+ buffersize:=DAQmxGetSystemInfoAttribute(DAQmx_Sys_DevNames,devicenames[0],[0]);
154+ //set array of Char lenght
155+ if Buffersize<>0 then begin
156+ writeln('-------------------------------------------------------------');
157+ writeln('|Device name | Product Type | # Serial number | Is Simulated?');
158+ writeln('-------------------------------------------------------------');
159+ SetLength(devicenames,buffersize);
160+ //get the device list
161+ DAQmxGetSystemInfoAttribute(DAQmx_Sys_DevNames,devicenames[0],[buffersize]);
162+ //convert it to string: names are separated by comma
163+ SetString(infostr,PChar(@devicenames[0]),buffersize);
164+ //add names to TStringList
165+ DeviceNamesList.CommaText:=infostr;
166+ {************************************************************************
167+ Get Product info
168+ ***********************************************************************}
169+ for i:=0 to DeviceNamesList.Count-1 do begin
170+ //get buffer size or length of string of product type
171+ buffersize:=DAQmxGetDeviceAttribute(@DeviceNamesList.Strings[i][1],DAQmx_Dev_ProductType,Nil);
172+ //set lenght of array of char
173+ SetLength(product_type,buffersize);
174+ //get product type info
175+ DAQmxGetDeviceAttribute(@DeviceNamesList.Strings[i][1],DAQmx_Dev_ProductType,product_type[0],[buffersize]);
176+ {***********************************************************************
177+ Get Serial Number
178+ **********************************************************************}
179+ DAQmxGetDeviceAttribute(@DeviceNamesList.Strings[i][1],DAQmx_Dev_SerialNum,devserialnum,[1]);
180+ //DeviceInfoGrid.Cells[3,i+1]:=IntToHex(devserialnum,8);
181+ {***********************************************************************
182+ Is simulated?
183+ ***********************************************************************}
184+ DAQmxGetDeviceAttribute(@DeviceNamesList.Strings[i][1],DAQmx_Dev_IsSimulated,is_simulated,[1]);
185+ if is_simulated = 0 then is_simulated_str:='No'
186+ else is_simulated_str:='Yes';
187+ //Show info
188+ writeln('| ',DeviceNamesList.Strings[i],' | ',PChar(@product_type[0]),' | $',IntToHex(devserialnum,8),' |',is_simulated_str);
189+ end;
190+ end
191+ else writeln('any device found');
192+ finally
193+ DeviceNamesList.Free;
194+ end;
195+end.
196+```
197+
198+Output example
199+
200+```text
201+-------------------------------------------------------------
202+|Device name | Product Type | # Serial number | Is Simulated?
203+-------------------------------------------------------------
204+| Dev1 | PCI-6250 | $018D0B90 |No
205+```
206+
207+#### Get channel names
208+
209+``` pascal
210+program chaninfo;
211+
212+{$mode objfpc}{$H+}
213+
214+uses
215+ {$IFDEF UNIX}{$IFDEF UseCThreads}
216+ cthreads,
217+ {$ENDIF}{$ENDIF}
218+ Classes,nidaqmx
219+ { you can add units after this };
220+var
221+ buffersize,infotype:longint;
222+ channelnames:array of char;
223+ MsgChannelNames:array [0..255] of char;
224+ MsgNoChannelsText:array [0..255] of char;
225+ channeltype:byte;
226+ DeviceName:string;
227+begin
228+ {**********INPUT Device name and interested channel type **********************
229+ **********WITHOUT CHEKING IF DEVICE EXITS IN THE SYSTEM**********************}
230+ write('Enter device name, for example Dev1, Dev2 etc.: ');
231+ readln(Devicename);
232+ writeln('0 - analog inputs');
233+ writeln('1 - analog outputs');
234+ writeln('2 - digital inputs');
235+ writeln('3 - digital outputs');
236+ writeln('4 - counter inputs');
237+ writeln('5 - counter outputs');
238+ write('choose the number of required channel type:');
239+ readln(channeltype);
240+ {**********CHANNEL TYPE CHOSEN**********************************************}
241+ case channeltype of
242+ {********************ANALOG INPUTS NAMES*************************************}
243+ 0: begin
244+ infotype:=DAQmx_Dev_AI_PhysicalChans;
245+ MsgChannelNames:='Analog input names';
246+ MsgNoChannelsText:='There are no analog inputs';
247+ end;
248+ {********************ANALOG OUTPUTS NAMES************************************}
249+ 1: begin
250+ infotype:=DAQmx_Dev_AO_PhysicalChans;
251+ MsgChannelNames:='Analog output names';
252+ MsgNoChannelsText:='There are no analog outputs';
253+ end;
254+ {********************DIGITAL INPUT PORTS NAMES*******************************}
255+ 2: begin
256+ infotype:=DAQmx_Dev_DI_Ports;
257+ MsgChannelNames:='Digital input ports';
258+ MsgNoChannelsText:='There are no digital input ports';
259+ end;
260+ {********************DIGITAL OUTPUT PORTS NAMES******************************}
261+ 3:begin
262+ infotype:=DAQmx_Dev_DO_Ports;
263+ MsgChannelNames:='Digital output ports';
264+ MsgNoChannelsText:='There are no digital output ports';
265+ end;
266+ {********************COUNTER INPUT NAMES******************************}
267+ 4:begin
268+ infotype:= DAQmx_Dev_CI_PhysicalChans;
269+ MsgChannelNames:='Digital counter inputs';
270+ MsgNoChannelsText:='There are no counter inputs ';
271+ end;
272+ {********************COUNTER OUTPUT NAMES******************************}
273+ 5:begin
274+ infotype:= DAQmx_Dev_CO_PhysicalChans;
275+ MsgChannelNames:='Digital counter outputs';
276+ MsgNoChannelsText:='There are no counter outputs ';
277+ end;
278+ end;
279+{************GET CHANNEL NAMES*********************************************}
280+ if (channeltype>=0) and (channeltype<6) then begin
281+ //get buffer size or length of channelnames
282+ buffersize:=DAQmxGetDeviceAttribute(@DeviceName[1],infotype,Nil);
283+ if buffersize<>0 then begin
284+ SetLength(channelnames,buffersize);
285+ //get analog channel names separated by comma
286+ DAQmxGetDeviceAttribute(@DeviceName[1],infotype,channelnames[0],[buffersize]);
287+ //show info
288+ writeln(MsgChannelNames+': '+PChar(@channelnames[0]));
289+ end
290+ else writeln(MsgNoChannelsText);
291+ end;
292+end.
293+```
294+
295+Output example
296+
297+```text
298+Enter device name, for example Dev1, Dev2 etc.: Dev1
299+0 - analog inputs
300+1 - analog outputs
301+2 - digital inputs
302+3 - digital outputs
303+4 - counter inputs
304+5 - counter outputs
305+choose the number of required channel type:0
306+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
307+```
308+
309+### ANALOG INPUTS/OUTPUTS
310+
311+#### Acquire finite number of samples from one analog input
312+
313+``` pascal
314+program aichan;
315+
316+{$mode objfpc}{$H+}
317+
318+uses
319+ {$IFDEF UNIX}{$IFDEF UseCThreads}
320+ cthreads,
321+ {$ENDIF}{$ENDIF}
322+ Classes, nidaqmx
323+ { you can add units after this };
324+var
325+ AITaskHandle:TaskHandle;
326+ data:array[1..1000] of double;
327+ reads,i:longint;
328+
329+{************Error handling procedure *****************************************
330+ Example:
331+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
332+
333+*******************************************************************************}
334+
335+procedure ErrorCheck(AError:longint;ATaskHandle:longint);
336+var
337+ errBuffer:array[0..2048] of char;
338+begin
339+ //get error description
340+ if Aerror<>0 then begin
341+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
342+ writeln(PChar(@ErrBuffer[0]));
343+ //stop and cleat task
344+ if Assigned(@ATaskHandle) then begin
345+ DAQmxStopTask(ATaskHandle);
346+ DAQmxClearTask(ATaskHandle);
347+ end;
348+ //stop program
349+ Halt;
350+ end;
351+end;
352+{*********************MAIN PROGRAM*********************************************
353+ ******************* without error handling************************************}
354+begin
355+ //create task
356+ DAQmxCreateTask('',@AITaskHandle);
357+ //create analog input channel Dev1/ai0 (activate it)
358+ //voltage range -10 - 10
359+ DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL);
360+ //set timing
361+ //Sample rate = 10000 (10 kHz), sample per channel =1000
362+ //acquire finite samples (1000 samples) defined by DAQmx_Val_FiniteSamps
363+ DAQmxCfgSampClkTiming(AITaskHandle,'OnboardClock',10000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000);
364+ //start task
365+ DAQmxStartTask(AITaskHandle);
366+ //acquire 1000 samples
367+ DAQmxReadAnalogF64(AITaskHandle,1000,10.0,DAQmx_Val_GroupByChannel,@data[1],1000,@reads,NIL);
368+ //show first 10 samples
369+ writeln(reads,' samples were acquired');
370+ writeln('');
371+ writeln('Value of first 10 samples');
372+ for i:=1 to 10 do writeln('sample[',i,'] = ',data[i]:4:2,' V');
373+ //stop and clear task
374+ DAQmxStopTask(AITaskHandle);
375+ DAQmxClearTask(AITaskHandle);
376+end.
377+```
378+
379+Output example
380+
381+```text
382+1000 samples were acquired
383+
384+Value of first 10 samples
385+sample[1] = 0.23 V
386+sample[2] = 0.23 V
387+sample[3] = 0.23 V
388+sample[4] = 0.23 V
389+sample[5] = 0.23 V
390+sample[6] = 0.23 V
391+sample[7] = 0.23 V
392+sample[8] = 0.23 V
393+sample[9] = 0.23 V
394+sample[10] = 0.23 V
395+```
396+
397+#### Continuously acquire samples from three analog inputs
398+
399+``` pascal
400+program multiaichannel;
401+
402+{$mode objfpc}{$H+}
403+
404+uses
405+ {$IFDEF UNIX}{$IFDEF UseCThreads}
406+ cthreads,
407+ {$ENDIF}{$ENDIF}
408+ Classes, nidaqmx,crt
409+ { you can add units after this };
410+var
411+ AITaskHandle:TaskHandle;
412+ data:array of double;
413+ reads:longint;
414+ totalsamplereads:longint=0;
415+ i:longint;
416+
417+{************Error handling procedure *****************************************
418+ Example:
419+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
420+
421+*******************************************************************************}
422+
423+procedure ErrorCheck(AError:longint;ATaskHandle:longint);
424+var
425+ errBuffer:array[0..2048] of char;
426+begin
427+ //get error description
428+ if Aerror<>0 then begin
429+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
430+ writeln(PChar(@ErrBuffer[0]));
431+ //stop and cleat task
432+ if Assigned(@ATaskHandle) then begin
433+ DAQmxStopTask(ATaskHandle);
434+ DAQmxClearTask(ATaskHandle);
435+ end;
436+ //stop program
437+ Halt;
438+ end;
439+end;
440+{*********************MAIN PROGRAM*********************************************
441+ ******************* without error handling************************************}
442+begin
443+ //Set buffer size for data acquiring, sample per channel 1000
444+ //buffer size(data -array variable) = 3 channel * 1000 samples per channel
445+ Setlength(data,3*1000);
446+ //create task
447+ DAQmxCreateTask('',@AITaskHandle);
448+ //create analog input channel Dev1/ai0:2 (activate 3 channels)
449+ //voltage range -10 - 10
450+ DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0:2','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL);
451+ //set timing
452+ //Sample rate = 10000 (10 kHz), sample per channel =1000
453+ //acquire finite samples (1000 samples) defined by DAQmx_Val_Cont_Samps
454+ DAQmxCfgSampClkTiming(AITaskHandle,'OnboardClock',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000);
455+ //start task
456+ DAQmxStartTask(AITaskHandle);
457+ //acquire 10000 samples for each channel
458+ while totalsamplereads<10000 do begin
459+ //1000- sample rate, 3000 - buffer size(data -array variable) = 3 channel * 1000 samples per channel
460+ DAQmxReadAnalogF64(AITaskHandle,1000,10.0,DAQmx_Val_GroupByChannel,@data[0],3000,@reads,NIL);
461+ totalsamplereads:=totalsamplereads+reads;
462+ writeln('aquired number of samples: ',totalsamplereads);
463+ end;
464+ //show first 10 samples from last 1000 samples acquired from each channel
465+ writeln('');
466+ writeln('Value of first 10 samples of last 1000 samples for each channel');
467+ writeln('| chan0 | chan1 | chan2 | ');
468+ for i:= 0 to 9 do writeln('|',data[i]:5:2,' V| ',data[i+1000]:5:2,' V| ',data[i+2000]:5:2,' V|');
469+ //stop and clear task
470+ DAQmxStopTask(AITaskHandle);
471+ DAQmxClearTask(AITaskHandle);
472+end.
473+```
474+
475+Output example
476+
477+```text
478+acquired number of samples: 1000
479+aquired number of samples: 2000
480+acquired number of samples: 3000
481+acquired number of samples: 4000
482+acquired number of samples: 5000
483+acquired number of samples: 6000
484+acquired number of samples: 7000
485+acquired number of samples: 8000
486+acquired number of samples: 9000
487+acquired number of samples: 10000
488+
489+Value of first 10 samples of last 1000 samples for each channel
490+| chan0 | chan1 | chan2 |
491+| 5.07 V| 5.07 V| 5.06 V|
492+| 5.07 V| 5.07 V| 5.06 V|
493+| 5.07 V| 5.06 V| 5.07 V|
494+| 5.06 V| 5.06 V| 5.07 V|
495+| 5.06 V| 5.07 V| 5.07 V|
496+| 5.07 V| 5.07 V| 5.06 V|
497+| 5.07 V| 5.07 V| 5.07 V|
498+| 5.06 V| 5.06 V| 5.07 V|
499+| 5.06 V| 5.06 V| 5.06 V|
500+| 5.07 V| 5.07 V| 5.06 V|
501+```
502+
503+#### Start acquisition on analog input by digital trigger
504+
505+This example demonstrates how to start acquisition by digital trigger.
506+
507+``` pascal
508+program aidigtrig;
509+
510+{$mode objfpc}{$H+}
511+
512+uses
513+ {$IFDEF UNIX}{$IFDEF UseCThreads}
514+ cthreads,
515+ {$ENDIF}{$ENDIF}
516+ Classes,nidaqmx,crt
517+ { you can add units after this };
518+var
519+ AITaskHandle:TaskHandle;
520+ channel:string = 'Dev1/ai0';
521+ SampleRate:double = 10000;
522+ SamplePerChannel:longint = 1000;
523+ PretriggerSamples: longint= 100; //MUST be > 2
524+ reads:longint = 0;
525+ i:longint;
526+ data:array of double;
527+procedure ErrorCheck(AError:longint;ATaskHandle:longint);
528+var
529+ errBuffer:array[0..2048] of char;
530+begin
531+ //get error description
532+ if Aerror<>0 then begin
533+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
534+ writeln(ErrBuffer);
535+ //stop and cleat task
536+ if Assigned(@ATaskHandle) then begin
537+ DAQmxStopTask(ATaskHandle);
538+ DAQmxClearTask(ATaskHandle);
539+ end;
540+ //stop acquisition
541+ writeln('Program stoped');
542+ Halt;
543+ end;
544+end;
545+
546+begin
547+ //set buffer length
548+ SetLength(data,SamplePerChannel);
549+ //create take
550+ DAQmxCreateTask('',@AITaskHandle);
551+ //create ai channel
552+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,@channel[1],'',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,Nil),AITaskHandle);
553+ //configure sample clock
554+ ErrorCheck(DAQmxCfgSampClkTiming(AITaskHandle,'',SampleRate,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,SamplePerChannel),AITaskHandle);
555+ //configure triger with 100 pretriggered samples
556+ ErrorCheck(DAQmxCfgDigEdgeRefTrig(AITaskHandle,'/Dev1/PFI0',DAQmx_Val_Rising,PretriggerSamples),AITaskHandle);
557+ //start task
558+ ErrorCheck(DAQmxStartTask(AITaskHandle),AITaskHandle);
559+ //acquire data
560+ writeln('Press any key to stop acquisition');
561+ i := 0;
562+ repeat
563+ ErrorCheck(DAQmxReadAnalogF64(AITaskHandle,SamplePerChannel,10.0,DAQmx_Val_GroupByChannel,@data[0],Length(data),@reads,Nil),AITaskHandle);
564+ i := i + reads;
565+ writeln('Number of acquired samples: ', i);
566+ until keypressed;
567+ //show last readed number of samples
568+ for i:=Low(data) to High(data) do writeln('data[',i,'] = ', data[i]:4:2);
569+
570+ //stop and clear task
571+ if Assigned(@AITaskHandle) then begin
572+ DAQmxStopTask(AITaskHandle);
573+ DAQmxClearTask(AITaskHandle);
574+ end;
575+end.
576+```
577+
578+#### Analog output software controlled
579+
580+This example demonstrates sinusoidal waveform generation with software timed control analog output.
581+
582+``` pascal
583+program aochansw;
584+
585+{$mode objfpc}{$H+}
586+
587+uses
588+ {$IFDEF UNIX}{$IFDEF UseCThreads}
589+ cthreads,
590+ {$ENDIF}{$ENDIF}
591+ Classes,Crt,SysUtils,nidaqmx
592+ { you can add units after this };
593+var
594+ AOTaskHandle:TaskHandle;
595+ //data writted to analog output
596+ data:array [0..999] of double;
597+ writtensamples:integer;
598+ i:integer;
599+
600+ {************Error handling procedure *****************************************
601+ Example:
602+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
603+ *******************************************************************************}
604+procedure ErrorCheck(AError:longint;ATaskHandle:longint);
605+var
606+ errBuffer:array[0..2048] of char;
607+begin
608+ //get error description
609+ if Aerror<>0 then begin
610+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
611+ writeln(PChar(@ErrBuffer[0]));
612+ //stop and cleat task
613+ if Assigned(@ATaskHandle) then begin
614+ DAQmxStopTask(ATaskHandle);
615+ DAQmxClearTask(ATaskHandle);
616+ end;
617+ //stop program
618+ Halt;
619+ end;
620+end;
621+
622+begin
623+ //prepare data for analog output
624+ //sin waveform
625+ for i:=Low(data) to High(data) do data[i]:=9.95*sin(i*2.0*Pi/1000.0);
626+ //create task
627+ DAQmxCreateTask('',@AOTaskHandle);
628+ //configure analog output channel
629+ ErrorCheck(DAQmxCreateAOVoltageChan(AOTaskHandle,'Dev1/ao0','',-10.0,10.0,DAQmx_Val_Volts,Nil),AOTaskHandle);
630+ //start task
631+ ErrorCheck(DAQmxStartTask(AOTaskHandle),AOTaskHandle);
632+
633+ writeln('Press any key to stop generation');
634+ //continuosly waveform generation
635+ //if you call task start function (DAQmxStartTask)
636+ //before output write function (for example DAQmxWriteAnalogScalarF64)
637+ //set AutoStart parameter to 1
638+ //if output function berofe start AutoStart = 0
639+ i:=0;
640+ repeat
641+ sleep(1);
642+ ErrorCheck(DAQmxWriteAnalogScalarF64(AOTaskHandle,1,10.0,data[i],Nil),AOTaskHandle);
643+ inc(i);
644+ if i >=1000 then i:=0;
645+ until keypressed;
646+
647+ //stop and clear task
648+ if Assigned(@AOTaskHandle) then begin
649+ DAQmxStopTask(AOTaskHandle);
650+ DAQmxClearTask(AOTaskHandle);
651+ end;
652+end.
653+```
654+
655+#### Analog output hardware controlled
656+
657+This example demonstrates how to generate finite number of samples on analog output channel.
658+
659+``` pascal
660+program aochannel;
661+
662+{$mode objfpc}{$H+}
663+
664+uses
665+ {$IFDEF UNIX}{$IFDEF UseCThreads}
666+ cthreads,
667+ {$ENDIF}{$ENDIF}
668+ Classes,nidaqmx
669+ { you can add units after this };
670+
671+var
672+ AOTaskHandle:TaskHandle;
673+ //data writted to analog output
674+ data:array [0..3999] of double;
675+ writtensamples:integer;
676+ i:integer;
677+
678+ {************Error handling procedure *****************************************
679+ Example:
680+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
681+
682+*******************************************************************************}
683+
684+procedure ErrorCheck(AError:longint;ATaskHandle:longint);
685+var
686+ errBuffer:array[0..2048] of char;
687+begin
688+ //get error description
689+ if Aerror<>0 then begin
690+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
691+ writeln(PChar(@ErrBuffer[0]));
692+ //stop and cleat task
693+ if Assigned(@ATaskHandle) then begin
694+ DAQmxStopTask(ATaskHandle);
695+ DAQmxClearTask(ATaskHandle);
696+ end;
697+ //stop program
698+ Halt;
699+ end;
700+end;
701+
702+{*********************MAIN PROGRAM*********************************************
703+ }
704+begin
705+ //prepare data for analog output
706+ for i:=Low(data) to High(data) do data[i]:= 5.0*i/4000.0;
707+ //create task
708+ DAQmxCreateTask('',@AOTaskHandle);
709+ //configure analog output channel
710+ ErrorCheck(DAQmxCreateAOVoltageChan(AOTaskHandle,'Dev1/ao0','',-10.0,10.0,DAQmx_Val_Volts,Nil),AOTaskHandle);
711+ //configure clock
712+ ErrorCheck(DAQmxCfgSampClkTiming(AOTaskHandle,'',1000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,4000),AOTaskHandle);
713+ //write data to buffer
714+ ErrorCheck(DAQmxWriteAnalogF64(AOTaskHandle,4000,0,10.0,DAQmx_Val_GroupByChannel,data,@writtensamples,Nil),AOTaskHandle);
715+ //start task
716+ ErrorCheck(DAQmxStartTask(AOTaskHandle),AOTaskHandle);
717+ //wait until all samples are generated
718+ ErrorCheck(DAQmxWaitUntilTaskDone(AOTaskHandle,10.0),AOTaskHandle);
719+ //stop and clear task
720+ if Assigned(@AOTaskHandle) then begin
721+ DAQmxStopTask(AOTaskHandle);
722+ DAQmxClearTask(AOTaskHandle);
723+ end;
724+end.
725+```
726+
727+### DIGITAL INPUTS/OUTPUTS
728+
729+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.
730+
731+Read/Write data from/to 8-bit and 32-bit digital port use an appropriate function **DAQmxReadDigitalU8**, **DAQmxWriteDigitalU8** and **DAQmxReadDigitalU32**, **DAQmxWriteDigitalU32**.
732+
733+*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!!!*
734+
735+#### Software timed digital input
736+
737+To check it, connected +5V(depend on hardware) to one of available port pins.
738+
739+``` pascal
740+program diport;
741+
742+{$mode objfpc}{$H+}
743+
744+uses
745+ {$IFDEF UNIX}{$IFDEF UseCThreads}
746+ cthreads,
747+ {$ENDIF}{$ENDIF}
748+ Classes,nidaqmx,SysUtils,StrUtils
749+ { you can add units after this };
750+var
751+ DITaskHandle:TaskHandle;
752+ data:array [0..9] of byte;
753+ reads:longint = 0;
754+ totalreads:longint = 0;
755+ i:longint ;
756+{************Error handling procedure *****************************************
757+ Example:
758+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
759+
760+ *******************************************************************************}
761+
762+ procedure ErrorCheck(AError:longint;ATaskHandle:longint);
763+ var
764+ errBuffer:array[0..2048] of char;
765+ begin
766+ //get error description
767+ if Aerror<>0 then begin
768+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
769+ writeln(PChar(@ErrBuffer[0]));
770+ //stop and cleat task
771+ if Assigned(@ATaskHandle) then begin
772+ DAQmxStopTask(ATaskHandle);
773+ DAQmxClearTask(ATaskHandle);
774+ end;
775+ //stop program
776+ Halt;
777+ end;
778+ end;
779+{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
780+begin
781+ //task create
782+ ErrorCheck(DAQmxCreateTask('',@DITaskHandle),DITaskHandle);
783+ //digital input port create
784+ ErrorCheck(DAQmxCreateDIChan(DITaskHandle,'Dev1/port1','',DAQmx_Val_ChanForAllLines),DITaskHandle);
785+ //Start Task
786+ ErrorCheck(DAQmxStartTask(DITaskHandle),DITaskHandle);
787+ //read 10 samples from 8-bit digital port (for example NI PCI-6250 card port1(pins P1.0-P1.7))
788+ //for 32-bit digital port use DAQmxReadDigitalU32 function
789+ ErrorCheck(DAQmxReadDigitalU8(DITaskHandle,10,10.0,DAQmx_Val_GroupByChannel,@data,10,@reads,Nil),DITaskHandle);
790+ writeln('number of readed samples: ',reads);
791+ for i:=0 to 9 do writeln('data [',i,'] = %',IntToBin(data[i],8));
792+ //stop and clear task
793+ if DITaskHandle<>0 then begin
794+ DAQmxStopTask(DITaskHandle);
795+ DAQmxClearTask(DITaskHandle);
796+ end;
797+end.
798+```
799+
800+Output example: +5V connected to pin P1.2 port1 on NI-PCI6250 card.
801+
802+```text
803+number of readed samples: 10
804+data [0] = %00000100
805+data [1] = %00000100
806+data [2] = %00000100
807+data [3] = %00000100
808+data [4] = %00000100
809+data [5] = %00000100
810+data [6] = %00000100
811+data [7] = %00000100
812+data [8] = %00000100
813+data [9] = %00000100
814+```
815+
816+#### Hardware timed digital input
817+
818+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.
819+
820+To check it, connected +5V(depend on hardware) to one of available pins on correlated digital port.
821+
822+``` pascal
823+program diporttimed;
824+
825+{$mode objfpc}{$H+}
826+
827+uses
828+ {$IFDEF UNIX}{$IFDEF UseCThreads}
829+ cthreads,
830+ {$ENDIF}{$ENDIF}
831+ Classes,nidaqmx,SysUtils,StrUtils
832+ { you can add units after this };
833+var
834+ DITaskHandle,CtrTaskHandle:TaskHandle;
835+ data:array [0..9] of byte;
836+ reads:longint = 0;
837+ totalreads:longint = 0;
838+ i:longint ;
839+{************Error handling procedure *****************************************
840+ Example:
841+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
842+
843+ *******************************************************************************}
844+
845+ procedure ErrorCheck(AError:longint;ATaskHandle:longint);
846+ var
847+ errBuffer:array[0..2048] of char;
848+ begin
849+ //get error description
850+ if Aerror<>0 then begin
851+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
852+ writeln(PChar(@ErrBuffer[0]));
853+ //stop and cleat task
854+ if Assigned(@ATaskHandle) then begin
855+ DAQmxStopTask(ATaskHandle);
856+ DAQmxClearTask(ATaskHandle);
857+ end;
858+ //stop program
859+ Halt;
860+ end;
861+ end;
862+{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
863+begin
864+ {******CREATE COUNTER OUTPUT TO USE IT AS CLOCK FOR DIGITAL PORT INPUTS******
865+ *******INTERNALLY CONNECTED ON M-SERIES as /Dev1/Ctr0InternalOutput**********}
866+ //create couter task
867+ ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
868+ //create counter output channel
869+ //Frequency 1000 Hz, duty 0.5
870+ ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,1000,0.5),CtrTaskHandle);
871+ //timing 1000 samples per second
872+ ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
873+ //start counter task
874+ ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
875+
876+ //digital input task create
877+ ErrorCheck(DAQmxCreateTask('Digital input task',@DITaskHandle),DITaskHandle);
878+ //digital input port create
879+ ErrorCheck(DAQmxCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
880+ //timing use counter output as clock source internally connected
881+ //as /Dev1/Ctr0InternalOutput
882+ ErrorCheck(DAQmxCfgSampClkTiming(DITaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000),DITaskHandle);
883+ //Start digital input Task
884+ ErrorCheck(DAQmxStartTask(DITaskHandle),DITaskHandle);
885+ //read 10 samples from 8-bit digital port for example correlated port0
886+ //for 32-bit digital port use DAQmxReadDigitalU32 function
887+ ErrorCheck(DAQmxReadDigitalU8(DITaskHandle,10,10.0,DAQmx_Val_GroupByChannel,@data,10,@reads,Nil),DITaskHandle);
888+ writeln('number of readed samples: ',reads);
889+ for i:=0 to 9 do writeln('data [',i,'] = %',IntToBin(data[i],8));
890+ //stop and clear task
891+ DAQmxStopTask(DITaskHandle);
892+ DAQmxClearTask(DITaskHandle);
893+ DAQmxStopTask(CtrTaskHandle);
894+ DAQmxClearTask(CtrTaskHandle);
895+end.
896+```
897+
898+Output example: +5V connected to pin P0.5 on port0 on NI-PCI6250 card.
899+
900+```text
901+number of readed samples: 10
902+data [0] = %00100000
903+data [1] = %00100000
904+data [2] = %00100000
905+data [3] = %00100000
906+data [4] = %00100000
907+data [5] = %00100000
908+data [6] = %00100000
909+data [7] = %00100000
910+data [8] = %00100000
911+data [9] = %00100000
912+```
913+
914+#### Software controlled digital output
915+
916+To check it connect digital output(s) to oscilloscope or to card analog input.
917+
918+``` pascal
919+program doportlpi;
920+
921+{$mode objfpc}{$H+}
922+
923+uses
924+ {$IFDEF UNIX}{$IFDEF UseCThreads}
925+ cthreads,
926+ {$ENDIF}{$ENDIF}
927+ Classes,nidaqmx,SysUtils,StrUtils
928+ { you can add units after this };
929+var
930+ DOTaskHandle:TaskHandle;
931+ data: byte;
932+ written:longint = 0;
933+{************Error handling procedure *****************************************
934+ Example:
935+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
936+
937+ *******************************************************************************}
938+
939+ procedure ErrorCheck(AError:longint;ATaskHandle:longint);
940+ var
941+ errBuffer:array[0..2048] of char;
942+ begin
943+ //get error description
944+ if Aerror<>0 then begin
945+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
946+ writeln(PChar(@ErrBuffer[0]));
947+ //stop and cleat task
948+ if Assigned(@ATaskHandle) then begin
949+ DAQmxStopTask(ATaskHandle);
950+ DAQmxClearTask(ATaskHandle);
951+ end;
952+ //stop program
953+ Halt;
954+ end;
955+ end;
956+{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
957+begin
958+ //task create
959+ ErrorCheck(DAQmxCreateTask('',@DOTaskHandle),DOTaskHandle);
960+ //digital input port create
961+ ErrorCheck(DAQmxCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
962+ //task start
963+ //no need to start task
964+ ErrorCheck(DAQmxStartTask(DOTaskHandle),DOTaskHandle);
965+ //for 32-bit digital port use DAQmxReadDigitalU32 function
966+ //set 1 on all lines of digital port
967+ //change data:=0 to set 0 or use DAQmxResetDevice function to
968+ data:=0;
969+ ErrorCheck(DAQmxWriteDigitalU8(DOTaskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,@data,@written,Nil),DOTaskHandle);
970+ //use DAQmxResetDevice function here to set signal on Low state
971+ writeln('number of written samples: ',written);
972+ //stop and clear task
973+ if DOTaskHandle<>0 then begin
974+ DAQmxStopTask(DOTaskHandle);
975+ DAQmxClearTask(DOTaskHandle);
976+ end;
977+end.
978+```
979+
980+#### Hardware timed digital outputs with counter output used as source clock
981+
982+To check it connect digital output(s) to oscilloscope or to card analog input.
983+
984+``` pascal
985+program doporttimed;
986+
987+{$mode objfpc}{$H+}
988+
989+uses
990+ {$IFDEF UNIX}{$IFDEF UseCThreads}
991+ cthreads,
992+ {$ENDIF}{$ENDIF}
993+ Classes,nidaqmx,SysUtils,StrUtils,Crt
994+ { you can add units after this };
995+var
996+ DOTaskHandle,CtrTaskHandle:TaskHandle;
997+ data:array[0..7] of byte = (1,2,4,8,16,32,64,128);
998+ written:longint = 0;
999+{************Error handling procedure *****************************************
1000+ Example:
1001+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
1002+
1003+ *******************************************************************************}
1004+
1005+ procedure ErrorCheck(AError:longint;ATaskHandle:longint);
1006+ var
1007+ errBuffer:array[0..2048] of char;
1008+ begin
1009+ //get error description
1010+ if Aerror<>0 then begin
1011+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
1012+ writeln(PChar(@ErrBuffer[0]));
1013+ //stop and cleat task
1014+ if Assigned(@ATaskHandle) then begin
1015+ DAQmxStopTask(ATaskHandle);
1016+ DAQmxClearTask(ATaskHandle);
1017+ end;
1018+ //stop program
1019+ Halt;
1020+ end;
1021+ end;
1022+{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
1023+begin
1024+ {******CREATE COUNTER OUTPUT TO USE IT AS CLOCK FOR DIGITAL PORT OUTPUTS******
1025+ *******INTERNALLY CONNECTED ON M-SERIES as /Dev1/Ctr0InternalOutput**********}
1026+ //create couter task
1027+ ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
1028+ //create counter output channel
1029+ //Frequency 1000 Hz, duty 0.5
1030+ ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
1031+ //timing 1000 samples per second
1032+ ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
1033+ //start task
1034+ //start counter task
1035+ ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
1036+
1037+ //task create
1038+ ErrorCheck(DAQmxCreateTask('',@DOTaskHandle),DOTaskHandle);
1039+ //digital input port create
1040+ ErrorCheck(DAQmxCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
1041+ //timing
1042+ //frequency 1000Hz
1043+ ErrorCheck(DAQmxCfgSampClkTiming(DOTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),DOTaskHandle);
1044+ //for 32-bit digital port use DAQmxWriteDigitalU32 function
1045+ //function sets to start task automaticly 3-rd parameter
1046+ //write 8 samples
1047+ ErrorCheck(DAQmxWriteDigitalU8(DOTaskHandle,8,1,10.0,DAQmx_Val_GroupByChannel,data,@written,Nil),DOTaskHandle);
1048+ writeln('number of written samples: ',written);
1049+ //stop and clear task
1050+ DAQmxStopTask(DOTaskHandle);
1051+ DAQmxClearTask(DOTaskHandle);
1052+ DAQmxStopTask(CtrTaskHandle);
1053+ DAQmxClearTask(CtrTaskHandle);
1054+end.
1055+```
1056+
1057+### COUNTER INPUTS/OUTPUTS
1058+
1059+#### Pulse generation
1060+
1061+This example demonstrates pwm generaton with frequency 1000Hz and duty circle 0.5.
1062+
1063+``` pascal
1064+program doporttimed;
1065+
1066+{$mode objfpc}{$H+}
1067+
1068+uses
1069+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1070+ cthreads,
1071+ {$ENDIF}{$ENDIF}
1072+ Classes,nidaqmx,SysUtils,StrUtils,Crt
1073+ { you can add units after this };
1074+var
1075+ CtrTaskHandle:TaskHandle;
1076+ {************Error handling procedure *****************************************
1077+ Example:
1078+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
1079+
1080+ *******************************************************************************}
1081+
1082+ procedure ErrorCheck(AError:longint;ATaskHandle:longint);
1083+ var
1084+ errBuffer:array[0..2048] of char;
1085+ begin
1086+ //get error description
1087+ if Aerror<>0 then begin
1088+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
1089+ writeln(PChar(@ErrBuffer[0]));
1090+ //stop and cleat task
1091+ if Assigned(@ATaskHandle) then begin
1092+ DAQmxStopTask(ATaskHandle);
1093+ DAQmxClearTask(ATaskHandle);
1094+ end;
1095+ //stop program
1096+ Halt;
1097+ end;
1098+ end;
1099+{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
1100+begin
1101+ //create couter task
1102+ ErrorCheck(DAQmxCreateTask('Counter Task',@CtrTaskHandle),CtrTaskHandle);
1103+ //create counter output channel
1104+ //Frequency 1000 Hz, duty 0.5
1105+ ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
1106+ //timing 1000 samples per second
1107+ ErrorCheck(DAQmxCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,1000),CtrTaskHandle);
1108+ //start task
1109+ ErrorCheck(DAQmxStartTask(CtrTaskHandle),CtrTaskHandle);
1110+
1111+ writeln('Press any key to stop generation');
1112+ repeat
1113+ until keypressed;
1114+
1115+ DAQmxStopTask(CtrTaskHandle);
1116+ DAQmxClearTask(CtrTaskHandle);
1117+end.
1118+```
1119+
1120+#### Event counting
1121+
1122+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.
1123+
1124+``` pascal
1125+program eventcounting;
1126+
1127+{$mode objfpc}{$H+}
1128+
1129+uses
1130+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1131+ cthreads,
1132+ {$ENDIF}{$ENDIF}
1133+ Classes,nidaqmx,SysUtils,StrUtils,Crt
1134+ { you can add units after this };
1135+var
1136+ CtrOutTaskHandle,CtrInTaskHandle:TaskHandle;
1137+ reads:cardinal=0;
1138+ data:array [0..999] of longint;
1139+ i:longint;
1140+{************Error handling procedure *****************************************
1141+ Example:
1142+ ErrorCheck(DAQmxCreateAIVoltageChan(AITaskHandle,'Dev0/ai0','',DAQmx_Val_RSE,-10.0,10.0,DAQmx_Val_Volts,NIL),AITaskHandle);
1143+
1144+ *******************************************************************************}
1145+ procedure ErrorCheck(AError:longint;ATaskHandle:longint);
1146+ var
1147+ errBuffer:array[0..2048] of char;
1148+ begin
1149+ //get error description
1150+ if Aerror<>0 then begin
1151+ DAQmxGetExtendedErrorInfo(@ErrBuffer[0],2048);
1152+ writeln(PChar(@ErrBuffer[0]));
1153+ //stop and cleat task
1154+ if Assigned(@ATaskHandle) then begin
1155+ DAQmxStopTask(ATaskHandle);
1156+ DAQmxClearTask(ATaskHandle);
1157+ end;
1158+ //stop program
1159+ Halt;
1160+ end;
1161+ end;
1162+{*******************MAIN PROGRAM WITH ERROR HANDLING*************************}
1163+begin
1164+ {****************CREATE COUNTER OUTPUT***************************************}
1165+ //create couter output task
1166+ ErrorCheck(DAQmxCreateTask('Counter output task',@CtrOutTaskHandle),CtrOutTaskHandle);
1167+ //create counter output channel
1168+ //Frequency 1000 Hz, duty 0.5
1169+ ErrorCheck(DAQmxCreateCOPulseChanFreq(CtrOutTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrOutTaskHandle);
1170+ //timing 1000 samples per second
1171+ ErrorCheck(DAQmxCfgImplicitTiming(CtrOutTaskHandle,DAQmx_Val_ContSamps,1000),CtrOutTaskHandle);
1172+ //start counter output task
1173+ ErrorCheck(DAQmxStartTask(CtrOutTaskHandle),CtrOutTaskHandle);
1174+
1175+ {*****************CREATE COUNTER INPUT***************************************}
1176+ //create couter output task
1177+ ErrorCheck(DAQmxCreateTask('Counter input task',@CtrInTaskHandle),CtrInTaskHandle);
1178+ //create input counter for pulse counting
1179+ ErrorCheck(DAQmxCreateCICountEdgesChan(CtrInTaskHandle,'Dev1/ctr1','',DAQmx_Val_Rising,0,DAQmx_Val_CountUp),CtrInTaskHandle);
1180+ //timing
1181+ ErrorCheck(DAQmxCfgSampClkTiming(CtrInTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),CtrInTaskHandle);
1182+ //start counter input task
1183+ ErrorCheck(DAQmxStartTask(CtrInTaskHandle),CtrInTaskHandle);
1184+ //counting pulses
1185+ ErrorCheck(DAQmxReadCounterU32(CtrIntaskHandle,1000,10.0,@data,1000,@reads,Nil),CtrIntaskHandle);
1186+ writeln('acquired samples: ',reads);
1187+ for i:=0 to 10 do writeln('sample[',i,'] = ',data[i]);
1188+
1189+ //stop and clear tasks
1190+ DAQmxStopTask(CtrInTaskHandle);
1191+ DAQmxClearTask(CtrInTaskHandle);
1192+ DAQmxStopTask(CtrOutTaskHandle);
1193+ DAQmxClearTask(CtrOutTaskHandle);
1194+end.
1195+```
1196+
1197+### TESTED HARDWARE
1198+
1199+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:
1200+
1201+- **NI PCI-6250**
1202+- **NI PCI-6224**
1203+
1204+- **NI PXIe-6612 (Windows only)**
1205+
1206+- **NI USB-6356 (Windows only)**
1207+
1208+- **NI USB-6003 (Windows only)**
1209+
1210+## NI-DAQxmxBase examples
1211+
1212+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.
1213+
1214+**Read readme file to check card supported features!!!**
1215+
1216+### DEVICE INFO
1217+
1218+Functions, which provide device and channel information, are not implemented in this library, yet.
1219+
1220+### ANALOG INPUTS/OUTPUTS
1221+
1222+#### Acquire finite number of samples from one analog channel
1223+
1224+``` pascal
1225+program aichannel;
1226+
1227+{$mode objfpc}{$H+}
1228+
1229+uses
1230+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1231+ cthreads,
1232+ {$ENDIF}{$ENDIF}
1233+ Classes,nidaqmxbase;
1234+ { you can add units after this }
1235+var
1236+ AITaskHandle: PTaskHandle;
1237+ NiBool:Pnibool;
1238+ reads:longint=0;
1239+ i:byte;
1240+ data:array [1..1000] of double;
1241+procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
1242+var
1243+ errBuffer:array[0..2048] of char;
1244+ errMessage:string;
1245+begin
1246+ //get error description
1247+ if DAQmxFailed(AError) = niTrue then begin
1248+ DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
1249+ writeln(ErrBuffer);
1250+ //stop and cleat task
1251+ if Assigned(ATaskHandle) then begin
1252+ DAQmxBaseStopTask(ATaskHandle);
1253+ DAQmxBaseClearTask(ATaskHandle);
1254+ end;
1255+ //stop program
1256+ Halt;
1257+ end;
1258+end;
1259+
1260+begin
1261+ //create task
1262+ ErrorCheck(DAQmxBaseCreateTask ('', AITaskHandle),AITaskHandle);
1263+ //create analog input channel
1264+ ErrorCheck(DAQmxBaseCreateAIVoltageChan(AITaskHandle,'Dev1/ai0','', DAQmx_Val_RSE,-10, 10,DAQmx_Val_Volts,''),AITaskHandle);
1265+ //timing
1266+ //clock frequency 1000 Hz, sample rate 1000 per second
1267+ //if you use more than one active channel, generally sample rate = clock frequency/(active analog channles*10);
1268+ ErrorCheck(DAQmxBaseCfgSampClkTiming (AITaskHandle,'OnboardClock',1000,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000),AITaskHandle);
1269+ //start task
1270+ ErrorCheck(DAQmxBaseStartTask(AITaskHandle),AITaskHandle);
1271+ //read 1000 samples
1272+ ErrorCheck(DAQmxBaseReadAnalogF64 (AITaskHandle, 1000, 10.0,DAQmx_Val_GroupByChannel,data,1000,reads,NIBool^),AITaskHandle);
1273+ //acquired sample number
1274+ writeln(reads,' samples were acqiured');
1275+ //show value of first ten samples
1276+ for i:=1 to 10 do writeln('sample[',i,'] = ',data[i]:4:2,' V');
1277+ //stop and clear task
1278+ DAQmxBaseStopTask(AITaskHandle);
1279+ DAQmxBaseClearTask(AITaskHandle);
1280+end.
1281+```
1282+
1283+Output example +5V connected to pin 68 on NI PCI-6250
1284+
1285+```text
1286+1000 samples were acqiured
1287+sample[1] = 5.07 V
1288+sample[2] = 5.06 V
1289+sample[3] = 5.06 V
1290+sample[4] = 5.06 V
1291+sample[5] = 5.06 V
1292+sample[6] = 5.06 V
1293+sample[7] = 5.06 V
1294+sample[8] = 5.06 V
1295+sample[9] = 5.06 V
1296+sample[10] = 5.07 V
1297+```
1298+
1299+#### Continuously acquire samples from three analog inputs
1300+
1301+``` pascal
1302+program ai3contacq;
1303+
1304+{$mode objfpc}{$H+}
1305+
1306+uses
1307+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1308+ cthreads,
1309+ {$ENDIF}{$ENDIF}
1310+ Classes,nidaqmxbase;
1311+ { you can add units after this }
1312+var
1313+ AITaskHandle: PTaskHandle;
1314+ NiBool:Pnibool;
1315+ reads:longint=0;
1316+ totalreads:longint=0;
1317+ i:byte;
1318+ data:array of double;
1319+ acqnumsamples:longint;
1320+procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
1321+var
1322+ errBuffer:array[0..2048] of char;
1323+ errMessage:string;
1324+begin
1325+ //get error description
1326+ if DAQmxFailed(AError) = niTrue then begin
1327+ DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
1328+ writeln(ErrBuffer);
1329+ //stop and cleat task
1330+ if Assigned(ATaskHandle) then begin
1331+ DAQmxBaseStopTask(ATaskHandle);
1332+ DAQmxBaseClearTask(ATaskHandle);
1333+ end;
1334+ //stop program
1335+ Halt;
1336+ end;
1337+end;
1338+
1339+begin
1340+ //enter number of total samples for each channel to be acquired
1341+ write('Enter a number of samples for each channel to be acquired: ');
1342+ readln(acqnumsamples);
1343+ //Set buffer size = length of data array:=number of active channels * sample per channel
1344+ Setlength(data,3*1000);
1345+ //create task
1346+ ErrorCheck(DAQmxBaseCreateTask ('', AITaskHandle),AITaskHandle);
1347+ //create analog input channel - 3 active analog inputs
1348+ ErrorCheck(DAQmxBaseCreateAIVoltageChan(AITaskHandle,'Dev1/ai0:2','', DAQmx_Val_RSE,-10, 10,DAQmx_Val_Volts,''),AITaskHandle);
1349+ //timing
1350+ //clock frequency 10000 Hz, sample rate 1000 per second
1351+ //if you use more than one active channel, generally sample rate = clock frequency/(active analog channles*10);
1352+ ErrorCheck(DAQmxBaseCfgSampClkTiming (AITaskHandle,'OnboardClock',10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),AITaskHandle);
1353+ //start task
1354+ ErrorCheck(DAQmxBaseStartTask(AITaskHandle),AITaskHandle);
1355+ //read samples
1356+ while totalreads<acqnumsamples do begin
1357+ ErrorCheck(DAQmxBaseReadAnalogF64(AITaskHandle, 1000, 10.0, DAQmx_Val_GroupByChannel,data,Length(data),reads,NIBool^),AITaskHandle);
1358+ totalreads:=totalreads+reads;
1359+ writeln('total samples readed for each channel: ',totalreads);
1360+ //show first five values for each channel
1361+ 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 ');
1362+ end;
1363+ //stop and clear task
1364+ DAQmxBaseStopTask(AITaskHandle);
1365+ DAQmxBaseClearTask(AITaskHandle);
1366+end.
1367+```
1368+
1369+Output example +5V connected to pin 68 on NI PCI-6250
1370+
1371+```text
1372+Enter a number of samples for each channel to be acquired: 2000
1373+total samples readed for each channel: 1000
1374+chan1[0] = 5.07 V chan2[0] = 0.00 V chan3[0] = 0.03 V
1375+chan1[1] = 5.06 V chan2[1] = -0.00 V chan3[1] = 0.03 V
1376+chan1[2] = 5.07 V chan2[2] = -0.00 V chan3[2] = 0.02 V
1377+chan1[3] = 5.07 V chan2[3] = -0.00 V chan3[3] = 0.02 V
1378+chan1[4] = 5.06 V chan2[4] = -0.00 V chan3[4] = 0.02 V
1379+chan1[5] = 5.06 V chan2[5] = -0.00 V chan3[5] = 0.01 V
1380+total samples readed for each channel: 2000
1381+chan1[0] = 5.06 V chan2[0] = -0.00 V chan3[0] = -0.02 V
1382+chan1[1] = 5.07 V chan2[1] = -0.00 V chan3[1] = -0.02 V
1383+chan1[2] = 5.06 V chan2[2] = -0.00 V chan3[2] = -0.02 V
1384+chan1[3] = 5.07 V chan2[3] = -0.00 V chan3[3] = -0.02 V
1385+chan1[4] = 5.06 V chan2[4] = -0.00 V chan3[4] = -0.02 V
1386+chan1[5] = 5.06 V chan2[5] = -0.00 V chan3[5] = -0.02 V
1387+```
1388+
1389+### DIGITAL INPUTS/OUTPUTS
1390+
1391+Read readme file to check supported card features by NI-DAQmxBase.
1392+
1393+In case of M-series cards, correlated digital input/output is limited to about 100kHz, because DMA data transfer is not supported.
1394+
1395+#### Software timed digital input
1396+
1397+``` pascal
1398+program diport;
1399+
1400+{$mode objfpc}{$H+}
1401+
1402+uses
1403+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1404+ cthreads,
1405+ {$ENDIF}{$ENDIF}
1406+ Classes,nidaqmxbase,StrUtils
1407+ { you can add units after this };
1408+var
1409+ DITaskHandle:PTaskHandle;
1410+ NiBool:Pnibool;
1411+ data:byte;
1412+ reads:longint=0;
1413+procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
1414+var
1415+ errBuffer:array[0..2048] of char;
1416+begin
1417+ //get error description
1418+ if DAQmxFailed(AError) = niTrue then begin
1419+ DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
1420+ writeln(ErrBuffer);
1421+ //stop and cleat task
1422+ if Assigned(ATaskHandle) then begin
1423+ DAQmxBaseStopTask(ATaskHandle);
1424+ DAQmxBaseClearTask(ATaskHandle);
1425+ end;
1426+ //stop program
1427+ Halt;
1428+ end;
1429+end;
1430+begin
1431+ //create task
1432+ ErrorCheck(DAQmxBaseCreateTask('', DITaskHandle),DITaskHandle);
1433+ //create digital input port
1434+ ErrorCheck(DAQmxBaseCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
1435+ //start task
1436+ ErrorCheck(DAQmxBaseStartTask(DITaskHandle),DITaskHandle);
1437+ //read dat form port
1438+ //use DAQmxBaseReadDigitalU8 for 8 bit port
1439+ //use DAQmxBaseReadDigitalU32 for 32 bit port
1440+ ErrorCheck(DAQmxBaseReadDigitalU8(DITaskHandle,1,10.0,DAQmx_Val_GroupByChannel,data,1,reads,NiBool^),DITaskHandle);
1441+ writeln('digital port value %',IntToBin(data,8));
1442+ //stop and clear task
1443+ DAQmxBaseStopTask(DITaskHandle);
1444+ DAQmxBaseClearTask(DITaskHandle);
1445+end.
1446+```
1447+
1448+Output example: +5V connected to line 1 of 8-bit digital port
1449+
1450+```text
1451+digital port value %00000010
1452+```
1453+
1454+#### Hardware timed digital input
1455+
1456+``` pascal
1457+program diporthwtimed;
1458+
1459+{$mode objfpc}{$H+}
1460+
1461+uses
1462+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1463+ cthreads,
1464+ {$ENDIF}{$ENDIF}
1465+ Classes,nidaqmxbase,StrUtils
1466+ { you can add units after this };
1467+var
1468+ DITaskHandle,CtrTaskHandle:PTaskHandle;
1469+ NiBool:Pnibool;
1470+ data:array of byte;
1471+ reads:longint=0;
1472+ i:longint;
1473+procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
1474+var
1475+ errBuffer:array[0..2048] of char;
1476+begin
1477+ //get error description
1478+ if DAQmxFailed(AError) = niTrue then begin
1479+ DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
1480+ writeln(ErrBuffer);
1481+ //stop and cleat task
1482+ if Assigned(ATaskHandle) then begin
1483+ DAQmxBaseStopTask(ATaskHandle);
1484+ DAQmxBaseClearTask(ATaskHandle);
1485+ end;
1486+ //stop program
1487+ Halt;
1488+ end;
1489+end;
1490+begin
1491+
1492+ {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
1493+ //create counter task
1494+ ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
1495+ //create counter output channel
1496+ //Frequency 10000 Hz, duty 0.5
1497+ ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
1498+ //timing
1499+ //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
1500+ ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
1501+ //start counter task
1502+ ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
1503+
1504+ {*******************HW TIMED DIGITAL INPUT***********************************
1505+ **********LIMITED TO 10kHz,DMA IS NOT IMPLEMENTED****************************}
1506+ //configure buffer for 1000 samples
1507+ SetLength(data,1000);
1508+ //create task
1509+ ErrorCheck(DAQmxBaseCreateTask('', DITaskHandle),DITaskHandle);
1510+ //create digital input port
1511+ ErrorCheck(DAQmxBaseCreateDIChan(DITaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DITaskHandle);
1512+ //timing frequency 10000Hz, 1000 sample per channel
1513+ ErrorCheck(DAQmxBaseCfgSampClkTiming(DITaskHandle,'/Dev1/Ctr0InternalOutput',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,10000),DITaskHandle);
1514+ //start task
1515+ ErrorCheck(DAQmxBaseStartTask(DITaskHandle),DITaskHandle);
1516+ //read dat form port
1517+ //use DAQmxBaseReadDigitalU8 for 8 bit port
1518+ //use DAQmxBaseReadDigitalU32 for 32 bit port
1519+ ErrorCheck(DAQmxBaseReadDigitalU8(DITaskHandle,10000,10.0,DAQmx_Val_GroupByChannel,data,10000,reads,NiBool^),DITaskHandle);
1520+ writeln(reads,' samples were readed');
1521+ //show first 10 samples
1522+ for i:=0 to 9 do writeln('sample[',i,'] = %',IntToBin(data[i],8));
1523+ //stop and clear task
1524+ DAQmxBaseStopTask(DITaskHandle);
1525+ DAQmxBaseClearTask(DITaskHandle);
1526+ DAQmxBaseStopTask(CtrTaskHandle);
1527+ DAQmxBaseClearTask(CtrTaskHandle);
1528+end.
1529+```
1530+
1531+Output example: +5V connected to line 1 of 8-bit digital port, executed with time command under Linux.
1532+
1533+```text
1534+10000 samples were readed
1535+sample[0] = %00000010
1536+sample[1] = %00000010
1537+sample[2] = %00000010
1538+sample[3] = %00000010
1539+sample[4] = %00000010
1540+sample[5] = %00000010
1541+sample[6] = %00000010
1542+sample[7] = %00000010
1543+sample[8] = %00000010
1544+sample[9] = %00000010
1545+
1546+real 0m4.483s
1547+user 0m4.261s
1548+sys 0m0.100s
1549+```
1550+
1551+#### Software timed digital output
1552+
1553+``` pascal
1554+program doport;
1555+
1556+{$mode objfpc}{$H+}
1557+
1558+uses
1559+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1560+ cthreads,
1561+ {$ENDIF}{$ENDIF}
1562+ Classes,nidaqmxbase,StrUtils,SysUtils
1563+ { you can add units after this };
1564+var
1565+ DOTaskHandle,CtrTaskHandle:PTaskHandle;
1566+ NiBool:Pnibool;
1567+ data: byte;
1568+ written:longint=0;
1569+ i:longint;
1570+procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
1571+var
1572+ errBuffer:array[0..2048] of char;
1573+begin
1574+ //get error description
1575+ if DAQmxFailed(AError) = niTrue then begin
1576+ DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
1577+ writeln(ErrBuffer);
1578+ //stop and cleat task
1579+ if Assigned(ATaskHandle) then begin
1580+ DAQmxBaseStopTask(ATaskHandle);
1581+ DAQmxBaseClearTask(ATaskHandle);
1582+ end;
1583+ //stop program
1584+ Halt;
1585+ end;
1586+end;
1587+begin
1588+ //write data to buffer, produce digital waveform on all port lines
1589+ data:=255;
1590+ //create task
1591+ ErrorCheck(DAQmxBaseCreateTask('', DOTaskHandle),DOTaskHandle);
1592+ //create digital input port
1593+ ErrorCheck(DAQmxBaseCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
1594+ //use DAQmxBaseWriteDigitalU8 for 8 bit port
1595+ //use DAQmxBaseWriteDigitalU32 for 32 bit port
1596+ //set third parametr to 1 to enable autostart or set to 0 and use DAQmxBaseStartTask before
1597+ //set digital "1"
1598+ writeln('set digital 1 on all port lines');
1599+ writeln('sleep 10s');
1600+ ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
1601+ sleep(10000);
1602+ writeln(written,' samples were written');
1603+ //set digital "0"
1604+ writeln('set digital 0 on all port lines');
1605+ writeln('sleep 10s');
1606+ sleep(10000);
1607+ ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
1608+ writeln(written,' samples were written');
1609+ //stop and clear task
1610+ DAQmxBaseStopTask(DOTaskHandle);
1611+ DAQmxBaseClearTask(DOTaskHandle);
1612+ DAQmxBaseStopTask(CtrTaskHandle);
1613+ DAQmxBaseClearTask(CtrTaskHandle);
1614+end.
1615+```
1616+
1617+#### Hardware timed digital output
1618+
1619+Digital output generation frequency is limited to ~100kHz, because DMA is not supported by the driver .
1620+
1621+``` pascal
1622+program doporthwtimed;
1623+
1624+{$mode objfpc}{$H+}
1625+
1626+uses
1627+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1628+ cthreads,
1629+ {$ENDIF}{$ENDIF}
1630+ Classes,nidaqmxbase,StrUtils
1631+ { you can add units after this };
1632+var
1633+ DOTaskHandle,CtrTaskHandle:PTaskHandle;
1634+ NiBool:Pnibool;
1635+ data:array of byte;
1636+ written:longint=0;
1637+ i:longint;
1638+procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
1639+var
1640+ errBuffer:array[0..2048] of char;
1641+begin
1642+ //get error description
1643+ if DAQmxFailed(AError) = niTrue then begin
1644+ DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
1645+ writeln(ErrBuffer);
1646+ //stop and cleat task
1647+ if Assigned(ATaskHandle) then begin
1648+ DAQmxBaseStopTask(ATaskHandle);
1649+ DAQmxBaseClearTask(ATaskHandle);
1650+ end;
1651+ //stop program
1652+ Halt;
1653+ end;
1654+end;
1655+begin
1656+ {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
1657+ //create counter task
1658+ ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
1659+ //create counter output channel
1660+ //Frequency 10000 Hz, duty 0.5
1661+ ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
1662+ //timing
1663+ //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
1664+ ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
1665+ //start counter task
1666+ ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
1667+ {*******************HW TIMED DIGITAL INPUT***********************************
1668+ **********LIMITED TO 10kHz,DMA IS NOT IMPLEMENTED****************************}
1669+ //configure buffer for 1000 samples
1670+ SetLength(data,1000);
1671+ //write data to buffer, produce digital waveform on all port lines
1672+ for i:=0 to 999 do if (i mod 2 = 0) then data[i]:=255;
1673+ //create task
1674+ ErrorCheck(DAQmxBaseCreateTask('', DOTaskHandle),DOTaskHandle);
1675+ //create digital input port
1676+ ErrorCheck(DAQmxBaseCreateDOChan(DOTaskHandle,'Dev1/port0','',DAQmx_Val_ChanForAllLines),DOTaskHandle);
1677+ //timing frequency 10000Hz, 1000 sample per channel
1678+ ErrorCheck(DAQmxBaseCfgSampClkTiming(DOTaskHandle,'/Dev1/Ctr0InternalOutput',10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),DOTaskHandle);
1679+ //use DAQmxBaseWriteDigitalU8 for 8 bit port
1680+ //use DAQmxBaseWriteDigitalU32 for 32 bit port
1681+ //set third parametr to 1 to enable autostart or set to 0 and use DAQmxBaseStartTask before
1682+ ErrorCheck(DAQmxBaseWriteDigitalU8(DOTaskHandle,1000,1,1000,DAQmx_Val_GroupByChannel,data,written,NiTrue),DOTaskHandle);
1683+ writeln(written,' samples were written');
1684+ //stop and clear task
1685+ DAQmxBaseStopTask(DOTaskHandle);
1686+ DAQmxBaseClearTask(DOTaskHandle);
1687+ DAQmxBaseStopTask(CtrTaskHandle);
1688+ DAQmxBaseClearTask(CtrTaskHandle);
1689+end.
1690+```
1691+
1692+### COUNTER INPUTS/OUTPUTS
1693+
1694+Counter input of M-series cards is limited to computer speed.
1695+
1696+#### COUNTER OUTPUT
1697+
1698+Counter output can be timed by software or hardware.
1699+
1700+Example demontrate how to use couter ouput as frequency generator(clock signal for other hardware) or as basic pwm regulation.
1701+
1702+In this example counter output is hardware timed.
1703+
1704+``` pascal
1705+program ctrout;
1706+
1707+{$mode objfpc}{$H+}
1708+
1709+uses
1710+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1711+ cthreads,
1712+ {$ENDIF}{$ENDIF}
1713+ Classes,nidaqmxbase,StrUtils,SysUtils
1714+ { you can add units after this };
1715+var
1716+ CtrTaskHandle:PTaskHandle;
1717+ NiBool:Pnibool;
1718+ data:array of byte;
1719+ reads:longint=0;
1720+procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
1721+var
1722+ errBuffer:array[0..2048] of char;
1723+begin
1724+ //get error description
1725+ if DAQmxFailed(AError) = niTrue then begin
1726+ DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
1727+ writeln(ErrBuffer);
1728+ //stop and cleat task
1729+ if Assigned(ATaskHandle) then begin
1730+ DAQmxBaseStopTask(ATaskHandle);
1731+ DAQmxBaseClearTask(ATaskHandle);
1732+ end;
1733+ //stop program
1734+ Halt;
1735+ end;
1736+end;
1737+begin
1738+
1739+ {********CONFIGURE COUNTER TO USE AS CLOCK FOR DIGITAL INPUT*****************}
1740+ //create counter task
1741+ ErrorCheck(DAQmxBaseCreateTask('', CtrTaskHandle),CtrTaskHandle);
1742+ //create counter output channel
1743+ //Frequency 10000 Hz, duty 0.5
1744+ ErrorCheck(DAQmxBaseCreateCOPulseChanFreq(CtrTaskHandle,'Dev1/ctr0','',DAQmx_Val_Hz,DAQmx_Val_Low,0,10000,0.5),CtrTaskHandle);
1745+ //timing
1746+ //last value is not important for continuesly sample mode, for finite sample mode = generate 10000 samples
1747+ ErrorCheck(DAQmxBaseCfgImplicitTiming(CtrTaskHandle,DAQmx_Val_ContSamps,10000),CtrTaskHandle);
1748+ //start counter task
1749+ ErrorCheck(DAQmxBaseStartTask(CtrTaskHandle),CtrTaskHandle);
1750+ //generate frequency signal for 10 seconds
1751+ sleep(10000);
1752+ DAQmxBaseStopTask(CtrTaskHandle);
1753+ DAQmxBaseClearTask(CtrTaskHandle);
1754+end.
1755+```
1756+
1757+#### COUNTER INPUT
1758+
1759+Counter input is only software operated. It is limited by hardware driver.
1760+
1761+``` pascal
1762+program ctrin;
1763+
1764+{$mode objfpc}{$H+}
1765+
1766+uses
1767+ {$IFDEF UNIX}{$IFDEF UseCThreads}
1768+ cthreads,
1769+ {$ENDIF}{$ENDIF}
1770+ Classes,nidaqmxbase,StrUtils,SysUtils,Crt
1771+ { you can add units after this };
1772+var
1773+ CtrInTaskHandle:PTaskHandle;
1774+ NiBool:Pnibool;
1775+ data:dword=0;
1776+ reads:longint=0;
1777+procedure ErrorCheck(AError:longint;ATaskHandle:PTaskHandle);
1778+var
1779+ errBuffer:array[0..2048] of char;
1780+begin
1781+ //get error description
1782+ if DAQmxFailed(AError) = niTrue then begin
1783+ DAQmxBaseGetExtendedErrorInfo(ErrBuffer,2048);
1784+ writeln(ErrBuffer);
1785+ //stop and cleat task
1786+ if Assigned(ATaskHandle) then begin
1787+ DAQmxBaseStopTask(ATaskHandle);
1788+ DAQmxBaseClearTask(ATaskHandle);
1789+ end;
1790+ //stop program
1791+ Halt;
1792+ end;
1793+end;
1794+begin
1795+ {*****************CREATE COUNTER INPUT***************************************}
1796+ //create couter input task
1797+ ErrorCheck(DAQmxBaseCreateTask('Counter input task',CtrInTaskHandle),CtrInTaskHandle);
1798+ //create input counter for pulse counting
1799+ ErrorCheck(DAQmxBaseCreateCICountEdgesChan(CtrInTaskHandle,'Dev1/ctr1','',DAQmx_Val_Rising,0,DAQmx_Val_CountUp),CtrInTaskHandle);
1800+ //timing
1801+ //ErrorCheck(DAQmxBaseCfgSampClkTiming(CtrInTaskHandle,'/Dev1/Ctr0InternalOutput',1000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000),CtrInTaskHandle);
1802+ //start counter input task
1803+ ErrorCheck(DAQmxBaseStartTask(CtrInTaskHandle),CtrInTaskHandle);
1804+ //counting pulses
1805+ writeln('press any key to stop counting');
1806+ repeat
1807+ ErrorCheck(DAQmxBaseReadCounterU32(CtrIntaskHandle,1,10.0,data,1,reads,NiTrue),CtrIntaskHandle);
1808+ writeln('counter value: ',data);
1809+ until keypressed;
1810+ //clear and stop task
1811+ DAQmxBaseStopTask(CtrInTaskHandle);
1812+ DAQmxBaseClearTask(CtrInTaskHandle);
1813+end.
1814+```
1815+
1816+### TESTED HARDWARE
1817+
1818+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:
1819+
1820+- **NI PCI-6250**
1821+- **NI PCI-6224**
1822+- **NI USB-6356** (Windows only)
1823+
1824+---
1825+*From the Free Pascal wiki, page "NI-DAQmx and NI-DAQmx Base examples", as it stood on 2019-12-23 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
1826+Category: FPC in Science and Technology
1827+Category: Hardware
1828+Category: Measuring and Instrumentation

Back to history