434 lines
16 KiB
C#
434 lines
16 KiB
C#
using DeviceCommand.Base;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace DeviceCommand.Device
|
||
{
|
||
//是德
|
||
public class E36233A:Tcp
|
||
{
|
||
public E36233A(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
|
||
{
|
||
ConfigureDevice(ipAddress, port, sendTimeout, receiveTimeout);
|
||
}
|
||
#region SCPI 常用命令方法
|
||
|
||
/// <summary>
|
||
/// 查询仪器标识,返回制造商、型号、序列号、固件版本
|
||
/// </summary>
|
||
public Task<string> QueryIDAsync(CancellationToken ct = default)
|
||
{
|
||
return SendCommandAndReadAsync("*IDN?", ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 恢复出厂设置,不清除错误队列
|
||
/// </summary>
|
||
public Task SendResetAsync(CancellationToken ct = default)
|
||
{
|
||
return SendAsync("*RST", ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 存储当前仪器状态到指定位置(0~9)
|
||
/// </summary>
|
||
public Task SaveStateAsync(int slot, CancellationToken ct = default)
|
||
{
|
||
if (slot < 0 || slot > 9) throw new ArgumentOutOfRangeException(nameof(slot));
|
||
return SendAsync($"*SAV {slot}", ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 调用指定位置的仪器状态(0~9)
|
||
/// </summary>
|
||
public Task RecallStateAsync(int slot, CancellationToken ct = default)
|
||
{
|
||
if (slot < 0 || slot > 9) throw new ArgumentOutOfRangeException(nameof(slot));
|
||
return SendAsync($"*RCL {slot}", ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 操作完成标记,发送命令等待操作完成
|
||
/// </summary>
|
||
public Task SendOPCAsync(CancellationToken ct = default)
|
||
{
|
||
return SendAsync("*OPC", ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询操作完成标记,返回 "1" 表示完成
|
||
/// </summary>
|
||
public async Task<bool> QueryOPCAsync(CancellationToken ct = default)
|
||
{
|
||
var result = await SendCommandAndReadAsync("*OPC?", ct);
|
||
return result == "1";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清除状态寄存器与错误队列
|
||
/// </summary>
|
||
public Task ClearStatusAsync(CancellationToken ct = default)
|
||
{
|
||
return SendAsync("*CLS", ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询状态字节(STB),返回状态值
|
||
/// </summary>
|
||
public async Task<int> QueryStatusByteAsync(CancellationToken ct = default)
|
||
{
|
||
var result = await SendCommandAndReadAsync("*STB?", ct);
|
||
return int.TryParse(result, out var value) ? value : 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通用方法:发送命令并读取响应
|
||
/// </summary>
|
||
private async Task<string> SendCommandAndReadAsync(string command, CancellationToken ct = default)
|
||
{
|
||
await SendAsync($"{command}\r\n", ct);
|
||
return await ReadAsync("\n", ct);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 通道与输出控制命令
|
||
|
||
/// <summary>
|
||
/// 选择操作通道
|
||
/// </summary>
|
||
/// <param name="channel">通道号 1 或 2</param>
|
||
public Task SelectChannelAsync(int channel, CancellationToken ct = default)
|
||
{
|
||
if (channel < 1 || channel > 2) throw new ArgumentOutOfRangeException(nameof(channel));
|
||
return SendAsync($"INST:SEL CH{channel}\r\n", ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开启/关闭输出
|
||
/// </summary>
|
||
/// <param name="state">true 表示开,false 表示关</param>
|
||
/// <param name="channels">通道列表,如 "1", "1:2"</param>
|
||
public Task SetOutputStateAsync(bool state, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(channels)) throw new ArgumentNullException(nameof(channels));
|
||
string cmd = $"OUTP {(state ? "ON" : "OFF")}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 输出上升延迟设置
|
||
/// </summary>
|
||
/// <param name="delay">延迟时间 0~3600 秒</param>
|
||
/// <param name="channels">通道列表,如 "1", "1:2"</param>
|
||
public Task SetOutputRiseDelayAsync(double delay, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
if (delay < 0 || delay > 3600) throw new ArgumentOutOfRangeException(nameof(delay));
|
||
string cmd = $"OUTP:DEL:RISE {delay}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 输出下降延迟设置
|
||
/// </summary>
|
||
/// <param name="delay">延迟时间 0~3600 秒</param>
|
||
/// <param name="channels">通道列表,如 "1", "1:2"</param>
|
||
public Task SetOutputFallDelayAsync(double delay, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
if (delay < 0 || delay > 3600) throw new ArgumentOutOfRangeException(nameof(delay));
|
||
string cmd = $"OUTP:DEL:FALL {delay}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置串/并联模式
|
||
/// </summary>
|
||
/// <param name="mode">OFF(独立)、SER(串联)、PAR(并联)</param>
|
||
public Task SetOutputPairModeAsync(string mode, CancellationToken ct = default)
|
||
{
|
||
if (mode != "OFF" && mode != "SER" && mode != "PAR")
|
||
throw new ArgumentException("模式必须为 OFF, SER, PAR", nameof(mode));
|
||
return SendAsync($"OUTP:PAIR {mode}\r\n", ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通道耦合控制
|
||
/// </summary>
|
||
/// <param name="channelList">ALL(全耦合)、NONE(无耦合)、或指定通道,如 @1:2</param>
|
||
public Task SetChannelCoupleAsync(string channelList, CancellationToken ct = default)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(channelList)) throw new ArgumentNullException(nameof(channelList));
|
||
return SendAsync($"OUTP:COUP:CHAN {channelList}\r\n", ct);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 电压 / 电流参数设置命令
|
||
|
||
/// <summary>
|
||
/// 设置立即电压(单通道或多通道)
|
||
/// </summary>
|
||
public Task SetVoltageAsync(double voltage, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
if (voltage < 0 || voltage > 30.9) throw new ArgumentOutOfRangeException(nameof(voltage));
|
||
string cmd = $"SOUR:VOLT {voltage}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置立即电流(单通道或多通道)
|
||
/// </summary>
|
||
public Task SetCurrentAsync(double current, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
if (current < 0 || current > 20.6) throw new ArgumentOutOfRangeException(nameof(current));
|
||
string cmd = $"SOUR:CURR {current}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置触发电压(步进/序列模式使用)
|
||
/// </summary>
|
||
public Task SetTriggeredVoltageAsync(double voltage, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:VOLT:TRIG {voltage}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置触发电流(步进/序列模式使用)
|
||
/// </summary>
|
||
public Task SetTriggeredCurrentAsync(double current, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:CURR:TRIG {current}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置电压模式(FIX/STEP/LIST)
|
||
/// </summary>
|
||
public Task SetVoltageModeAsync(string mode, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
if (mode != "FIX" && mode != "STEP" && mode != "LIST") throw new ArgumentException("模式必须为 FIX, STEP, LIST", nameof(mode));
|
||
string cmd = $"SOUR:VOLT:MODE {mode}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置电流模式(FIX/STEP/LIST)
|
||
/// </summary>
|
||
public Task SetCurrentModeAsync(string mode, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
if (mode != "FIX" && mode != "STEP" && mode != "LIST") throw new ArgumentException("模式必须为 FIX, STEP, LIST", nameof(mode));
|
||
string cmd = $"SOUR:CURR:MODE {mode}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置过压保护 OVP(110% 最大电压内)
|
||
/// </summary>
|
||
public Task SetOVPAsync(double voltage, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:VOLT:PROT {voltage}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置过流保护 OCP(110% 最大电流内)
|
||
/// </summary>
|
||
public Task SetOCPAsync(double current, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:CURR:PROT {current}, (@{channels})\r\n";
|
||
return SendAsync(cmd, ct);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 测量与状态查询命令
|
||
|
||
/// <summary>
|
||
/// 测量指定通道的实际电压
|
||
/// </summary>
|
||
public async Task<double> MeasureVoltageAsync(string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"MEAS:VOLT? (@{channels})\r\n";
|
||
string result = await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||
return double.TryParse(result, out var voltage) ? voltage : 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测量指定通道的实际电流
|
||
/// </summary>
|
||
public async Task<double> MeasureCurrentAsync(string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"MEAS:CURR? (@{channels})\r\n";
|
||
string result = await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||
return double.TryParse(result, out var current) ? current : 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询错误队列(FIFO 返回下一个错误)
|
||
/// </summary>
|
||
public async Task<string> QueryNextErrorAsync(CancellationToken ct = default)
|
||
{
|
||
string cmd = "SYST:ERR? \r\n";
|
||
return await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询 OVP(过压保护)状态,返回 true 表示触发
|
||
/// </summary>
|
||
public async Task<bool> QueryOVPTrippedAsync(string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:VOLT:PROT:TRIP? (@{channels})\r\n";
|
||
string result = await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||
return result == "1";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询 OCP(过流保护)状态,返回 true 表示触发
|
||
/// </summary>
|
||
public async Task<bool> QueryOCPTrippedAsync(string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:CURR:PROT:TRIP? (@{channels})\r\n";
|
||
string result = await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||
return result == "1";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询远程 / 本地模式,返回 LOC / REM / RWL
|
||
/// </summary>
|
||
public async Task<string> QueryRemoteLocalStateAsync(CancellationToken ct = default)
|
||
{
|
||
string cmd = "SYST:COMM:RLST?\r\n";
|
||
return await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 电压/电流序列设置与触发
|
||
|
||
/// <summary>
|
||
/// 设置通道的电压序列
|
||
/// </summary>
|
||
/// <param name="voltages">电压序列,逗号分隔</param>
|
||
/// <param name="channels">通道列表,如 "1" 或 "1:2"</param>
|
||
public async Task SetVoltageListAsync(double[] voltages, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string values = string.Join(",", voltages);
|
||
string cmd = $"SOUR:LIST:VOLT {values}, (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置通道的电流序列
|
||
/// </summary>
|
||
public async Task SetCurrentListAsync(double[] currents, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string values = string.Join(",", currents);
|
||
string cmd = $"SOUR:LIST:CURR {values}, (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置每步的 dwell 时间序列
|
||
/// </summary>
|
||
public async Task SetDwellListAsync(double[] dwellTimes, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string values = string.Join(",", dwellTimes);
|
||
string cmd = $"SOUR:LIST:DWEL {values}, (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置序列循环次数
|
||
/// </summary>
|
||
/// <param name="count">循环次数,1~9999 或 "INF"</param>
|
||
public async Task SetSequenceCountAsync(string count, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:LIST:COUN {count}, (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启动序列触发
|
||
/// </summary>
|
||
public async Task StartSequenceAsync(string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"INIT (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置序列触发源
|
||
/// </summary>
|
||
/// <param name="source">IMMediate、BUS、PIN1、PIN2、PIN3</param>
|
||
public async Task SetTriggerSourceAsync(string source, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"TRIG:SOUR {source}, (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 特殊功能命令
|
||
|
||
/// <summary>
|
||
/// 设置远端 sensing 模式
|
||
/// </summary>
|
||
/// <param name="mode">INTernal(本地2线)、EXTernal(远端4线)</param>
|
||
/// <param name="channels">通道列表,如 "1" 或 "1:2"</param>
|
||
public async Task SetRemoteSensingAsync(string mode, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:VOLT:SENS {mode}, (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置电压上升斜率
|
||
/// </summary>
|
||
/// <param name="slewRate">单位 V/s</param>
|
||
/// <param name="channels">通道列表</param>
|
||
public async Task SetVoltageRiseSlewAsync(double slewRate, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:VOLT:SLEW:RIS {slewRate}, (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置电压下降斜率
|
||
/// </summary>
|
||
public async Task SetVoltageFallSlewAsync(double slewRate, string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:VOLT:SLEW:FALL {slewRate}, (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启动数据日志
|
||
/// </summary>
|
||
/// <param name="filename">日志文件路径,如 Internal:/log1.dlog</param>
|
||
public async Task StartDataLogAsync(string filename, CancellationToken ct = default)
|
||
{
|
||
string cmd = $"INIT:DLOG \"{filename}\"\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清除保护状态(OVP/OCP)
|
||
/// </summary>
|
||
/// <param name="channels">通道列表</param>
|
||
public async Task ClearProtectionAsync(string channels = "1", CancellationToken ct = default)
|
||
{
|
||
string cmd = $"SOUR:VOLT:PROT:CLE (@{channels})\r\n";
|
||
await SendAsync(cmd, ct);
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
}
|
||
}
|