NI-DAQmx:减少开发时间,提升系统系能
自NI-DAQmx发布以来,NI数据采集(DAQ)硬件用户一直在充分利用软件的诸多特性来节省开发时间,并提高数据采集应用程序的性能。
其中一个能节省大量开发时间的特性是NI-DAQmx应用程序编程接口(API),该接口适用于各种设备功能和设备系列。 也就意味着在一个多功能设备的所有功能都可通过同一功能集(模拟输入、模拟输出、数字I/O和计数器)进行编程。 而且,数字I/O设备和模拟输出设备也可由同一个功能集进行编程。 在LabVIEW中,多态机制使得这些都成为可能。 一个多态VI可接受多种数据类型,用于一个或多个输入和/或输出终端。 NI-DAQmx API对于所有可支持的编程环境都是一样的。 用户只需学习运用一个功能集,便可在多种编程环境下对大部分的NI数据采集硬件进行编程。
另一个能够提升开发体验的NI-DAQmx特性是DAQ助手。 这个工具可帮助用户无需编程,仅通过图形化界面配置各种简单或复杂的数据采集任务,即可创建应用。 此外,因为触发和/或时钟信号必须手动路由,因此通常很难实现同步性。而使用NI-DAQmx,这将变得轻而易举,NI-DAQmx可以在一个设备上不同的功能区域间以及在多个设备上自动进行信号路由。
使用NI-DAQmx搭建的数据采集应用将受益于NI-DAQmx这一专门针对最优化系统性能而设计的架构。 该架构以一个高效的状态模型为基础,去除了不必要的重复配置。 将这些系统占用去除后,配置和采集过程都得到了优化。 另外,由于内存映射寄存器的存在,单点I/O采样率可达到50 kS/s以上。
NI-DAQmx构架的另一个重要特性是测量多线程。 NI-DAQmx的多线程性可实现同时进行多个数据采集操作,从而大大提高了多操作应用的性能, 同时极大地简化此类应用的编程。
用户只需学习几个函数,即可开始享受这些特性所带来的好处。 事实上, NI-DAQmx的10个函数提供了解决80%的数据采集应用问题的功能。 下面将详细介绍这些函数,帮助用户理解其功能及其所适用的应用类型。
NI-DAQmx创建虚拟通道
Task.Channel.CreateChannel Property [.NET]
“NI-DAQmx创建虚拟通道”函数可创建一个虚拟通道并将其添加至任务, 也可用于创建多个虚拟通道并将其全部添加至任务。 如未指定任务,该函数将自动创建一个任务。 “NI-DAQmx创建虚拟通道”函数包含多个实例, 这些实例对应虚拟通道执行的具体测量或生成类型。
在.NET中创建通道
大部分NI-DAQmx .NET库中的类无法直接被初始化, 这些类被用作 类的子对象。
这些类包含了某个特定通道类型的专用属性。 例如:计数器
等属性只适用于计数器,且只能在CIChannel和CIChannel类中找到。 用户可在NI-DAQmx .NET类库中将下列通道类型与某个 关联起来:
模拟输入通道— 类
模拟输出通道— 类
数字输入通道— 类
数字输出通道— 类
计数器输入通道— 类
计数器输出通道— 类
任务类包含一个适用于六种通道类型的通道集合属性, 用户可使用通道集合中任意一种创建通道的方法创建通道。
建立了一个新的“任务”对象后,通过调用“通道”类中相应的成员函数即可创建和分配AIChannel对象。 以下程序片段用于创建一个简单的模拟输入电压通道:
analogInTask = new Task();
AIChannel myChannel;
myChannel = analogInTask.AIChannels.CreateVoltageChannel(
"dev1/ai1", //The physical name of the channel
"myChannel", //The name to associate with this channel
AITerminalConfiguration.Differential, //Differential wiring
-10, //-10v minimum
10, //10v maximum
AIVoltageUnits.Volts //Use volts
);
练习范例:
.NET | WriteDigPort |
ContAcqThermocoupleSamples_IntClk |
NI-DAQmx触发
Task.Triggers Property [.NET]
“NI-DAQmx触发”函数可用于对触发进行配置来执行指定操作。 常用的操作是开始触发和参考触发。 开始触发用于启动采集或生成, 参考触发则用于在一组采集样本中创建预触发数据结束后和后触发数据开始前的位置。 可对这两个触发进行配置,使其发生在数字边沿、模拟边沿、或模拟信号进入或离开窗口时。
在.NET中创建触发
创建“任务”对象和“通道”后,用户可以调用“任务.触发”集合中的方法将触发添加至任务中。 以下程序代码显示了创建“数字边沿开始触发”:
analogInTask = new Task();
DigitalEdgeStartTriggerEdge triggerEdge = DigitalEdgeStartTriggerEdge.Rising;
analogInTask.AIChannels.CreateVoltageChannel( ... );
analogInTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("PFI0", triggerEdge);
基于发送至ConfigureDigitalEdgeTrigger函数的参数,设备会根据内部或外部的触发线判断是否存在上升或下降数字边沿,然后再开始采集数据。 上面的程序代码用于将设备配置为根据PFI 0判断上升数字边沿触发。
NI-DAQmx的定时和同步特性文档中介绍了更多关于借助NI-DAQmx使用“NI-DAQmx触发”函数来实现同步的信息。
练习范例:
.NET | AcqVoltageSamples_IntClkDigStartAndRef |
ContAcqVoltageSamples_IntClkAnalogStart |
NI-DAQmx定时
Task.Timing Property [.NET]
“NI-DAQmx定时”函数用于对硬件定时的数据采集操作进行定时配置, 包括指定操作是连续执行还是有限执行、选择采集或生成的样本数量以进行有限操作、以及需要时创建缓冲区。
对于需要采样定时(模拟输入、模拟输出和计数器)的操作,“NI-DAQmx定时”函数的采样时钟实例可用于设置采样时钟源和采样速率,采样时钟源可以是内部也可以是外部的信号源。 采样时钟能够控制采集或生成样本的速率。 每个时钟脉冲将启动任务中每个虚拟通道的样本采集或生成。
在.NET中配置任务定时
Channel.Timing.ConfigureSampleClock()函数用于配置采样时钟源、采样时钟速率,以及待采集或生成的采样数。 以下程序代码显示了根据连接至设备PFI 0的外部采样时钟创建一个连续采样。
analogInTask = new Task();
analogInTask.AIChannels.CreateVoltageChannel( ... );
analogInTask.Timing.ConfigureSampleClock(
"/Dev1/PFI0", // external clock source line or use "" for internal clock
10000, // expected rate of external clock or actual rate of internal clock
SampleClockActiveEdge.Rising, // acquire on rising or falling edge of ticks
SampleQuantityMode.ContinuousSamples, // continuous or finite samples
1000 // number of finite samples to acquire or used for buffer size if continuous
);
某些数据采集设备针对数字I/O操作采用的是握手定时模式。 握手协议通过与外部设备进行定时信号的请求和确认交互来传输样本。 “NI-DAQmx定时”函数的握手实例可用于为数字I/O操作配置握手定时模式。
练习范例:
.NET | ContGenVoltageWfm_ExtClk |
MeasBuffered_SemiPeriodFinite |
NI-DAQmx开始任务
Task.Start Method [.NET]
在引言中我们提过,NI-DAQmx使用的状态模型已去除了不必要的重复配置,可实现更高的效率和最佳的性能。 该状态模型包含一个任务的五个状态。 关于每一个状态的详细信息可在NI-DAQmx帮助下的NI-DAQmx重要概念»NI-DAQmx通道和任务»NI-DAQmx任务»任务状态模型中找到。
“NI-DAQmx开始任务”函数可以将一个任务显式转换成运行状态。 运行状态下,任务进行指定的采集和生成。 当“NI-DAQmx读取”函数运行而“NI-DAQmx开始任务”函数未运行时,任务将隐式转换成运行状态并自动启动。 这种隐式转换也会发生在“NI-DAQmx写入”函数在指定的自动开始输入驱动下运行但“NI-DAQmx开始任务”函数未运行时。
虽然不一定需要,但包含硬件定时的采集或生成的任务最好使用“NI-DAQmx开始任务”函数来显式启动。 而且,如果需要多次执行“NI-DAQmx读取”函数或“NI-DAQmx写入”函数(比如在一个循环中),则应使用“NI-DAQmx开始任务”函数。 否则任务会由于不断重复开始和停止而影响执行性能。 关于使用何时“NI-DAQmx开始任务”函数的详细信息,请查看何时使用“DAQmx开始任务”和“DAQmx停止任务”VI。
在.NET中开始任务
Start()函数用于在“任务”对象中开始任务。 下面的代码是Start()函数的一个使用范例。
analogInTask = new Task();
analogInTask.AIChannels.CreateVoltageChannel( ... );
analogInTask.Timing.ConfigureSampleClock( ... );
analogInTask.Start();
练习范例:
.NET | GenDigPulseTrain_Continuous |
ContAcq0_20mACurrentSamples_IntClk |
NI-DAQmx读取
ChannelReader Class [.NET]
“NI-DAQmx读取”函数可从指定的采集任务中读取样本。 针对不同的函数实例可选择不同的采集类型(模拟、数字、或计数器)、虚拟通道数量、采样数量和数据类型。 指定的采样数量从DAQ板卡上的FIFO传输到RAM中的PC缓存后,“NI-DAQmx读取”函数再将样本从PC缓存转移到应用程序开发环境(ADE)内存中。
在.NET中读取数据
读取NI-DAQmx .NET库需要使用读取器和流对象。 该编程模式与.NET Framework读取文件和网络I/O的方式相似。
类包含与I/O相关的属性(如 )和获取原始I/O的方法。 属性用于获取某个指定 相对应的DaqStream类实例。 用户无法直接获得DaqStream类的例程。
为了在NI-DAQmx库中进行读取,需要创建一个读取器实例,并在构造器中传递DaqStream类的实例。 然后调用读取器类上的方法来读取数据,代码如下所示:
analogInTask = new Task();
analogInTask.AIChannels.CreateVoltageChannel( ... );
//Create the reader and attach it to the stream
AnalogSingleChannelReader reader = new AnalogSingleChannelReader(analogInTask.Stream);
//Perform the read
double[] data = reader.ReadMultiSample(100);
练习范例:
.NET | AcqOneVoltageSample |
ReadDigChan |
NI-DAQmx写入
ChannelWriter Class [.NET]
“NI-DAQmx写入”函数用于将样本写入指定的生成任务中。 针对不同的函数例程可选择不同的生成类型(模拟或数字)、虚拟通道数量、采样数量和数据类型。 “NI-DAQmx写入”函数将样本从应用程序开发环境(ADE)写入到PC缓存中。 然后这些样本从PC缓存传输到DAQ板卡FIFO以进行生成。
每个“NI-DAQmx写入”函数的实例包含一个自动开始输入,用于在任务没有显式启动时判定该函数是否隐式启动任务。 本文“NI-DAQmx开始任务”一节已介绍过,显式启动硬件定时的生成任务时应使用“NI-DAQmx开始任务”函数。 如果需要多次执行“NI-DAQmx写入”函数,则还应使用该函数来使性能最优化。
在.NET中写入数据
写入NI-DAQmx .NET库需要使用写入器和流对象。 该过程与上述数据读取过程相似。
执行写入操作需要创建一个写入器实例,并在构造器中传递DaqStream类的实例。 然后调用写入器类上的方法来写入数据,代码如下所示:
analogOutTask = new Task();
analogOutTask.AOChannels.CreateVoltageChannel( ... );
//Create the writer and attach it to the stream
AnalogSingleChannelWriter writer = new AnalogSingleChannelWriter(analogOutTask.Stream);
//Perform the write
double[] data = writer.WriteMultiSample(100);
练习范例:
.NET | GenVoltageUpdate |
WriteDigChan |
NI-DAQmx结束前等待
Task.WaitUntilDone Method [.NET]
“NI-DAQmx结束前等待”函数用于等待数据采集完毕后结束任务。 该函数可用于确保停止任务前已完成指定的采集或生成。 一般情况下,“NI-DAQmx结束前等待”函数用于有限操作。 一旦该函数执行完毕,则表示有限采集或生成已完成,任务可在不影响操作的情况下停止。 此外,超时输入可用于指定最长等待时间。 如果采集或生成没有在该时间内完成,则函数将退出并生成一个相应错误。
在.NET中结束前等待
更多关于在.NET中使用该函数的信息,请查看随附的GenMultVoltUpdates_IntClk范例。
练习范例:
.NET | GenDigPulse |
GenMultVoltUpdates_IntClk |
NI-DAQmx清除任务
Task.Dispose Method [.NET]
“NI-DAQmx清除任务”函数用于清除指定的任务。 如果任务正在运行,则函数将先停止任务,然后释放任务所有的资源。 一旦任务被清除后,除非再次创建,否者该任务无法再使用。 因此,如果需要再次使用任务,则应使用“NI-DAQmx停止任务”函数来停止任务,而不是将其清除。
对于连续操作,应使用“NI-DAQmx清除任务”函数来停止实际的采集或生成。
在.NET中清除任务
任务完成读取或写入后,调用Task.Dispose方法即可清除任务。
练习范例:
.NET | ContGenVoltageWfm_IntClk |
CountDigEvents |
NI-DAQmx属性
Property [.NET]
通过“NI-DAQmx属性”可以访问与数据采集操作相关的的所有属性。 这些属性可通过“NI-DAQmx属性”写入来进行设置,当前的属性值也可以通过“NI-DAQmx属性”读取。
前面我们已讨论过,许多属性可使用NI-DAQmx函数进行设置。 比如,采样时钟源和采样时钟有效边沿属性可通过“NI-DAQmx定时”函数进行设置。 然而,一些较少使用的属性只能通过“NI-DAQmx属性”来进行设置。
在.NET中使用属性
我们在“定时”部分已介绍过,许多属性是通过“任务”对象内部的子类和集合进行设置。 以下代码片段是NI-DAQmx属性使用的一个常见范例:
//Create a new NI-DAQmx Task
Task t = new Task();
//Access the subobject properties of the Task class
t.Timing.SamplesPerChannel = 1000;
练习范例:
.NET | AcqStrainSamples |
ContAcqAccelSamp_IntClk_AnalogStart |
结语
NI-DAQmx可通过多种方式来帮助用户节省开发时间并提高数据采集应用的性能, 其中一种方式是提供仅需使用少量函数却可实现大部分功能的API。 事实上,用户只需学习本文介绍的10个函数,便可解决80%的数据采集应用问题。