解决方案简介

LabMax-Pro SSIM 仪表与 PowerMax-Pro 在 C# 中的高速 OEM 集成指南

引言

客户正越来越多地使用LabMax-Pro SSIM仪表进行深度集成,编写定制代码以传输高速数据。此类仪表接口的实现不仅需要我们的技术指导,更要求客户具备高水平的专业能力。本文档旨在提供成功实施所需的工具。

确定集成所需的工具。

我们为 LabMax-Pro SSIM 仪表提供的高意 连接(CMC)”软件能够以 20kHz / 50us 的采样率读取并实时传输高速数据,并将其导出到文件中。  该过程较为复杂,需要用户/程序员具备丰富的经验才能成功。本文档中提供的数据曾帮助多家客户成功实现该功能。所需资源……

1. 客户方需配备一名经验丰富的程序员或软件工程师来编写接口程序。

2. LabMax-Pro SSIM 用户手册(特别是“主机接口”一章)。

3. 已安装并运行 CMC 应用程序,以便查看 I/O 日志功能。

a. 显示了适用于类似操作设置的 SCPI 命令。

b. 有些命令虽然并非必需,但会被发送多次。

4. 本技术说明。

 

流程概述——重点内容。

在对 SSIM 仪表进行编程时,整个过程中需注意以下几点。请参考以下操作步骤。

1. 数据采集可通过以下两种方式进行:

a. 计数停止——发送 N 个样本后自动停止

· 强烈建议使用“停止计数”功能

b. 持续运行——直至主机明确下达停止指令

· 由于计费器在停止前会发送额外的记录,因此情况更为复杂

2. 数据采集可通过以下两种方式进行编码:

a. 二进制

· 强烈建议使用二进制文件!

b. ASCII

3. 这两种编码方式都支持传输多种数据

a. 优先考虑速度(不要发送不需要的数据) vs. 为了以防万一而收集更多数据

b. 选项:

  • 主要(测量)
  • X、Y 偏移量(仅来自 LM 传感器)
  • 数据采集标志(始终建议使用)
  • 序列ID(仅限能量)
  • 脉冲周期(仅适用于能量)

c. 详见SCPI参考资料

d. SSIM 不会发送数据样本的时间戳信息

时间戳通常由接收端通过将变量值增加采样率来重建。

4. 握手

a. 在与 SCPI 交互时非常有用,如果该功能关闭,则无法查看响应

b. 但通常禁用流式数据传输

c. 作为执行“Start”命令前的最后一条命令发出

数据采集概述。

数据采集(DAQ)可以使用ASCII或二进制格式进行——按样本迭代:

  • 对于二进制数据:只需读取相应数量的字节,并根据您指定的编码标志将其打包到目标结构体中。无需进行数值转换。
  • 二进制流USB数据是以块为单位传输的,通常单次读取无法获取所需的所有字节。您需要反复读取字节,直到收集到所需数量为止。
  • 建议使用二进制,因为它速度更快、占用空间更小,且无需进行耗时的文本转数字转换
  • 对于 ASCII:读取一行文本,并根据您指定的编码标志进行解析

我们的 CMC 软件在单独的线程中进行数据采集,因此当该线程等待读取数据时,用户界面不会被阻塞。线程机制是一个高级话题,超出了本文的讨论范围。

发送 SCPI 配置命令,以针对您的具体测量需求进行设置

1. 首先,你至少需要(顺序不限)

  • 发送CONF:MEAS:MODE W以选择功率测量,或发送J以选择能量测量
  • 发送CONF:READ:MODE BINARY以指定二进制模式(推荐)
  • 发送CONF:ITEM PRI,FLAG以指定仅需测量数据和标志数据。二进制数据将包含一个
  1. 4字节浮点数(IEEE浮点数)测量值,后跟
  2. 2字节无符号整数标志字
  • 还有许多其他命令可能适用于您的具体情况

2. 最后,请按以下顺序操作:

i. 发送SYST:COMM:HAND OFF命令以关闭握手协议

ii. 清空输入缓冲区——你需要丢弃在发送上述命令期间积累的任何握手信息、错误消息或其他多余的输入数据,以便首次读取时能从第一个数据记录的开头开始。具体操作方式很大程度上取决于你的编译器、运行时系统和操作系统。

iii. 发送START 100

  • 指示仪表开始采集数据,并在采集到100条记录后停止
  • 请指定记录数,以便计数器发送固定数量的记录。建议最初仅使用少量记录进行测试和调试。
然后开始读取数据

1. 每次处理一条记录

2. 直到计数用尽

注意事项

每个数据记录通常包含一个标志字。每次采样时,应检查其中若干个测量标志:

1. OverTemp = 0x80 – 表示传感器过热,应终止数据采集,且无论如何都应报告该错误

2. 终止 = 0x8000 – 表示仪表检测到致命错误(例如传感器断开),必须单方面终止采集;此后将不再有数据传出

3. MissingSamples = 0x100 – 主机未能及时从仪表读取数据,导致仪表的内部缓冲区溢出,数据流中部分数据记录因此被省略。数据采集可继续进行,但该标志表示数据存在不连续性 

C# 接口代码示例。

客户最常提出的问题是:“如何捕获这路高速数据流,并根据自身需求对其进行处理?”下一节将介绍用于传输高速数据所需的数据采集循环。

ThreadBody– 数据采集的内部循环

ThreadBody 的核心是一个 while 循环,该循环会反复调用 ReadOneRecord 来获取每个数据样本。任何错误(异常)都会导致函数退出。它还实现了可选的StopOnCount功能。

