This commit is contained in:
@@ -13,9 +13,9 @@ namespace ASTM_D7896_Tester.Services
|
||||
public FiveHalfDmmService(string portName, int baudRate = 115200)
|
||||
{
|
||||
_serialPort = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
|
||||
_serialPort.ReadTimeout = 2000;
|
||||
_serialPort.ReadTimeout = 5000; // 增加超时,批量数据可能需要更长时间
|
||||
_serialPort.WriteTimeout = 1000;
|
||||
_serialPort.NewLine = "\n";
|
||||
_serialPort.NewLine = "\n"; // 结束符为 LF
|
||||
}
|
||||
|
||||
public void Open()
|
||||
@@ -32,9 +32,7 @@ namespace ASTM_D7896_Tester.Services
|
||||
|
||||
public bool IsOpen => _serialPort?.IsOpen == true;
|
||||
|
||||
/// <summary>
|
||||
/// 发送命令并等待响应(同步读写,但因在Task.Run中执行,不阻塞UI)
|
||||
/// </summary>
|
||||
// ========== 核心通信方法 ==========
|
||||
private async Task<string> QueryAsync(string command)
|
||||
{
|
||||
if (!_serialPort.IsOpen) throw new InvalidOperationException("串口未打开");
|
||||
@@ -42,13 +40,12 @@ namespace ASTM_D7896_Tester.Services
|
||||
{
|
||||
lock (_serialPort)
|
||||
{
|
||||
// 清空缓冲区
|
||||
_serialPort.DiscardInBuffer();
|
||||
_serialPort.DiscardOutBuffer();
|
||||
|
||||
_serialPort.WriteLine(command);
|
||||
System.Diagnostics.Debug.WriteLine($"[发送] {command}");
|
||||
|
||||
// 读取直到遇到换行符(批量数据可能很长,但 ReadLine 会一直读到 \n)
|
||||
string response = _serialPort.ReadLine();
|
||||
System.Diagnostics.Debug.WriteLine($"[接收] {response}");
|
||||
return response.Trim();
|
||||
@@ -56,16 +53,6 @@ namespace ASTM_D7896_Tester.Services
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public string TestCommunication()
|
||||
{
|
||||
if (!_serialPort.IsOpen) throw new InvalidOperationException("串口未打开");
|
||||
_serialPort.DiscardInBuffer();
|
||||
_serialPort.WriteLine("*IDN?");
|
||||
return _serialPort.ReadLine().Trim();
|
||||
}
|
||||
|
||||
|
||||
private async Task SendCommandAsync(string command)
|
||||
{
|
||||
if (!_serialPort.IsOpen) throw new InvalidOperationException("串口未打开");
|
||||
@@ -78,71 +65,97 @@ namespace ASTM_D7896_Tester.Services
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置为高速直流电压测量(根据8255文档)
|
||||
/// </summary>
|
||||
// ========== 配置高速直流电压测量(基于8255文档) ==========
|
||||
public async Task ConfigureHighSpeedDcvAsync()
|
||||
{
|
||||
// 配置直流电压,自动量程
|
||||
await SendCommandAsync("CONFigure:VOLTage:DC AUTO");
|
||||
// 设置精度为FAST(高速模式)
|
||||
await SendCommandAsync("SENSe:VOLTage:DC:RESolution FAST");
|
||||
// 使用软件触发
|
||||
await SendCommandAsync("TRIGger:SOURce BUS");
|
||||
// 关闭自动延迟
|
||||
await SendCommandAsync("TRIGger:DELay:AUTO OFF");
|
||||
await SendCommandAsync("TRIGger:DELay 0");
|
||||
// 1. 复位到已知状态(可选)
|
||||
await SendCommandAsync("*RST");
|
||||
await Task.Delay(100);
|
||||
|
||||
// 2. 固定量程(推荐手动设定,例如 1V,根据实际信号调整)
|
||||
// 文档中量程可选 200mV, 2V, 20V, 200V, 1000V
|
||||
await SendCommandAsync("VOLT:DC:RANG 1");
|
||||
|
||||
// 3. 设置分辨率为 FAST(高速模式)
|
||||
await SendCommandAsync("VOLT:DC:RES FAST");
|
||||
|
||||
// 4. 触发源设为 BUS(软件触发)
|
||||
await SendCommandAsync("TRIG:SOUR BUS");
|
||||
|
||||
// 5. 关闭自动延迟,延迟设为 0
|
||||
await SendCommandAsync("TRIG:DEL:AUTO OFF");
|
||||
await SendCommandAsync("TRIG:DEL 0");
|
||||
}
|
||||
|
||||
// ========== 方案一:READ? 一次性批量采集(推荐,稳定可靠) ==========
|
||||
/// <summary>
|
||||
/// 预置采样点数并进入等待触发状态
|
||||
/// 批量读取指定数量的电压值(使用 READ? 命令)
|
||||
/// </summary>
|
||||
/// <param name="sampleCount">采样点数,如 400</param>
|
||||
/// <returns>电压值数组(单位:伏特)</returns>
|
||||
public async Task<double[]> ReadBatchAsync(int sampleCount)
|
||||
{
|
||||
// 设置采样点数
|
||||
await SendCommandAsync($"SAMP:COUN {sampleCount}");
|
||||
|
||||
// 发送 READ?,仪器将自动完成触发、采集并返回所有结果
|
||||
string response = await QueryAsync("READ?");
|
||||
|
||||
// 解析逗号分隔的数值
|
||||
return ParseResponse(response, sampleCount);
|
||||
}
|
||||
|
||||
// ========== 方案二:INIT + *TRG + FETCh? 流程(保留,以备特殊场景) ==========
|
||||
public async Task PrepareBatchAsync(int sampleCount)
|
||||
{
|
||||
await SendCommandAsync($"SAMPle:COUNt {sampleCount}");
|
||||
await SendCommandAsync("INITiate");
|
||||
await SendCommandAsync($"SAMP:COUN {sampleCount}");
|
||||
await SendCommandAsync("INIT");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送软件触发信号
|
||||
/// </summary>
|
||||
public async Task TriggerAsync()
|
||||
{
|
||||
await SendCommandAsync("*TRG");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取批量采集结果
|
||||
/// </summary>
|
||||
public async Task<double[]> FetchBatchAsync()
|
||||
{
|
||||
string response = await QueryAsync("FETCh?");
|
||||
if (string.IsNullOrWhiteSpace(response))
|
||||
throw new Exception("FETCh? 返回空响应");
|
||||
return ParseResponse(response, null); // 不检查数量,直接解析
|
||||
}
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
private double[] ParseResponse(string response, int? expectedCount = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(response))
|
||||
throw new Exception("返回数据为空");
|
||||
|
||||
// 文档示例返回值如 "+1.234500E-02,+2.345600E-02"
|
||||
string[] parts = response.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
double[] values = new double[parts.Length];
|
||||
for (int i = 0; i < parts.Length; i++)
|
||||
{
|
||||
string valStr = parts[i].Trim();
|
||||
if (!double.TryParse(valStr, System.Globalization.NumberStyles.Float,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out values[i]))
|
||||
if (!double.TryParse(parts[i].Trim(),
|
||||
System.Globalization.NumberStyles.Float,
|
||||
System.Globalization.CultureInfo.InvariantCulture,
|
||||
out values[i]))
|
||||
{
|
||||
throw new Exception($"解析失败: {valStr},原始响应: {response}");
|
||||
throw new Exception($"解析失败: {parts[i]},原始响应: {response}");
|
||||
}
|
||||
}
|
||||
|
||||
if (expectedCount.HasValue && values.Length != expectedCount.Value)
|
||||
System.Diagnostics.Debug.WriteLine($"警告:实际点数 {values.Length},期望 {expectedCount.Value}");
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单次读取电压
|
||||
/// </summary>
|
||||
// ========== 单次读取(保留兼容) ==========
|
||||
public async Task<double> ReadVoltageAsync()
|
||||
{
|
||||
string resp = await QueryAsync("MEASure:VOLTage:DC?");
|
||||
if (double.TryParse(resp, System.Globalization.NumberStyles.Float,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out double value))
|
||||
string resp = await QueryAsync("MEAS:VOLT:DC?");
|
||||
if (double.TryParse(resp,
|
||||
System.Globalization.NumberStyles.Float,
|
||||
System.Globalization.CultureInfo.InvariantCulture,
|
||||
out double value))
|
||||
return value;
|
||||
throw new Exception($"无效响应: {resp}");
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace ASTM_D7896_Tester.Services
|
||||
public int ConnectTimeoutMs { get; set; } = 3000;
|
||||
public int ReadWriteTimeoutMs { get; set; } = 5000;
|
||||
|
||||
// 默认电压量程(伏特),可根据实际信号修改,例如 0.1, 1, 10, 100, 1000
|
||||
public double DefaultVoltageRange { get; set; } = 1.0;
|
||||
|
||||
public async Task ConnectAsync(string ipAddress, int port = 45454)
|
||||
{
|
||||
if (_tcpClient != null && _tcpClient.Connected)
|
||||
@@ -37,6 +40,9 @@ namespace ASTM_D7896_Tester.Services
|
||||
_stream.WriteTimeout = ReadWriteTimeoutMs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送命令并等待完整响应(支持多行/大数据量)
|
||||
/// </summary>
|
||||
public async Task<string> QueryAsync(string command)
|
||||
{
|
||||
EnsureConnected();
|
||||
@@ -44,19 +50,30 @@ namespace ASTM_D7896_Tester.Services
|
||||
await _stream.WriteAsync(cmdBytes, 0, cmdBytes.Length);
|
||||
|
||||
var responseBuilder = new StringBuilder();
|
||||
byte[] buffer = new byte[4096];
|
||||
byte[] buffer = new byte[65536];
|
||||
int bytesRead;
|
||||
while (true)
|
||||
bool endReached = false;
|
||||
|
||||
while (!endReached)
|
||||
{
|
||||
bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length);
|
||||
if (bytesRead == 0) break;
|
||||
string chunk = Encoding.ASCII.GetString(buffer, 0, bytesRead);
|
||||
responseBuilder.Append(chunk);
|
||||
if (chunk.Contains("\n")) break;
|
||||
// 如果收到换行符,再等50ms确认没有更多数据(TCP分包情况)
|
||||
if (chunk.Contains("\n"))
|
||||
{
|
||||
await Task.Delay(50);
|
||||
if (!_stream.DataAvailable)
|
||||
endReached = true;
|
||||
}
|
||||
}
|
||||
return responseBuilder.ToString().Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送命令,不等待响应
|
||||
/// </summary>
|
||||
public async Task SendCommandAsync(string command)
|
||||
{
|
||||
EnsureConnected();
|
||||
@@ -65,60 +82,76 @@ namespace ASTM_D7896_Tester.Services
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置为高速直流电压测量(外部触发模式)
|
||||
/// 配置为高速直流电压测量(BUS触发模式,固定量程,0.02PLC,关闭自归零)
|
||||
/// </summary>
|
||||
public async Task ConfigureForHighSpeedDcvAsync()
|
||||
{
|
||||
await SendCommandAsync("CONF:VOLT:DC AUTO");
|
||||
// 1. 重置到默认状态(可选)
|
||||
await SendCommandAsync("*RST");
|
||||
await Task.Delay(100);
|
||||
|
||||
// 2. 固定量程(避免自动量程降低速度)
|
||||
await SendCommandAsync($"VOLT:DC:RANG {DefaultVoltageRange}");
|
||||
|
||||
// 3. 设置积分时间 0.02PLC(最快速度)
|
||||
await SendCommandAsync("VOLT:DC:NPLC 0.02");
|
||||
|
||||
// 4. 关闭自动归零(提高速度)
|
||||
await SendCommandAsync("VOLT:DC:ZERO:AUTO OFF");
|
||||
await SendCommandAsync("TRIG:SOUR EXT");
|
||||
|
||||
// 5. 触发源设为 BUS(软件触发)
|
||||
await SendCommandAsync("TRIG:SOUR BUS");
|
||||
|
||||
// 6. 关闭自动延迟,延迟设为0
|
||||
await SendCommandAsync("TRIG:DEL:AUTO OFF");
|
||||
await SendCommandAsync("TRIG:DEL 0");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预置采样点数并进入等待触发状态
|
||||
/// 预置采样点数并进入等待触发状态(发送 INIT)
|
||||
/// </summary>
|
||||
public async Task PrepareBatchAsync(int sampleCount)
|
||||
{
|
||||
await SendCommandAsync($"SAMP:COUN {sampleCount}");
|
||||
await SendCommandAsync("INIT"); // 等待外部触发
|
||||
await SendCommandAsync("INIT"); // 进入等待触发状态
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送触发信号(软件触发,用于测试,但外部触发模式不使用)
|
||||
/// 此方法仅用于 BUS 触发模式,当前配置为 EXT 触发,实际触发由硬件信号完成。
|
||||
/// 保留此方法以备将来切换触发模式。
|
||||
/// 发送软件触发信号(*TRG),开始采集
|
||||
/// </summary>
|
||||
public async Task TriggerAsync()
|
||||
{
|
||||
// 当前为外部触发模式,不需要软件触发;若需软件触发,请先执行 TRIG:SOUR BUS
|
||||
// 保留空实现或抛出 NotSupportedException,根据需求选择
|
||||
// 为避免编译错误,提供一个空实现
|
||||
await Task.CompletedTask;
|
||||
await SendCommandAsync("*TRG");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量采集(假设已经配置并等待外部触发完成)
|
||||
/// </summary>
|
||||
public async Task<double[]> AcquireBatchAsync(int sampleCount)
|
||||
{
|
||||
await SendCommandAsync($"SAMP:COUN {sampleCount}");
|
||||
await SendCommandAsync("INIT");
|
||||
int waitMs = (int)(sampleCount / 1000.0 * 1000) + 200;
|
||||
await Task.Delay(waitMs);
|
||||
string response = await QueryAsync("FETCh?");
|
||||
return ParseResponse(response, sampleCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取批量采集结果(在 PrepareBatchAsync 和外部触发之后调用)
|
||||
/// 获取批量采集结果(FETCh?)
|
||||
/// </summary>
|
||||
public async Task<double[]> FetchBatchAsync()
|
||||
{
|
||||
string response = await QueryAsync("FETCh?");
|
||||
// 注意:此时不知道预期点数,但可以从返回数组长度得知
|
||||
return ParseResponse(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一次性批量采集(简化接口,内部自动完成 SAMP:COUN + READ?)
|
||||
/// 注意:此方法会阻塞直到采集完成,适合不需要分离触发时序的场景
|
||||
/// </summary>
|
||||
public async Task<double[]> ReadBatchAsync(int sampleCount)
|
||||
{
|
||||
await SendCommandAsync($"SAMP:COUN {sampleCount}");
|
||||
string response = await QueryAsync("READ?");
|
||||
return ParseResponse(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析逗号分隔的电压值数组
|
||||
/// </summary>
|
||||
private double[] ParseResponse(string response)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(response))
|
||||
throw new Exception("返回数据为空");
|
||||
|
||||
string[] parts = response.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
double[] values = new double[parts.Length];
|
||||
for (int i = 0; i < parts.Length; i++)
|
||||
@@ -130,21 +163,9 @@ namespace ASTM_D7896_Tester.Services
|
||||
return values;
|
||||
}
|
||||
|
||||
private double[] ParseResponse(string response, int expectedCount)
|
||||
{
|
||||
string[] parts = response.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
double[] values = new double[parts.Length];
|
||||
for (int i = 0; i < parts.Length; i++)
|
||||
{
|
||||
if (!double.TryParse(parts[i], System.Globalization.NumberStyles.Float,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out values[i]))
|
||||
throw new Exception($"解析失败: {parts[i]}");
|
||||
}
|
||||
if (values.Length != expectedCount)
|
||||
throw new Exception($"期望 {expectedCount} 个点,实际收到 {values.Length}");
|
||||
return values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单次读取电压(保留,但不推荐用于高速采集)
|
||||
/// </summary>
|
||||
public async Task<double> ReadVoltageAsync()
|
||||
{
|
||||
string resp = await QueryAsync("MEAS:VOLT:DC?");
|
||||
|
||||
Reference in New Issue
Block a user