在循环的第一次迭代中,ReadOneRecord 调用是发送 start 命令后读取的第一条数据。循环将持续进行,直到所有数据均已加载并 并添加到 CaptureBuffer

`data` 是一个全局静态临时数组,其容量足以处理任何记录。

IsStopping是一个全局标志,用于指示所有采集代码提前终止。

TerminatedByMeter 测试 ( record.Flags & MeasurementFlags.Terminated ) != 0 时,
其中 Terminated = 0x8000 // 计量表声明单方面终止

蓝色标出的部分可以忽略。

 

      protected override void ThreadBody()
      {
       try
        {
              BoostThreadPriority();
              // energy mode has to actually wait a while before IsWaiting comes true
              OnDAQ_StateChanged( DAQ_State.Start );
              // fill Data array with the required number of bytes
              while( !正在停止 && ReadOneRecord( 数据)) 
              // fill Data array with the required number of bytes
              while( !IsStopping && ReadOneRecord( Data ) )
              {
                          // if we get data while waiting, then we're no longer waiting
                          if( IsWaiting )
                          {
                                        IsWaiting = false;
                                       OnDAQ_StateChanged( DAQ_State.Triggered );
                           }

                          // copy the binary 数据 转换为数据记录
#if PREALLOCATE_DATA_RECORDS
                          Record.Read( 数据 );
#else
                          Record = new DataRecordSingle( 数据 );
#endif
#if TRACE_DAQ_HS_Read && DEBUG
                          TraceLogger.TraceRead( $"DAQ.HS.Read: {Record.ToString_AsHex()} // {Record.ToStringEx()}" );
#endif
                           // if meter sets abort flag, then we have to stop 
                           // (and this record should NOT get added to Capture buffer)
                           if( TerminatedByMeter( Record ) )
               break;

                           // Add the data Record to the CaptureBuffer, where a timestamp is assigned
                            CaptureBuffer.TimestampAndAdd( Record );
                            TraceData( "Add[ {0} ]: {1}", RecordsRead, Record.ToString() );

                            计数++;
                            if( StopOnCount && Count >= Capacity )
                                         换行;
                        }
     
      }
      catch( Exception ex )
      {
                       // all uncaught exceptions are reported and terminate the thread
                       ReportException( ex );
       }
       // all exits from try statement need to exit successfully
       OnThreadExits();
}

 

ReadOneRecord——数据采集的内循环

ReadOneRecord会反复调用 Read 函数,将所需数量的字节加载到目标数据数组中。

程序的核心是前两个 while 循环。其余大部分代码涉及一些异常情况,这些情况在您的系统上可能不会发生。

如果 ReadOneRecord 因任何原因无法获取所有数据,它将返回 false,从而终止 ThreadBody 循环。还有许多其他异常情况也可能导致循环终止。

复杂性源于COM端口的读取函数并不一定返回所有请求的数据。如果返回的数据少于所需量,内层循环会反复获取数据中越来越小的剩余部分。

Channel.Read实质上是.Net SerialPort读取函数。

唯一的区别在于,整个目标数组会被作为参数传入,索引指定了新数据应放置的位置,而计数参数则表示请求的字节数。Read 函数返回实际读取的字节数,该数值可能少于请求的字节数。

正在停止 这是一个全局标志,用于指示所有采集代码提前终止。



protected virtual bool ReadOneRecord( byte[] data )
{
     int count = data.Length;
	 int index = 0;
	 SampleTime.Start();

	// outer loop repeatedly attempts reading 1 record,
	// restarting an incomplete inner loop after a timeout
	while( count > 0 && !正在停止 )
    {
        try
        {
            // 内层循环读取一条记录,但
            // 可能在读取完成前就超时了
            while( count > 0 && !正在停止 )
			{
				int actual = Channel.Read( data, index, count );
				if( actual <= 0 )
				{
					// eof "cannot happen" thus fatal error
					ReportUnexpectedEOF();
					return false;
				}

				count -= actual;
				index += actual;
			}

			// if we get here, we have a complete record

			 // stats only for complete records
			BytesRead += data.Length;
			RecordsRead++;
		}

		// in Energy mode, we sometimes wait a long time for an energy reading, 
		// so timeout while reading is normal 

		catch( TimeoutException )
		{
			// Stop while Waiting terminates the operation

			if( IsStopping )
				return false;	// terminate DAQ

			// else if timeout when we're not stopping...

			// timeouts are not allowed in power mode
			if( !OperatingMode_IsTrueEnergy
			&& SampleTime.ElapsedMilliseconds > PowerModeMaxElapsed_ms )
			{
				ReportUnexpectedTimeout();
				return false;   // terminate DAQ
			}

			// signal TriggerWait first time we start waiting again
			if( !IsWaiting )
			{
				IsWaiting = true;
				OnDAQ_StateChanged( DAQ_State.TriggerWait );
			}

			// ignore timeouts if not stopping or PowerMode timeout
			continue;
		}
		finally
		{
			SampleTime.Stop();
		}
	} // outer while loop

	return ( count == 0 );  // 计数不为零表示失败
}

 

联系高意

如需帮助或了解更多信息,请访问我们的支持 页面。例如,如果您找不到传感器的校准证书,我们可以为您寄送一份替换件。

如需安排保修服务或年度重新校准,请先联系 所在高意 ,以获取退货授权(RMA)编号。请使用您保留的运输箱和包装材料,将传感器安全地寄回工厂,寄送地址如下:

高意
收件人:RMA #
27650 SW 95th Ave.
俄勒冈州威尔逊维尔市 97070

预约免费咨询,讨论您的需求。