diff --git a/DeviceCommand/Devices/ANEVH80.cs b/DeviceCommand/Devices/ANEVH80.cs index 239febb..57207ba 100644 --- a/DeviceCommand/Devices/ANEVH80.cs +++ b/DeviceCommand/Devices/ANEVH80.cs @@ -2,6 +2,7 @@ using DeviceCommand.Base; using Model.Models; using System; +using System.Collections.Generic; using System.Globalization; using System.Text.RegularExpressions; using System.Threading; @@ -10,19 +11,125 @@ using System.Threading.Tasks; namespace DeviceCommand.Devices { /// - /// ANEVH 操作模式枚举 + /// ANEVH 操作模式枚举(兼容旧接口,映射到功能模式 SOUR:MOD) /// public enum ANEVH操作模式_枚举 { - /// 定值模式 + /// 定值模式(常规界面,SOUR:MOD 0) FIXED, - /// 序列测试模式 + /// 序列测试模式(SOUR:MOD 1) LIST } + /// ANEVH 输出状态(MEASure:COND? 返回值:1=非启动 3=CV 4=CC 5=CP 6=CR) + public enum ANEVH输出状态_枚举 + { + /// 非启动状态(OFF) + 非启动 = 1, + /// 恒压 CV 状态 + CV = 3, + /// 恒流 CC 状态 + CC = 4, + /// 恒功率 CP 状态 + CP = 5, + /// 恒阻 CR 状态 + CR = 6 + } + + /// ANEVH 功能界面([SOURce:]MODe 取值) + public enum ANEVH功能模式_枚举 + { + /// 常规界面 + 常规 = 0, + /// 序列测试(Program) + 序列测试 = 1, + /// 光伏 SAS 模拟 + 光伏SAS = 2, + /// 光伏 EN50530 模拟 + 光伏EN50530 = 3, + /// 光伏 SANDIA 模拟 + 光伏SANDIA = 4, + /// 内阻模式 + 内阻模式 = 5, + /// 固定电池模拟 + 固定电池模拟 = 6, + /// 其他界面 + 其他 = 7, + /// 电池测试(充放电) + 电池测试 = 10, + /// 电子负载 + 电子负载 = 12 + } + + /// ANEVH 电子负载操作模式(SINK:MODe 取值,仅待机态可切换) + public enum ANEVH负载模式_枚举 + { + /// 定电压 CV + CV = 0, + /// 定电流 CC + CC = 1, + /// 定功率 CP + CP = 2, + /// 定电阻 CR + CR = 3, + /// CV+CC 复合模式 + CV_CC = 4, + /// CV+CR 复合模式 + CV_CR = 5, + /// CC+CR 复合模式 + CC_CR = 6, + /// CV+CC+CP+CR 复合模式(Auto) + Auto = 7 + } + + /// ANEVH 序列测试状态(PROGram:STATus? 返回值) + public enum ANEVH序列状态_枚举 + { + /// 序列测试已完成(非启动状态) + 已完成 = 0, + /// 序列测试正在运行 + 运行 = 1, + /// 序列测试暂停 + 暂停 = 2 + } + + /// ANEVH 电池模拟电池类型([BATTery:]FUNCtion:TYPE 取值) + public enum ANEVH电池类型_枚举 + { + /// 锰酸锂 + 锰酸锂 = 0, + /// 钴酸锂 + 钴酸锂 = 1, + /// 磷酸铁锂 + 磷酸铁锂 = 2, + /// 铅酸电池 + 铅酸 = 3, + /// 镍氢电池 + 镍氢 = 4, + /// 三元锂 + 三元锂 = 5, + /// 钛酸锂 + 钛酸锂 = 6 + } + + /// ANEVH 电池测试工作模式([BATTery:]TEST:MODe 取值) + public enum ANEVH电池测试模式_枚举 + { + /// 静态充电 + 静态充电 = 0, + /// 静态放电 + 静态放电 = 1, + /// 动态测试 + 动态测试 = 2 + } + /// - /// ANEVH 系列双向可编程直流电源(一拖三),基于 TCP 通信,使用 SCPI 指令集。 + /// 艾诺 ANEVH 系列双向可编程直流电源(一拖三),基于 TCP 通信,使用 SCPI 指令集。 /// 作为高压源载一体机使用:同时具备直流电源输出(SOURce)与电子负载(SINK)能力。 + /// 参考文档:艾诺 ANEVH 系列双向电源用户手册 附录B 直流电源通讯协议(SCPI)。 + /// 功能覆盖:常规输出(CV/CC/CP)、内阻模式、电子负载(8种模式+短路)、光伏模拟(SAS/EN50530/SANDIA)、 + /// 序列测试(50组×20步)、固定电池模拟(含电能计量)、电池测试(静态充放电/动态测试)。 + /// 注意:*RST 会复位限值/报警/斜率等参数并停止输出;网口 SCPI 端口以设备「通讯设置-网口参数配置」为准。 /// [ACPCommand] public class ANEVH80 : Tcp @@ -38,6 +145,11 @@ namespace DeviceCommand.Devices { } + #region 底层辅助 + + /// 数值格式化为 SCPI 参数(不变文化,避免区域设置导致小数点变成逗号) + private static string Fmt(double v) => v.ToString(CultureInfo.InvariantCulture); + /// /// 从设备返回的 SCPI 响应字符串中提取数值部分并转换为 double。 /// 支持科学计数法(如 2.48E-03),结果保留两位小数。 @@ -55,303 +167,1258 @@ namespace DeviceCommand.Devices : 0; } - #region 1. 系统与公共指令 + /// 发送设定类命令(只发不读,自动追加结束符;基类 _commLock 已保证串行) + protected async Task SendCmdAsync(string command, CancellationToken ct) + => await base.SendAsync($"{command}{ScpiDelimiter}", ct).ConfigureAwait(false); - /// - /// 清除错误队列 (*CLS) - /// + /// 发送查询类命令并返回去除首尾空白的响应字符串 + protected async Task QueryAsync(string command, CancellationToken ct) + => (await WriteReadAsync($"{command}{ScpiDelimiter}", ScpiDelimiter, ct).ConfigureAwait(false)).Trim(); + + /// 发送查询类命令并把响应解析为 double(解析失败返回 0) + protected async Task QueryDoubleAsync(string command, CancellationToken ct) + => ExtractDouble(await QueryAsync(command, ct).ConfigureAwait(false)); + + /// 发送查询类命令并把响应解析为 int(解析失败返回 0) + protected async Task QueryIntAsync(string command, CancellationToken ct) + => (int)ExtractDouble(await QueryAsync(command, ct).ConfigureAwait(false)); + + /// 发送查询类命令并把响应解析为逗号分隔的 double 数组 + protected async Task QueryDoubleArrayAsync(string command, CancellationToken ct) + { + string resp = await QueryAsync(command, ct).ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(resp)) return Array.Empty(); + var parts = resp.Split(','); + var result = new double[parts.Length]; + for (int i = 0; i < parts.Length; i++) result[i] = ExtractDouble(parts[i]); + return result; + } + + /// 发送查询类命令并把响应解析为开关状态(ON/1 为 true) + protected async Task QueryOnOffAsync(string command, CancellationToken ct) + { + string r = await QueryAsync(command, ct).ConfigureAwait(false); + return r.Equals("ON", StringComparison.OrdinalIgnoreCase) || r == "1"; + } + + #endregion + + #region 1. 系统与公共指令(手册 B2.2/B2.3) + + /// 清除错误队列,清除问题状态事件寄存器、错误信息及报警状态 (*CLS) /// 异步取消令牌 public virtual async Task 清除错误队列Async(CancellationToken ct = default) - { - await SendAsync($"*CLS{ScpiDelimiter}", ct); - } + => await SendCmdAsync("*CLS", ct).ConfigureAwait(false); - /// - /// 重设仪器为出厂默认状态 (*RST) - /// + /// 重设仪器为出厂默认状态,会复位限值/报警/斜率参数、清除报警并停止输出 (*RST) /// 异步取消令牌 public virtual async Task 复位Async(CancellationToken ct = default) - { - await SendAsync($"*RST{ScpiDelimiter}", ct); - } + => await SendCmdAsync("*RST", ct).ConfigureAwait(false); - /// - /// 查询仪器识别码 (*IDN?) - /// + /// 查询仪器识别码:制造商、产品标号、出厂编号、软件版本 (*IDN?) /// 异步取消令牌 /// 设备标识字符串(厂商,型号,序列号,固件版本) public virtual async Task 查询设备信息Async(CancellationToken ct = default) - { - return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct); - } + => await QueryAsync("*IDN?", ct).ConfigureAwait(false); - /// - /// 查询错误信息 (SYST:ERR?) - /// + /// 查询标准事件状态寄存器 (*ESR?) + /// 异步取消令牌 + /// 事件状态寄存器值 + public virtual async Task 查询事件状态Async(CancellationToken ct = default) + => await QueryAsync("*ESR?", ct).ConfigureAwait(false); + + /// 查询错误信息,0=无错误 -101=无效字符 -102=语法错误 -106=非法参数 -200=无效分隔符 -222=参数超电源限值 (SYSTem:ERR?) /// 异步取消令牌 /// 错误信息字符串 public virtual async Task 查询错误信息Async(CancellationToken ct = default) + => await QueryAsync("SYSTem:ERR?", ct).ConfigureAwait(false); + + /// + /// 逐条取空 SCPI 错误队列并返回全部错误码(SYSTem:ERR? 为 FIFO,每次只弹出最早的一条)。 + /// 用于定位"到底是哪条命令报的错":在多命令流程中每发完一条就调用一次,即可把错误精确归因到该命令。 + /// + /// 最多读取条数,防止异常时无限循环 + /// 异步取消令牌 + /// 错误码列表,空列表表示无错误 + public virtual async Task> 读取并清空错误队列Async(int maxCount = 20, CancellationToken ct = default) { - return await WriteReadAsync($"SYST:ERR?{ScpiDelimiter}", ScpiDelimiter, ct); + var errors = new List(); + for (int i = 0; i < maxCount; i++) + { + string e = await 查询错误信息Async(ct).ConfigureAwait(false); + if (e.Split(',')[0].Trim() == "0") break; + errors.Add(e); + } + return errors; } #endregion - #region 2. 输出控制 (OUTPut 子系统) + #region 2. 输出控制(手册 B2.5,OUTPut/INPUT 子系统) - /// - /// 设置输出开关状态 (OUTP ON / OFF) - /// + /// 设置电源输出开关状态 (OUTP ON|OFF) /// true: 开启输出, false: 关闭输出 /// 异步取消令牌 public virtual async Task 设置输出开关Async(bool isOn, CancellationToken ct = default) - { - string state = isOn ? "ON" : "OFF"; - await SendAsync($"OUTP {state}{ScpiDelimiter}", ct); - } + => await SendCmdAsync($"OUTP {(isOn ? "ON" : "OFF")}", ct).ConfigureAwait(false); - /// - /// 设置操作模式 (OUTP:MODE) - /// + /// 设置电子负载输入开关状态,负载模式下才有效 (INPUT ON|OFF) + /// true: 开启输入, false: 关闭输入 + /// 异步取消令牌 + public virtual async Task 设置输入开关Async(bool isOn, CancellationToken ct = default) + => await SendCmdAsync($"INPUT {(isOn ? "ON" : "OFF")}", ct).ConfigureAwait(false); + + /// 启动电源输出 (OUTP ON) + /// 异步取消令牌 + public virtual async Task 启动输出Async(CancellationToken ct = default) + => await 设置输出开关Async(true, ct).ConfigureAwait(false); + + /// 停止电源输出 (OUTP OFF) + /// 异步取消令牌 + public virtual async Task 停止输出Async(CancellationToken ct = default) + => await 设置输出开关Async(false, ct).ConfigureAwait(false); + + /// 启动负载输入 (INPUT ON) + /// 异步取消令牌 + public virtual async Task 启动负载Async(CancellationToken ct = default) + => await 设置输入开关Async(true, ct).ConfigureAwait(false); + + /// 停止负载输入 (INPUT OFF) + /// 异步取消令牌 + public virtual async Task 停止负载Async(CancellationToken ct = default) + => await 设置输入开关Async(false, ct).ConfigureAwait(false); + + /// 查询电源输出开关状态 (OUTP?) + /// 异步取消令牌 + /// true: 输出已开启 + public virtual async Task 查询输出状态Async(CancellationToken ct = default) + => await QueryOnOffAsync("OUTP?", ct).ConfigureAwait(false); + + /// 查询负载输入开关状态 (INPUT?) + /// 异步取消令牌 + /// true: 输入已开启 + public virtual async Task 查询负载输入状态Async(CancellationToken ct = default) + => await QueryOnOffAsync("INPUT?", ct).ConfigureAwait(false); + + /// 清除报警状态,返回待机状态 (OUTP:PROT:CLE) + /// 异步取消令牌 + public virtual async Task 清除报警Async(CancellationToken ct = default) + => await SendCmdAsync("OUTP:PROT:CLE", ct).ConfigureAwait(false); + + /// 设置操作模式(兼容旧接口:FIXED→常规界面,LIST→序列测试界面)(SOUR:MOD) /// 操作模式枚举 (FIXED: 定值 | LIST: 序列测试) /// 异步取消令牌 public virtual async Task 设置操作模式Async(ANEVH操作模式_枚举 mode, CancellationToken ct = default) - { - await SendAsync($"OUTP:MODE {mode}{ScpiDelimiter}", ct); - } + => await SendCmdAsync($"SOUR:MOD {(int)(mode == ANEVH操作模式_枚举.LIST ? ANEVH功能模式_枚举.序列测试 : ANEVH功能模式_枚举.常规)}", ct).ConfigureAwait(false); #endregion - #region 3. 源模式参数设置 (SOURce 子系统) + #region 3. 测量查询(手册 B2.4,MEASure 子系统) - /// - /// 设置源输出电压 (SOUR:VOLT) - /// + /// 查询测量电压 (MEAS:VOLT:DC?) + /// 异步取消令牌 + /// 实际输出电压 (单位: V,保留两位小数) + public virtual async Task 读取电压Async(CancellationToken ct = default) + => await QueryDoubleAsync("MEAS:VOLT:DC?", ct).ConfigureAwait(false); + + /// 查询测量电流,正向为正、反向为负 (MEAS:CURR:DC?) + /// 异步取消令牌 + /// 实际输出电流 (单位: A,保留两位小数,正值为源模式,负值为负载模式) + public virtual async Task 读取电流Async(CancellationToken ct = default) + => await QueryDoubleAsync("MEAS:CURR:DC?", ct).ConfigureAwait(false); + + /// 查询测量功率 (MEAS:POW:DC?) + /// 异步取消令牌 + /// 实际输出功率 (单位: W,保留两位小数) + public virtual async Task 读取功率Async(CancellationToken ct = default) + => await QueryDoubleAsync("MEAS:POW:DC?", ct).ConfigureAwait(false); + + /// 一次性查询输出电压(V)、电流(A)、功率(W) (MEAS:ARR:DC?) + /// 异步取消令牌 + /// (电压, 电流, 功率) 元组 + public virtual async Task<(double 电压, double 电流, double 功率)> 查询输出测量值Async(CancellationToken ct = default) + { + var arr = await QueryDoubleArrayAsync("MEAS:ARR:DC?", ct).ConfigureAwait(false); + return arr.Length >= 3 ? (arr[0], arr[1], arr[2]) : (0, 0, 0); + } + + /// 查询输出电阻,用于内阻模式和电子负载 (MEAS:RES:DC?) + /// 异步取消令牌 + /// 输出电阻 (单位: Ω) + public virtual async Task 查询输出电阻Async(CancellationToken ct = default) + => await QueryDoubleAsync("MEAS:RES:DC?", ct).ConfigureAwait(false); + + /// 查询电源输出状态:1=非启动 3=CV 4=CC 5=CP 6=CR (MEAS:COND?) + /// 异步取消令牌 + /// 输出状态枚举 + public virtual async Task 查询输出条件Async(CancellationToken ct = default) + => (ANEVH输出状态_枚举)await QueryIntAsync("MEAS:COND?", ct).ConfigureAwait(false); + + /// 查询报警代码,16进制值,0x00=无报警,详见手册 B2.4 报警代码表 (MEAS:SYST?) + /// 异步取消令牌 + /// 报警代码 + public virtual async Task 查询报警代码Async(CancellationToken ct = default) + => await QueryIntAsync("MEAS:SYST?", ct).ConfigureAwait(false); + + /// 查询是否处于报警状态,即报警代码 != 0 (MEAS:SYST?) + /// 异步取消令牌 + /// true: 存在报警 + public virtual async Task 是否报警Async(CancellationToken ct = default) + => await 查询报警代码Async(ct).ConfigureAwait(false) != 0; + + /// 查询电池模拟运行 SOC (MEAS:SOC?) + /// 异步取消令牌 + /// SOC (单位: %) + public virtual async Task 查询SOCAsync(CancellationToken ct = default) + => await QueryDoubleAsync("MEAS:SOC?", ct).ConfigureAwait(false); + + #endregion + + #region 4. 源模式——电压(手册 B2.6,SOURce 子系统) + + /// 设置源输出电压 (SOUR:VOLT) /// 电压值 (单位: V) /// 异步取消令牌 public virtual async Task 设置电压Async(double voltage, CancellationToken ct = default) - { - string valStr = voltage.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:VOLT {valStr}{ScpiDelimiter}", ct); - } + => await SendCmdAsync($"SOUR:VOLT {Fmt(voltage)}", ct).ConfigureAwait(false); - /// - /// 查询源设定电压 (SOUR:VOLT?) - /// + /// 查询源设定电压 (SOUR:VOLT?) /// 异步取消令牌 /// 设定电压值 (单位: V) public virtual async Task 查询设定电压Async(CancellationToken ct = default) - { - string resp = await WriteReadAsync($"SOUR:VOLT?{ScpiDelimiter}", ScpiDelimiter, ct); - return ExtractDouble(resp); - } + => await QueryDoubleAsync("SOUR:VOLT?", ct).ConfigureAwait(false); - /// - /// 设置源正向限流 (SOUR:CURR) - /// + /// 设置电压斜率,不允许为 0,范围 0~2000,仅常规功能有效,配合启动命令与在线切换电压使用 (SOUR:VOLT:SLEW) + /// 电压斜率 (单位: V/ms) + /// 异步取消令牌 + public virtual async Task 设置电压斜率Async(double voltsPerMs, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:VOLT:SLEW {Fmt(voltsPerMs)}", ct).ConfigureAwait(false); + + /// 查询电压斜率 (SOUR:VOLT:SLEW?) + /// 异步取消令牌 + /// 电压斜率 (单位: V/ms) + public virtual async Task 查询电压斜率Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:VOLT:SLEW?", ct).ConfigureAwait(false); + + /// 设置过压保护值 OVP (SOUR:VOLT:PROT:HIGH) + /// 过压保护阈值 (单位: V) + /// 异步取消令牌 + public virtual async Task 设置过压保护Async(double voltage, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:VOLT:PROT:HIGH {Fmt(voltage)}", ct).ConfigureAwait(false); + + /// 查询过压保护值 OVP (SOUR:VOLT:PROT:HIGH?) + /// 异步取消令牌 + /// 过压保护阈值 (单位: V) + public virtual async Task 查询过压保护Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:VOLT:PROT:HIGH?", ct).ConfigureAwait(false); + + /// 设置电压设定值上限,限制电压设置范围 (SOUR:VOLT:LIM:HIGH) + /// 电压上限 (单位: V) + /// 异步取消令牌 + public virtual async Task 设置电压上限Async(double volts, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:VOLT:LIM:HIGH {Fmt(volts)}", ct).ConfigureAwait(false); + + /// 查询电压设定值上限 (SOUR:VOLT:LIM:HIGH?) + /// 异步取消令牌 + /// 电压上限 (单位: V) + public virtual async Task 查询电压上限Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:VOLT:LIM:HIGH?", ct).ConfigureAwait(false); + + /// 设置电压设定值下限,限制电压设置范围 (SOUR:VOLT:LIM:LOW) + /// 电压下限 (单位: V) + /// 异步取消令牌 + public virtual async Task 设置电压下限Async(double volts, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:VOLT:LIM:LOW {Fmt(volts)}", ct).ConfigureAwait(false); + + /// 查询电压设定值下限 (SOUR:VOLT:LIM:LOW?) + /// 异步取消令牌 + /// 电压下限 (单位: V) + public virtual async Task 查询电压下限Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:VOLT:LIM:LOW?", ct).ConfigureAwait(false); + + #endregion + + #region 5. 源模式——电流(手册 B2.6,SOURce 子系统) + + /// 设置源正向限流 (SOUR:CURR) /// 电流值 (单位: A,正值) /// 异步取消令牌 public virtual async Task 设置电流Async(double current, CancellationToken ct = default) - { - string valStr = current.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:CURR {valStr}{ScpiDelimiter}", ct); - } + => await SendCmdAsync($"SOUR:CURR {Fmt(current)}", ct).ConfigureAwait(false); - /// - /// 查询源设定电流 (SOUR:CURR?) - /// + /// 查询源设定电流 (SOUR:CURR?) /// 异步取消令牌 /// 设定电流值 (单位: A) public virtual async Task 查询设定电流Async(CancellationToken ct = default) - { - string resp = await WriteReadAsync($"SOUR:CURR?{ScpiDelimiter}", ScpiDelimiter, ct); - return ExtractDouble(resp); - } + => await QueryDoubleAsync("SOUR:CURR?", ct).ConfigureAwait(false); + + /// 设置电流斜率,不允许为 0,范围 0~2000,仅常规功能和电子负载模式有效 (SOUR:CURR:SLEW) + /// 电流斜率 (单位: A/ms) + /// 异步取消令牌 + public virtual async Task 设置电流斜率Async(double ampsPerMs, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:CURR:SLEW {Fmt(ampsPerMs)}", ct).ConfigureAwait(false); + + /// 查询电流斜率 (SOUR:CURR:SLEW?) + /// 异步取消令牌 + /// 电流斜率 (单位: A/ms) + public virtual async Task 查询电流斜率Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:CURR:SLEW?", ct).ConfigureAwait(false); + + /// 设置正向过流报警值 (SOUR:CURR:PROT:HIGH) + /// 过流报警阈值 (单位: A) + /// 异步取消令牌 + public virtual async Task 设置过流保护Async(double current, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:CURR:PROT:HIGH {Fmt(current)}", ct).ConfigureAwait(false); + + /// 查询正向过流报警值 (SOUR:CURR:PROT:HIGH?) + /// 异步取消令牌 + /// 过流报警阈值 (单位: A) + public virtual async Task 查询过流保护Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:CURR:PROT:HIGH?", ct).ConfigureAwait(false); + + /// 设置反向(负载)过流报警值 (SINK:CURR:PROT:HIGH) + /// 过流报警阈值 (单位: A) + /// 异步取消令牌 + public virtual async Task 设置负载过流保护Async(double amps, CancellationToken ct = default) + => await SendCmdAsync($"SINK:CURR:PROT:HIGH {Fmt(amps)}", ct).ConfigureAwait(false); + + /// 查询反向(负载)过流报警值 (SINK:CURR:PROT:HIGH?) + /// 异步取消令牌 + /// 过流报警阈值 (单位: A) + public virtual async Task 查询负载过流保护Async(CancellationToken ct = default) + => await QueryDoubleAsync("SINK:CURR:PROT:HIGH?", ct).ConfigureAwait(false); + + /// 设置过流报警延时时间,电流持续超限达到该时间后报警 (SOUR:CURR:PROT:DEL) + /// 延时时间 (单位: s) + /// 异步取消令牌 + public virtual async Task 设置过流报警延时Async(double seconds, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:CURR:PROT:DEL {Fmt(seconds)}", ct).ConfigureAwait(false); + + /// 查询过流报警延时时间 (SOUR:CURR:PROT:DEL?) + /// 异步取消令牌 + /// 延时时间 (单位: s) + public virtual async Task 查询过流报警延时Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:CURR:PROT:DEL?", ct).ConfigureAwait(false); + + /// 设置电流设定值上限 (SOUR:CURR:LIM:HIGH) + /// 电流上限 (单位: A) + /// 异步取消令牌 + public virtual async Task 设置电流上限Async(double amps, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:CURR:LIM:HIGH {Fmt(amps)}", ct).ConfigureAwait(false); + + /// 查询电流设定值上限 (SOUR:CURR:LIM:HIGH?) + /// 异步取消令牌 + /// 电流上限 (单位: A) + public virtual async Task 查询电流上限Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:CURR:LIM:HIGH?", ct).ConfigureAwait(false); + + /// 设置电流设定值下限 (SOUR:CURR:LIM:LOW) + /// 电流下限 (单位: A) + /// 异步取消令牌 + public virtual async Task 设置电流下限Async(double amps, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:CURR:LIM:LOW {Fmt(amps)}", ct).ConfigureAwait(false); + + /// 查询电流设定值下限 (SOUR:CURR:LIM:LOW?) + /// 异步取消令牌 + /// 电流下限 (单位: A) + public virtual async Task 查询电流下限Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:CURR:LIM:LOW?", ct).ConfigureAwait(false); + + #endregion + + #region 6. 源模式——功率与电阻(手册 B2.6) /// - /// 设置源正向限功率 (SOUR:POW) + /// 设置源正向限功率 (SOUR:POW)。单位 W(面板以 kW 显示,分辨率 0.001kW)。 + /// 可设上界 = min(机型额定功率, 电压设定值×电流设定值),低电压工况下设不到额定功率,需先抬高电压/电流设定值; + /// 另受功率上限(SOUR:POW:LIM:HIGH)限制,超限时设备蜂鸣并拒收(SYSTem:ERR? 返回 -222),必须回读确认。 /// /// 功率值 (单位: W,正值) /// 异步取消令牌 public virtual async Task 设置功率Async(double power, CancellationToken ct = default) - { - string valStr = power.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:POW {valStr}{ScpiDelimiter}", ct); - } + => await SendCmdAsync($"SOUR:POW {Fmt(power)}", ct).ConfigureAwait(false); - /// - /// 查询源设定功率 (SOUR:POW?) - /// + /// 查询源设定功率 (SOUR:POW?) /// 异步取消令牌 /// 设定功率值 (单位: W) public virtual async Task 查询设定功率Async(CancellationToken ct = default) - { - string resp = await WriteReadAsync($"SOUR:POW?{ScpiDelimiter}", ScpiDelimiter, ct); - return ExtractDouble(resp); - } + => await QueryDoubleAsync("SOUR:POW?", ct).ConfigureAwait(false); + + /// 设置正向过功率报警值,0~电源最大功率 (SOUR:POW:PROT:HIGH) + /// 过功率报警阈值 (单位: W) + /// 异步取消令牌 + public virtual async Task 设置过功率保护Async(double watts, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:POW:PROT:HIGH {Fmt(watts)}", ct).ConfigureAwait(false); + + /// 查询正向过功率报警值 (SOUR:POW:PROT:HIGH?) + /// 异步取消令牌 + /// 过功率报警阈值 (单位: W) + public virtual async Task 查询过功率保护Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:POW:PROT:HIGH?", ct).ConfigureAwait(false); + + /// 设置过功率报警延时时间,范围 0~99.999s (SOUR:POW:PROT:DEL) + /// 延时时间 (单位: s) + /// 异步取消令牌 + public virtual async Task 设置过功率报警延时Async(double seconds, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:POW:PROT:DEL {Fmt(seconds)}", ct).ConfigureAwait(false); + + /// 查询过功率报警延时时间 (SOUR:POW:PROT:DEL?) + /// 异步取消令牌 + /// 延时时间 (单位: s) + public virtual async Task 查询过功率报警延时Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:POW:PROT:DEL?", ct).ConfigureAwait(false); /// - /// 设置电压上升斜率 (SOUR:VOLT:SLEW:POS) + /// 设置功率设定值上限,限制所有功能的正/反向功率设置范围,须在设置功率之前下发 (SOUR:POW:LIM:HIGH)。 + /// 可填最大值 = 本机额定功率(并机时为单机功率×台数),超限会被蜂鸣拒收(SYSTem:ERR? 返回 -222); + /// 需保证功率下限不大于上限,建议待机态(OUTP OFF)修改。 /// - /// 电压上升速率 (单位: V/ms) + /// 功率上限 (单位: W) /// 异步取消令牌 - public virtual async Task 设置电压上升斜率Async(double slewRate, CancellationToken ct = default) - { - string valStr = slewRate.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:VOLT:SLEW:POS {valStr}{ScpiDelimiter}", ct); - } + public virtual async Task 设置功率上限Async(double watts, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:POW:LIM:HIGH {Fmt(watts)}", ct).ConfigureAwait(false); - /// - /// 设置电压下降斜率 (SOUR:VOLT:SLEW:NEG) - /// - /// 电压下降速率 (单位: V/ms) + /// 查询功率设定值上限 (SOUR:POW:LIM:HIGH?) /// 异步取消令牌 - public virtual async Task 设置电压下降斜率Async(double slewRate, CancellationToken ct = default) - { - string valStr = slewRate.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:VOLT:SLEW:NEG {valStr}{ScpiDelimiter}", ct); - } + /// 功率上限 (单位: W) + public virtual async Task 查询功率上限Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:POW:LIM:HIGH?", ct).ConfigureAwait(false); - /// - /// 设置电流上升斜率 (SOUR:CURR:SLEW:POS) - /// - /// 电流上升速率 (单位: A/ms) + /// 设置功率设定值下限,不得大于功率上限,否则上限/功率设置均会被拒收 (SOUR:POW:LIM:LOW) + /// 功率下限 (单位: W) /// 异步取消令牌 - public virtual async Task 设置电流上升斜率Async(double slewRate, CancellationToken ct = default) - { - string valStr = slewRate.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:CURR:SLEW:POS {valStr}{ScpiDelimiter}", ct); - } + public virtual async Task 设置功率下限Async(double watts, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:POW:LIM:LOW {Fmt(watts)}", ct).ConfigureAwait(false); - /// - /// 设置电流下降斜率 (SOUR:CURR:SLEW:NEG) - /// - /// 电流下降速率 (单位: A/ms) + /// 查询功率设定值下限 (SOUR:POW:LIM:LOW?) /// 异步取消令牌 - public virtual async Task 设置电流下降斜率Async(double slewRate, CancellationToken ct = default) - { - string valStr = slewRate.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:CURR:SLEW:NEG {valStr}{ScpiDelimiter}", ct); - } + /// 功率下限 (单位: W) + public virtual async Task 查询功率下限Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:POW:LIM:LOW?", ct).ConfigureAwait(false); - /// - /// 设置过压保护值 (SOUR:VOLT:PROT) - /// - /// 过压保护阈值 (单位: V) + /// 设置电阻设定值,内阻模式与电子负载 CR 模式使用 (SINK:RES) + /// 电阻值 (单位: Ω) /// 异步取消令牌 - public virtual async Task 设置过压保护Async(double voltage, CancellationToken ct = default) - { - string valStr = voltage.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:VOLT:PROT {valStr}{ScpiDelimiter}", ct); - } + public virtual async Task 设置电阻Async(double ohms, CancellationToken ct = default) + => await SendCmdAsync($"SINK:RES {Fmt(ohms)}", ct).ConfigureAwait(false); - /// - /// 设置过流保护值 (SOUR:CURR:PROT) - /// - /// 过流保护阈值 (单位: A) + /// 查询电阻设定值 (SINK:RES?) /// 异步取消令牌 - public virtual async Task 设置过流保护Async(double current, CancellationToken ct = default) - { - string valStr = current.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:CURR:PROT {valStr}{ScpiDelimiter}", ct); - } + /// 电阻设定值 (单位: Ω) + public virtual async Task 查询电阻设定值Async(CancellationToken ct = default) + => await QueryDoubleAsync("SINK:RES?", ct).ConfigureAwait(false); - /// - /// 设置过功率保护值 (SOUR:POW:PROT) - /// - /// 过功率保护阈值 (单位: W) + /// 设置电阻设定值上限 (SINK:RES:LIM:HIGH) + /// 电阻上限 (单位: Ω) /// 异步取消令牌 - public virtual async Task 设置过功率保护Async(double power, CancellationToken ct = default) - { - string valStr = power.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SOUR:POW:PROT {valStr}{ScpiDelimiter}", ct); - } + public virtual async Task 设置电阻上限Async(double ohms, CancellationToken ct = default) + => await SendCmdAsync($"SINK:RES:LIM:HIGH {Fmt(ohms)}", ct).ConfigureAwait(false); + + /// 查询电阻设定值上限 (SINK:RES:LIM:HIGH?) + /// 异步取消令牌 + /// 电阻上限 (单位: Ω) + public virtual async Task 查询电阻上限Async(CancellationToken ct = default) + => await QueryDoubleAsync("SINK:RES:LIM:HIGH?", ct).ConfigureAwait(false); + + /// 设置电阻设定值下限 (SINK:RES:LIM:LOW) + /// 电阻下限 (单位: Ω) + /// 异步取消令牌 + public virtual async Task 设置电阻下限Async(double ohms, CancellationToken ct = default) + => await SendCmdAsync($"SINK:RES:LIM:LOW {Fmt(ohms)}", ct).ConfigureAwait(false); + + /// 查询电阻设定值下限 (SINK:RES:LIM:LOW?) + /// 异步取消令牌 + /// 电阻下限 (单位: Ω) + public virtual async Task 查询电阻下限Async(CancellationToken ct = default) + => await QueryDoubleAsync("SINK:RES:LIM:LOW?", ct).ConfigureAwait(false); #endregion - #region 4. 负载模式参数设置 (SINK 子系统) + #region 7. 负载模式参数(SINK 子系统) - /// - /// 设置负载吸收电流 (SINK:CURR) - /// + /// 设置负载吸收电流(反向电流) (SINK:CURR) /// 负载电流值 (单位: A) /// 异步取消令牌 public virtual async Task 设置负载电流Async(double current, CancellationToken ct = default) - { - string valStr = current.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SINK:CURR {valStr}{ScpiDelimiter}", ct); - } + => await SendCmdAsync($"SINK:CURR {Fmt(current)}", ct).ConfigureAwait(false); - /// - /// 查询负载设定电流 (SINK:CURR?) - /// + /// 查询负载设定电流 (SINK:CURR?) /// 异步取消令牌 /// 负载电流设定值 (单位: A) public virtual async Task 查询负载电流Async(CancellationToken ct = default) - { - string resp = await WriteReadAsync($"SINK:CURR?{ScpiDelimiter}", ScpiDelimiter, ct); - return ExtractDouble(resp); - } + => await QueryDoubleAsync("SINK:CURR?", ct).ConfigureAwait(false); - - - /// - /// 设置负载吸收功率 (SINK:POW) - /// + /// 设置负载吸收功率(反向功率),限值设置中的「功率」行同时限制正反向功率,超限蜂鸣拒收 (SINK:POWer) /// 负载功率值 (单位: W) /// 异步取消令牌 public virtual async Task 设置负载功率Async(double power, CancellationToken ct = default) - { - string valStr = power.ToString("0.###", CultureInfo.InvariantCulture); - await SendAsync($"SINK:POWer {valStr}{ScpiDelimiter}", ct); - } + => await SendCmdAsync($"SINK:POWer {Fmt(power)}", ct).ConfigureAwait(false); - /// - /// 查询负载设定功率 (SINK:POW?) - /// + /// 查询负载设定功率 (SINK:POWer?) /// 异步取消令牌 /// 负载功率设定值 (单位: W) public virtual async Task 查询负载功率Async(CancellationToken ct = default) - { - string resp = await WriteReadAsync($"SINK:POWer?{ScpiDelimiter}", ScpiDelimiter, ct); - return ExtractDouble(resp); - } + => await QueryDoubleAsync("SINK:POWer?", ct).ConfigureAwait(false); + + /// 设置反向过功率报警值,0~电源最大功率 (SINK:POW:PROT:HIGH) + /// 过功率报警阈值 (单位: W) + /// 异步取消令牌 + public virtual async Task 设置负载过功率保护Async(double watts, CancellationToken ct = default) + => await SendCmdAsync($"SINK:POW:PROT:HIGH {Fmt(watts)}", ct).ConfigureAwait(false); + + /// 查询反向过功率报警值 (SINK:POW:PROT:HIGH?) + /// 异步取消令牌 + /// 过功率报警阈值 (单位: W) + public virtual async Task 查询负载过功率保护Async(CancellationToken ct = default) + => await QueryDoubleAsync("SINK:POW:PROT:HIGH?", ct).ConfigureAwait(false); #endregion - #region 5. 测量查询 (MEASure 子系统) + #region 8. 功能模式切换(手册 B2.6/B2.8) + + /// 切换功能界面:0常规/1序列/2SAS/3EN50530/4SANDIA/5内阻/6固定电池模拟/10电池测试/12电子负载 (SOUR:MOD) + /// 功能模式枚举 + /// 异步取消令牌 + public virtual async Task 设置功能模式Async(ANEVH功能模式_枚举 mode, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:MOD {(int)mode}", ct).ConfigureAwait(false); + + /// 查询当前功能界面 (SOUR:MOD?) + /// 异步取消令牌 + /// 功能模式枚举 + public virtual async Task 查询功能模式Async(CancellationToken ct = default) + => (ANEVH功能模式_枚举)await QueryIntAsync("SOUR:MOD?", ct).ConfigureAwait(false); + + /// 选择电子负载操作模式:0CV/1CC/2CP/3CR/4CV+CC/5CV+CR/6CC+CR/7Auto,仅待机态可切换 (SINK:MOD) + /// 负载模式枚举 + /// 异步取消令牌 + public virtual async Task 设置负载模式Async(ANEVH负载模式_枚举 mode, CancellationToken ct = default) + => await SendCmdAsync($"SINK:MOD {(int)mode}", ct).ConfigureAwait(false); + + /// 查询当前电子负载模式 (SINK:MOD?) + /// 异步取消令牌 + /// 负载模式枚举 + public virtual async Task 查询负载模式Async(CancellationToken ct = default) + => (ANEVH负载模式_枚举)await QueryIntAsync("SINK:MOD?", ct).ConfigureAwait(false); /// - /// 查询测量电压 (MEAS:VOLT?) + /// 设置电子负载短路模式,需先进入电子负载界面,OUTP OFF 后再退出 (INPUT:SHORt ON|OFF)。 + /// 命令必须全写 INPUT:SHORt:手册 B2.8 仅以举例形式给出该命令,固件不展开 SHOR 缩写,缩写会报 -101/-102。 /// + /// true: 短路开启, false: 短路关闭 /// 异步取消令牌 - /// 实际输出电压 (单位: V,保留两位小数) - public virtual async Task 读取电压Async(CancellationToken ct = default) + public virtual async Task 设置负载短路Async(bool enable, CancellationToken ct = default) + => await SendCmdAsync($"INPUT:SHORt {(enable ? "ON" : "OFF")}", ct).ConfigureAwait(false); + + #endregion + + #region 9. 光伏模拟(手册 B2.9,需先 SOUR:MOD 2|3|4 进入光伏界面) + + /// 设置光伏 Voc 缓升时间,范围 1~99.999s,配合启动命令使用 (SOUR:RAMP) + /// 缓升时间 (单位: s) + /// 异步取消令牌 + public virtual async Task 设置光伏缓升时间Async(double seconds, CancellationToken ct = default) + => await SendCmdAsync($"SOUR:RAMP {Fmt(seconds)}", ct).ConfigureAwait(false); + + /// 查询光伏 Voc 缓升时间 (SOUR:RAMP?) + /// 异步取消令牌 + /// 缓升时间 (单位: s) + public virtual async Task 查询光伏缓升时间Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOUR:RAMP?", ct).ConfigureAwait(false); + + /// 设置光伏运行调节速度:0最快/1快/2中/3慢/4最慢,掉电保存 (SOL:SPEE) + /// 调节速度档位 + /// 异步取消令牌 + public virtual async Task 设置光伏调节速度Async(int speed, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SPEE {speed}", ct).ConfigureAwait(false); + + /// 查询光伏运行调节速度 (SOL:SPEE?) + /// 异步取消令牌 + /// 调节速度档位 + public virtual async Task 查询光伏调节速度Async(CancellationToken ct = default) + => await QueryIntAsync("SOL:SPEE?", ct).ConfigureAwait(false); + + /// 设置光伏模型计算方式:false基础/true高级(高级算法更贴合设置的 VMP/IMP),掉电保存 (SOL:CALC) + /// true: 高级算法 + /// 异步取消令牌 + public virtual async Task 设置光伏计算方式Async(bool advanced, CancellationToken ct = default) + => await SendCmdAsync($"SOL:CALC {(advanced ? "1" : "0")}", ct).ConfigureAwait(false); + + /// 查询光伏模型计算方式 (SOL:CALC?) + /// 异步取消令牌 + /// 0基础/1高级 + public virtual async Task 查询光伏计算方式Async(CancellationToken ct = default) + => await QueryIntAsync("SOL:CALC?", ct).ConfigureAwait(false); + + /// 触发光伏参数生效,设置完光伏参数后必须执行 (SOL:TRIG) + /// 异步取消令牌 + public virtual async Task 触发光伏参数Async(CancellationToken ct = default) + => await SendCmdAsync("SOL:TRIG", ct).ConfigureAwait(false); + + /// 查询当前计算出的实际 Pmp (SOL:PMP?) + /// 异步取消令牌 + /// 实际 Pmp (单位: W) + public virtual async Task 查询光伏实际PmpAsync(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:PMP?", ct).ConfigureAwait(false); + + /// 查询当前计算出的实际 Vmp (SOL:VMP?) + /// 异步取消令牌 + /// 实际 Vmp (单位: V) + public virtual async Task 查询光伏实际VmpAsync(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:VMP?", ct).ConfigureAwait(false); + + /// 查询当前计算出的实际 Imp (SOL:IMP?) + /// 异步取消令牌 + /// 实际 Imp (单位: A) + public virtual async Task 查询光伏实际ImpAsync(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:IMP?", ct).ConfigureAwait(false); + + /// 查询当前计算出的实际 Voc (SOL:VOC?) + /// 异步取消令牌 + /// 实际 Voc (单位: V) + public virtual async Task 查询光伏实际VocAsync(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:VOC?", ct).ConfigureAwait(false); + + /// 查询当前计算出的实际 Isc (SOL:ISC?) + /// 异步取消令牌 + /// 实际 Isc (单位: A) + public virtual async Task 查询光伏实际IscAsync(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:ISC?", ct).ConfigureAwait(false); + + /// 设置 SAS 模式开路电压 Voc (SOL:SAS:VOC) + /// 开路电压 (单位: V) + /// 异步取消令牌 + public virtual async Task 设置SAS开路电压Async(double volts, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAS:VOC {Fmt(volts)}", ct).ConfigureAwait(false); + + /// 查询 SAS 模式开路电压 Voc (SOL:SAS:VOC?) + /// 异步取消令牌 + /// 开路电压 (单位: V) + public virtual async Task 查询SAS开路电压Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:SAS:VOC?", ct).ConfigureAwait(false); + + /// 设置 SAS 模式最大功率点电压 Vmp,须小于 Voc 且 Vmp*Imp 不超过电源最大功率 (SOL:SAS:VMP) + /// 最大功率点电压 (单位: V) + /// 异步取消令牌 + public virtual async Task 设置SAS最大功率点电压Async(double volts, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAS:VMP {Fmt(volts)}", ct).ConfigureAwait(false); + + /// 查询 SAS 模式最大功率点电压 Vmp (SOL:SAS:VMP?) + /// 异步取消令牌 + /// 最大功率点电压 (单位: V) + public virtual async Task 查询SAS最大功率点电压Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:SAS:VMP?", ct).ConfigureAwait(false); + + /// 设置 SAS 模式短路电流 Isc (SOL:SAS:ISC) + /// 短路电流 (单位: A) + /// 异步取消令牌 + public virtual async Task 设置SAS短路电流Async(double amps, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAS:ISC {Fmt(amps)}", ct).ConfigureAwait(false); + + /// 查询 SAS 模式短路电流 Isc (SOL:SAS:ISC?) + /// 异步取消令牌 + /// 短路电流 (单位: A) + public virtual async Task 查询SAS短路电流Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:SAS:ISC?", ct).ConfigureAwait(false); + + /// 设置 SAS 模式最大功率点电流 Imp,须小于 Isc (SOL:SAS:IMP) + /// 最大功率点电流 (单位: A) + /// 异步取消令牌 + public virtual async Task 设置SAS最大功率点电流Async(double amps, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAS:IMP {Fmt(amps)}", ct).ConfigureAwait(false); + + /// 查询 SAS 模式最大功率点电流 Imp (SOL:SAS:IMP?) + /// 异步取消令牌 + /// 最大功率点电流 (单位: A) + public virtual async Task 查询SAS最大功率点电流Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:SAS:IMP?", ct).ConfigureAwait(false); + + /// 设置 EN50530 模式最大功率点电压 Vmp (SOL:EN:VMP) + /// 最大功率点电压 (单位: V) + /// 异步取消令牌 + public virtual async Task 设置EN50530最大功率点电压Async(double volts, CancellationToken ct = default) + => await SendCmdAsync($"SOL:EN:VMP {Fmt(volts)}", ct).ConfigureAwait(false); + + /// 查询 EN50530 模式最大功率点电压 Vmp (SOL:EN:VMP?) + /// 异步取消令牌 + /// 最大功率点电压 (单位: V) + public virtual async Task 查询EN50530最大功率点电压Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:EN:VMP?", ct).ConfigureAwait(false); + + /// 设置 EN50530 模式最大功率点功率 Pmp,须小于电源最大功率 (SOL:EN:PMP) + /// 最大功率点功率 (单位: W) + /// 异步取消令牌 + public virtual async Task 设置EN50530最大功率点功率Async(double watts, CancellationToken ct = default) + => await SendCmdAsync($"SOL:EN:PMP {Fmt(watts)}", ct).ConfigureAwait(false); + + /// 查询 EN50530 模式最大功率点功率 Pmp (SOL:EN:PMP?) + /// 异步取消令牌 + /// 最大功率点功率 (单位: W) + public virtual async Task 查询EN50530最大功率点功率Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:EN:PMP?", ct).ConfigureAwait(false); + + /// 设置 EN50530 模式填充系数 FF:CSI=硅晶/TF=薄膜,具记忆功能 (SOL:EN:TECH) + /// 技术类型字符串(CSI 或 TF) + /// 异步取消令牌 + public virtual async Task 设置EN50530填充系数Async(string tech, CancellationToken ct = default) + => await SendCmdAsync($"SOL:EN:TECH {tech}", ct).ConfigureAwait(false); + + /// 查询 EN50530 模式填充系数 FF (SOL:EN:TECH?) + /// 异步取消令牌 + /// 技术类型字符串 + public virtual async Task 查询EN50530填充系数Async(CancellationToken ct = default) + => await QueryAsync("SOL:EN:TECH?", ct).ConfigureAwait(false); + + /// 设置 EN50530 模式光照强度,0~3000 整数,具记忆功能 (SOL:EN:IRR) + /// 光照强度 (单位: W/m2) + /// 异步取消令牌 + public virtual async Task 设置EN50530光照强度Async(int irr, CancellationToken ct = default) + => await SendCmdAsync($"SOL:EN:IRR {irr}", ct).ConfigureAwait(false); + + /// 查询 EN50530 模式光照强度 (SOL:EN:IRR?) + /// 异步取消令牌 + /// 光照强度 (单位: W/m2) + public virtual async Task 查询EN50530光照强度Async(CancellationToken ct = default) + => await QueryIntAsync("SOL:EN:IRR?", ct).ConfigureAwait(false); + + /// 设置 SANDIA 模式参考光照强度,0~3000 整数 (SOL:SAND:IRRREF) + /// 参考光照强度 (单位: W/m2) + /// 异步取消令牌 + public virtual async Task 设置SANDIA参考光照Async(int irr, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAND:IRRREF {irr}", ct).ConfigureAwait(false); + + /// 查询 SANDIA 模式参考光照强度 (SOL:SAND:IRRREF?) + /// 异步取消令牌 + /// 参考光照强度 (单位: W/m2) + public virtual async Task 查询SANDIA参考光照Async(CancellationToken ct = default) + => await QueryIntAsync("SOL:SAND:IRRREF?", ct).ConfigureAwait(false); + + /// 设置 SANDIA 模式参考温度,-40~85 度 (SOL:SAND:TMPREF) + /// 参考温度 (单位: ℃) + /// 异步取消令牌 + public virtual async Task 设置SANDIA参考温度Async(int temp, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAND:TMPREF {temp}", ct).ConfigureAwait(false); + + /// 查询 SANDIA 模式参考温度 (SOL:SAND:TMPREF?) + /// 异步取消令牌 + /// 参考温度 (单位: ℃) + public virtual async Task 查询SANDIA参考温度Async(CancellationToken ct = default) + => await QueryIntAsync("SOL:SAND:TMPREF?", ct).ConfigureAwait(false); + + /// 设置 SANDIA 模式 BETA 值,0.00~-2.00(薄膜-0.25/标准晶硅-0.38/高效晶硅-0.5) (SOL:SAND:BETA) + /// BETA 值 + /// 异步取消令牌 + public virtual async Task 设置SANDIABetaAsync(double beta, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAND:BETA {Fmt(beta)}", ct).ConfigureAwait(false); + + /// 查询 SANDIA 模式 BETA 值 (SOL:SAND:BETA?) + /// 异步取消令牌 + /// BETA 值 + public virtual async Task 查询SANDIABetaAsync(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:SAND:BETA?", ct).ConfigureAwait(false); + + /// 设置 SANDIA 模式填充系数 FF,0.4~0.95(薄膜0.55/标准晶硅0.68/高效晶硅0.8) (SOL:SAND:TECH) + /// 填充系数 + /// 异步取消令牌 + public virtual async Task 设置SANDIA填充系数Async(double ff, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAND:TECH {Fmt(ff)}", ct).ConfigureAwait(false); + + /// 查询 SANDIA 模式填充系数 FF (SOL:SAND:TECH?) + /// 异步取消令牌 + /// 填充系数 + public virtual async Task 查询SANDIA填充系数Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:SAND:TECH?", ct).ConfigureAwait(false); + + /// 设置 SANDIA 模式光照强度,0~3000 整数 (SOL:SAND:IRR) + /// 光照强度 (单位: W/m2) + /// 异步取消令牌 + public virtual async Task 设置SANDIA光照强度Async(int irr, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAND:IRR {irr}", ct).ConfigureAwait(false); + + /// 查询 SANDIA 模式光照强度 (SOL:SAND:IRR?) + /// 异步取消令牌 + /// 光照强度 (单位: W/m2) + public virtual async Task 查询SANDIA光照强度Async(CancellationToken ct = default) + => await QueryIntAsync("SOL:SAND:IRR?", ct).ConfigureAwait(false); + + /// 设置 SANDIA 模式温度,-40~85 度 (SOL:SAND:TMP) + /// 温度 (单位: ℃) + /// 异步取消令牌 + public virtual async Task 设置SANDIA温度Async(int temp, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAND:TMP {temp}", ct).ConfigureAwait(false); + + /// 查询 SANDIA 模式温度 (SOL:SAND:TMP?) + /// 异步取消令牌 + /// 温度 (单位: ℃) + public virtual async Task 查询SANDIA温度Async(CancellationToken ct = default) + => await QueryIntAsync("SOL:SAND:TMP?", ct).ConfigureAwait(false); + + /// 设置 SANDIA 模式最大功率点功率 Pmp,须小于电源最大功率 (SOL:SAND:PMP) + /// 最大功率点功率 (单位: W) + /// 异步取消令牌 + public virtual async Task 设置SANDIA最大功率点功率Async(double watts, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAND:PMP {Fmt(watts)}", ct).ConfigureAwait(false); + + /// 查询 SANDIA 模式最大功率点功率 Pmp (SOL:SAND:PMP?) + /// 异步取消令牌 + /// 最大功率点功率 (单位: W) + public virtual async Task 查询SANDIA最大功率点功率Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:SAND:PMP?", ct).ConfigureAwait(false); + + /// 设置 SANDIA 模式最大功率点电压 Vmp (SOL:SAND:VMP) + /// 最大功率点电压 (单位: V) + /// 异步取消令牌 + public virtual async Task 设置SANDIA最大功率点电压Async(double volts, CancellationToken ct = default) + => await SendCmdAsync($"SOL:SAND:VMP {Fmt(volts)}", ct).ConfigureAwait(false); + + /// 查询 SANDIA 模式最大功率点电压 Vmp (SOL:SAND:VMP?) + /// 异步取消令牌 + /// 最大功率点电压 (单位: V) + public virtual async Task 查询SANDIA最大功率点电压Async(CancellationToken ct = default) + => await QueryDoubleAsync("SOL:SAND:VMP?", ct).ConfigureAwait(false); + + #endregion + + #region 10. 序列测试(手册 B2.10,需先 SOUR:MOD 1 进入序列界面) + + /// 设置当前序列号,0~49 (PROG:INIT) + /// 序列号 (0~49) + /// 异步取消令牌 + public virtual async Task 设置序列号Async(int program, CancellationToken ct = default) + => await SendCmdAsync($"PROG:INIT {program}", ct).ConfigureAwait(false); + + /// 查询当前序列号,0~49 (PROG:INIT?) + /// 异步取消令牌 + /// 序列号 + public virtual async Task 查询序列号Async(CancellationToken ct = default) + => await QueryIntAsync("PROG:INIT?", ct).ConfigureAwait(false); + + /// 启动指定序列号的序列测试,0~49 (PROG:TRIG) + /// 序列号 (0~49) + /// 异步取消令牌 + public virtual async Task 启动序列测试Async(int program, CancellationToken ct = default) + => await SendCmdAsync($"PROG:TRIG {program}", ct).ConfigureAwait(false); + + /// 停止序列测试 (PROG:ABOR) + /// 异步取消令牌 + public virtual async Task 停止序列测试Async(CancellationToken ct = default) + => await SendCmdAsync("PROG:ABOR", ct).ConfigureAwait(false); + + /// 暂停序列测试 (PROG:ABOR:STEP) + /// 异步取消令牌 + public virtual async Task 暂停序列测试Async(CancellationToken ct = default) + => await SendCmdAsync("PROG:ABOR:STEP", ct).ConfigureAwait(false); + + /// 继续序列测试 (PROG:ABOR:INIT) + /// 异步取消令牌 + public virtual async Task 继续序列测试Async(CancellationToken ct = default) + => await SendCmdAsync("PROG:ABOR:INIT", ct).ConfigureAwait(false); + + /// 查询序列测试状态:0=已完成(未启动)/1=运行/2=暂停 (PROG:STAT?) + /// 异步取消令牌 + /// 序列状态枚举 + public virtual async Task 查询序列状态Async(CancellationToken ct = default) + => (ANEVH序列状态_枚举)await QueryIntAsync("PROG:STAT?", ct).ConfigureAwait(false); + + /// + /// 定义某一步的序列测试参数,共 12 个参数 (PROG:DEF)。 + /// step=序列步数(0-19);mode=0 VI模式/1 电压斜率/2 电流斜率;enable=使能; + /// operation=0无/1循环起始/2循环停止/3暂停;nextOrLink=0下一步/1链接;linkProgram=链接序列号(0-49); + /// loopCount=循环次数;seconds/millis=步进时间;volts/amps/watts=对应模式下的电压(V)/电流(A)/功率(W)。 + /// + /// 序列步数 (0-19) + /// 步进模式 (0 VI模式/1 电压斜率/2 电流斜率) + /// 是否使能 (0/1) + /// 操作 (0无/1循环起始/2循环停止/3暂停) + /// 下一步或链接 (0下一步/1链接) + /// 链接序列号 (0-49) + /// 循环次数 + /// 步进时间秒部分 + /// 步进时间毫秒部分 + /// 电压 (单位: V) + /// 电流 (单位: A) + /// 功率 (单位: W) + /// 异步取消令牌 + public virtual async Task 定义序列步Async(int step, int mode, int enable, int operation, int nextOrLink, int linkProgram, + int loopCount, int seconds, int millis, double volts, double amps, double watts, CancellationToken ct = default) + => await SendCmdAsync( + $"PROG:DEF {step},{mode},{enable},{operation},{nextOrLink},{linkProgram},{loopCount},{seconds},{millis},{Fmt(volts)},{Fmt(amps)},{Fmt(watts)}", ct).ConfigureAwait(false); + + /// 删除某一步序列数据,0-19 (PROG:DEF:DEL) + /// 序列步数 (0-19) + /// 异步取消令牌 + public virtual async Task 删除序列步Async(int step, CancellationToken ct = default) + => await SendCmdAsync($"PROG:DEF:DEL {step}", ct).ConfigureAwait(false); + + /// 复制某一步的序列数据,0-19 (PROG:DEF:STEP) + /// 序列步数 (0-19) + /// 异步取消令牌 + public virtual async Task 复制序列步Async(int step, CancellationToken ct = default) + => await SendCmdAsync($"PROG:DEF:STEP {step}", ct).ConfigureAwait(false); + + /// 粘贴序列数据到某一步,0-19,与复制序列步配合使用 (PROG:DEF:SAVE) + /// 序列步数 (0-19) + /// 异步取消令牌 + public virtual async Task 粘贴序列步Async(int step, CancellationToken ct = default) + => await SendCmdAsync($"PROG:DEF:SAVE {step}", ct).ConfigureAwait(false); + + /// 在某一步序列前插入一步新序列,0-19 (PROG:DEF:NEXT) + /// 序列步数 (0-19) + /// 异步取消令牌 + public virtual async Task 插入序列步Async(int step, CancellationToken ct = default) + => await SendCmdAsync($"PROG:DEF:NEXT {step}", ct).ConfigureAwait(false); + + #endregion + + #region 11. 固定电池模拟(手册 B2.11,需先 SOUR:MOD 6 进入电池模拟界面) + + /// 选择电池类型:0锰酸锂/1钴酸锂/2磷酸铁锂/3铅酸/4镍氢/5三元锂/6钛酸锂 (FUNC:TYPE) + /// 电池类型枚举 + /// 异步取消令牌 + public virtual async Task 设置电池类型Async(ANEVH电池类型_枚举 type, CancellationToken ct = default) + => await SendCmdAsync($"FUNC:TYPE {(int)type}", ct).ConfigureAwait(false); + + /// 查询电池类型 (FUNC:TYPE?) + /// 异步取消令牌 + /// 电池类型枚举 + public virtual async Task 查询电池类型Async(CancellationToken ct = default) + => (ANEVH电池类型_枚举)await QueryIntAsync("FUNC:TYPE?", ct).ConfigureAwait(false); + + /// 设置电池串联数 (FUNC:SERI) + /// 串联数 + /// 异步取消令牌 + public virtual async Task 设置电池串联数Async(int series, CancellationToken ct = default) + => await SendCmdAsync($"FUNC:SERI {series}", ct).ConfigureAwait(false); + + /// 查询电池串联数 (FUNC:SERI?) + /// 异步取消令牌 + /// 串联数 + public virtual async Task 查询电池串联数Async(CancellationToken ct = default) + => await QueryIntAsync("FUNC:SERI?", ct).ConfigureAwait(false); + + /// 设置电池并联数,1~999 (FUNC:PARA) + /// 并联数 + /// 异步取消令牌 + public virtual async Task 设置电池并联数Async(int parallel, CancellationToken ct = default) + => await SendCmdAsync($"FUNC:PARA {parallel}", ct).ConfigureAwait(false); + + /// 查询电池并联数 (FUNC:PARA?) + /// 异步取消令牌 + /// 并联数 + public virtual async Task 查询电池并联数Async(CancellationToken ct = default) + => await QueryIntAsync("FUNC:PARA?", ct).ConfigureAwait(false); + + /// 设置单体电池容量 Q1,范围 0.1~1000.0 (FUNC:CAP) + /// 单体电池容量 (单位: Ah) + /// 异步取消令牌 + public virtual async Task 设置单体电池容量Async(double capacity, CancellationToken ct = default) + => await SendCmdAsync($"FUNC:CAP {Fmt(capacity)}", ct).ConfigureAwait(false); + + /// 查询单体电池容量 Q1 (FUNC:CAP?) + /// 异步取消令牌 + /// 单体电池容量 (单位: Ah) + public virtual async Task 查询单体电池容量Async(CancellationToken ct = default) + => await QueryDoubleAsync("FUNC:CAP?", ct).ConfigureAwait(false); + + /// 设置初始 SOC,范围 0~100 (FUNC:SOC) + /// 初始 SOC (单位: %) + /// 异步取消令牌 + public virtual async Task 设置初始SOCAsync(double soc, CancellationToken ct = default) + => await SendCmdAsync($"FUNC:SOC {Fmt(soc)}", ct).ConfigureAwait(false); + + /// 查询初始 SOC (FUNC:SOC?) + /// 异步取消令牌 + /// 初始 SOC (单位: %) + public virtual async Task 查询初始SOCAsync(CancellationToken ct = default) + => await QueryDoubleAsync("FUNC:SOC?", ct).ConfigureAwait(false); + + /// 下发电池模拟参数,设置完类型/串并联/容量/SOC 后必须执行 (FUNC:TRIG) + /// 异步取消令牌 + public virtual async Task 下发电池模拟参数Async(CancellationToken ct = default) + => await SendCmdAsync("FUNC:TRIG", ct).ConfigureAwait(false); + + /// 查询特征参数:并联容量Qn(Ah)、串联电压E0(V)、单体上限/下限/标准电压(V) (FUNC:FEAT?) + /// 异步取消令牌 + /// (并联容量Qn, 串联电压E0, 单体上限电压, 单体下限电压, 单体标准电压) 元组 + public virtual async Task<(double 并联容量Qn, double 串联电压E0, double 单体上限电压, double 单体下限电压, double 单体标准电压)> 查询电池特征参数Async(CancellationToken ct = default) { - string resp = await WriteReadAsync($"MEAS:VOLT?{ScpiDelimiter}", ScpiDelimiter, ct); - return ExtractDouble(resp); + var arr = await QueryDoubleArrayAsync("FUNC:FEAT?", ct).ConfigureAwait(false); + return arr.Length >= 5 ? (arr[0], arr[1], arr[2], arr[3], arr[4]) : (0, 0, 0, 0, 0); } - /// - /// 查询测量电流 (MEAS:CURR?) - /// + /// 设置电能计量开关,必须在电池模拟运行界面使用 (FUNC:CALC:ENER) + /// true: 开启电能计量 /// 异步取消令牌 - /// 实际输出电流 (单位: A,保留两位小数,正值为源模式,负值为负载模式) - public virtual async Task 读取电流Async(CancellationToken ct = default) + public virtual async Task 设置电能计量Async(bool enable, CancellationToken ct = default) + => await SendCmdAsync($"FUNC:CALC:ENER {(enable ? "1" : "0")}", ct).ConfigureAwait(false); + + /// 查询电能计量开关状态 (FUNC:CALC:ENER?) + /// 异步取消令牌 + /// true: 电能计量已开启 + public virtual async Task 查询电能计量状态Async(CancellationToken ct = default) + => await QueryOnOffAsync("FUNC:CALC:ENER?", ct).ConfigureAwait(false); + + /// 查询电能计量耗能 (FUNC:DISC:ENER?) + /// 异步取消令牌 + /// 耗能 (单位: kWh) + public virtual async Task 查询耗能Async(CancellationToken ct = default) + => await QueryDoubleAsync("FUNC:DISC:ENER?", ct).ConfigureAwait(false); + + /// 查询电能计量馈能 (FUNC:CHAR:ENER?) + /// 异步取消令牌 + /// 馈能 (单位: kWh) + public virtual async Task 查询馈能Async(CancellationToken ct = default) + => await QueryDoubleAsync("FUNC:CHAR:ENER?", ct).ConfigureAwait(false); + + /// 查询电能计量安时 (FUNC:AMP:HOUR?) + /// 异步取消令牌 + /// 安时 (单位: Ah) + public virtual async Task 查询安时Async(CancellationToken ct = default) + => await QueryDoubleAsync("FUNC:AMP:HOUR?", ct).ConfigureAwait(false); + + /// 查询电能计量运行时间,原始返回 时,分,秒 (FUNC:RUN:TIM?) + /// 异步取消令牌 + /// 运行时间字符串(时,分,秒) + public virtual async Task 查询电池模拟运行时间Async(CancellationToken ct = default) + => await QueryAsync("FUNC:RUN:TIM?", ct).ConfigureAwait(false); + + #endregion + + #region 12. 电池测试-充放电(手册 B2.12,需先 SOUR:MOD 10 进入电池测试界面,设置命令在 OFF 状态有效) + + /// 选择电池测试工作模式:0静态充电/1静态放电/2动态测试 (TEST:MOD) + /// 电池测试模式枚举 + /// 异步取消令牌 + public virtual async Task 设置电池测试模式Async(ANEVH电池测试模式_枚举 mode, CancellationToken ct = default) + => await SendCmdAsync($"TEST:MOD {(int)mode}", ct).ConfigureAwait(false); + + /// 查询电池测试工作模式 (TEST:MOD?) + /// 异步取消令牌 + /// 电池测试模式枚举 + public virtual async Task 查询电池测试模式Async(CancellationToken ct = default) + => (ANEVH电池测试模式_枚举)await QueryIntAsync("TEST:MOD?", ct).ConfigureAwait(false); + + /// 查询电池测试状态:工作模式(0静态充电/1静态放电/2动态测试)、动态测试是否运行(0停止/1运行)、动态测试当前模式(0充电/1放电) (TEST:STAT?) + /// 异步取消令牌 + /// (工作模式, 动态运行, 动态当前模式) 元组 + public virtual async Task<(int 工作模式, int 动态运行, int 动态当前模式)> 查询电池测试状态Async(CancellationToken ct = default) { - string resp = await WriteReadAsync($"MEAS:CURR?{ScpiDelimiter}", ScpiDelimiter, ct); - return ExtractDouble(resp); + var arr = await QueryDoubleArrayAsync("TEST:STAT?", ct).ConfigureAwait(false); + return arr.Length >= 3 ? ((int)arr[0], (int)arr[1], (int)arr[2]) : (0, 0, 0); } - /// - /// 查询测量功率 (MEAS:POW?) - /// + /// 查询当前总运行时间,动态测试包括休息时间 (TEST:TIM?) /// 异步取消令牌 - /// 实际输出功率 (单位: W,保留两位小数) - public virtual async Task 读取功率Async(CancellationToken ct = default) + /// 运行时间 (单位: s) + public virtual async Task 查询电池测试运行时间Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:TIM?", ct).ConfigureAwait(false); + + /// 查询当前运行容量 (TEST:CAP?) + /// 异步取消令牌 + /// 运行容量 (单位: Ah) + public virtual async Task 查询电池测试运行容量Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:CAP?", ct).ConfigureAwait(false); + + /// 查询当前运行能量 (TEST:ENER?) + /// 异步取消令牌 + /// 运行能量 (单位: kWh) + public virtual async Task 查询电池测试运行能量Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:ENER?", ct).ConfigureAwait(false); + + /// 重置电池测试:清除当前运行时间、容量和能量 (TEST:CLE) + /// 异步取消令牌 + public virtual async Task 重置电池测试参数Async(CancellationToken ct = default) + => await SendCmdAsync("TEST:CLE", ct).ConfigureAwait(false); + + /// 设置充电电压 (TEST:CHAR:VOLT) + /// 充电电压 (单位: V) + /// 异步取消令牌 + public virtual async Task 设置充电电压Async(double volts, CancellationToken ct = default) + => await SendCmdAsync($"TEST:CHAR:VOLT {Fmt(volts)}", ct).ConfigureAwait(false); + + /// 查询充电电压 (TEST:CHAR:VOLT?) + /// 异步取消令牌 + /// 充电电压 (单位: V) + public virtual async Task 查询充电电压Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:CHAR:VOLT?", ct).ConfigureAwait(false); + + /// 设置充电电流 (TEST:CHAR:CURR) + /// 充电电流 (单位: A) + /// 异步取消令牌 + public virtual async Task 设置充电电流Async(double amps, CancellationToken ct = default) + => await SendCmdAsync($"TEST:CHAR:CURR {Fmt(amps)}", ct).ConfigureAwait(false); + + /// 查询充电电流 (TEST:CHAR:CURR?) + /// 异步取消令牌 + /// 充电电流 (单位: A) + public virtual async Task 查询充电电流Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:CHAR:CURR?", ct).ConfigureAwait(false); + + /// 设置充电停止电流 (TEST:CHAR:ABOR:CURR) + /// 充电停止电流 (单位: A) + /// 异步取消令牌 + public virtual async Task 设置充电停止电流Async(double amps, CancellationToken ct = default) + => await SendCmdAsync($"TEST:CHAR:ABOR:CURR {Fmt(amps)}", ct).ConfigureAwait(false); + + /// 查询充电停止电流 (TEST:CHAR:ABOR:CURR?) + /// 异步取消令牌 + /// 充电停止电流 (单位: A) + public virtual async Task 查询充电停止电流Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:CHAR:ABOR:CURR?", ct).ConfigureAwait(false); + + /// 设置充电停止容量 (TEST:CHAR:ABOR:CAP) + /// 充电停止容量 (单位: Ah) + /// 异步取消令牌 + public virtual async Task 设置充电停止容量Async(double capacity, CancellationToken ct = default) + => await SendCmdAsync($"TEST:CHAR:ABOR:CAP {Fmt(capacity)}", ct).ConfigureAwait(false); + + /// 查询充电停止容量 (TEST:CHAR:ABOR:CAP?) + /// 异步取消令牌 + /// 充电停止容量 (单位: Ah) + public virtual async Task 查询充电停止容量Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:CHAR:ABOR:CAP?", ct).ConfigureAwait(false); + + /// 设置充电停止时间,范围 0~36000 (TEST:CHAR:ABOR:TIM) + /// 充电停止时间 (单位: s) + /// 异步取消令牌 + public virtual async Task 设置充电停止时间Async(double seconds, CancellationToken ct = default) + => await SendCmdAsync($"TEST:CHAR:ABOR:TIM {Fmt(seconds)}", ct).ConfigureAwait(false); + + /// 查询充电停止时间 (TEST:CHAR:ABOR:TIM?) + /// 异步取消令牌 + /// 充电停止时间 (单位: s) + public virtual async Task 查询充电停止时间Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:CHAR:ABOR:TIM?", ct).ConfigureAwait(false); + + /// 设置放电运行模式:CC恒流(放电功率自动设为最大值)/CP恒功率(放电电流自动设为最大值) (TEST:DISC:MOD) + /// true: CP 恒功率, false: CC 恒流 + /// 异步取消令牌 + public virtual async Task 设置放电模式Async(bool constantPower, CancellationToken ct = default) + => await SendCmdAsync($"TEST:DISC:MOD {(constantPower ? "CP" : "CC")}", ct).ConfigureAwait(false); + + /// 查询放电运行模式,返回 CC|CP (TEST:DISC:MOD?) + /// 异步取消令牌 + /// 放电模式字符串(CC 或 CP) + public virtual async Task 查询放电模式Async(CancellationToken ct = default) + => await QueryAsync("TEST:DISC:MOD?", ct).ConfigureAwait(false); + + /// 设置放电电流 (TEST:DISC:CURR) + /// 放电电流 (单位: A) + /// 异步取消令牌 + public virtual async Task 设置放电电流Async(double amps, CancellationToken ct = default) + => await SendCmdAsync($"TEST:DISC:CURR {Fmt(amps)}", ct).ConfigureAwait(false); + + /// 查询放电电流 (TEST:DISC:CURR?) + /// 异步取消令牌 + /// 放电电流 (单位: A) + public virtual async Task 查询放电电流Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:DISC:CURR?", ct).ConfigureAwait(false); + + /// 设置放电功率 (TEST:DISC:POW) + /// 放电功率 (单位: W) + /// 异步取消令牌 + public virtual async Task 设置放电功率Async(double watts, CancellationToken ct = default) + => await SendCmdAsync($"TEST:DISC:POW {Fmt(watts)}", ct).ConfigureAwait(false); + + /// 查询放电功率 (TEST:DISC:POW?) + /// 异步取消令牌 + /// 放电功率 (单位: W) + public virtual async Task 查询放电功率Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:DISC:POW?", ct).ConfigureAwait(false); + + /// 设置放电停止电压 (TEST:DISC:ABOR:VOLT) + /// 放电停止电压 (单位: V) + /// 异步取消令牌 + public virtual async Task 设置放电停止电压Async(double volts, CancellationToken ct = default) + => await SendCmdAsync($"TEST:DISC:ABOR:VOLT {Fmt(volts)}", ct).ConfigureAwait(false); + + /// 查询放电停止电压 (TEST:DISC:ABOR:VOLT?) + /// 异步取消令牌 + /// 放电停止电压 (单位: V) + public virtual async Task 查询放电停止电压Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:DISC:ABOR:VOLT?", ct).ConfigureAwait(false); + + /// 设置放电停止容量 (TEST:DISC:ABOR:CAP) + /// 放电停止容量 (单位: Ah) + /// 异步取消令牌 + public virtual async Task 设置放电停止容量Async(double capacity, CancellationToken ct = default) + => await SendCmdAsync($"TEST:DISC:ABOR:CAP {Fmt(capacity)}", ct).ConfigureAwait(false); + + /// 查询放电停止容量 (TEST:DISC:ABOR:CAP?) + /// 异步取消令牌 + /// 放电停止容量 (单位: Ah) + public virtual async Task 查询放电停止容量Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:DISC:ABOR:CAP?", ct).ConfigureAwait(false); + + /// 设置放电停止时间,范围 0~36000 (TEST:DISC:ABOR:TIM) + /// 放电停止时间 (单位: s) + /// 异步取消令牌 + public virtual async Task 设置放电停止时间Async(double seconds, CancellationToken ct = default) + => await SendCmdAsync($"TEST:DISC:ABOR:TIM {Fmt(seconds)}", ct).ConfigureAwait(false); + + /// 查询放电停止时间 (TEST:DISC:ABOR:TIM?) + /// 异步取消令牌 + /// 放电停止时间 (单位: s) + public virtual async Task 查询放电停止时间Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:DISC:ABOR:TIM?", ct).ConfigureAwait(false); + + /// 设置动态测试初始模式:false=充电/true=放电 (TEST:DYN:INIT) + /// true: 先放电, false: 先充电 + /// 异步取消令牌 + public virtual async Task 设置动态测试初始模式Async(bool dischargeFirst, CancellationToken ct = default) + => await SendCmdAsync($"TEST:DYN:INIT {(dischargeFirst ? "1" : "0")}", ct).ConfigureAwait(false); + + /// 查询动态测试初始模式,返回 0=充电/1=放电 (TEST:DYN:INIT?) + /// 异步取消令牌 + /// 0=充电/1=放电 + public virtual async Task 查询动态测试初始模式Async(CancellationToken ct = default) + => await QueryIntAsync("TEST:DYN:INIT?", ct).ConfigureAwait(false); + + /// 设置动态测试循环次数,0~65535,0 为无限循环 (TEST:DYN:CYCL) + /// 循环次数 + /// 异步取消令牌 + public virtual async Task 设置动态测试循环次数Async(int cycles, CancellationToken ct = default) + => await SendCmdAsync($"TEST:DYN:CYCL {cycles}", ct).ConfigureAwait(false); + + /// 查询动态测试循环次数 (TEST:DYN:CYCL?) + /// 异步取消令牌 + /// 循环次数 + public virtual async Task 查询动态测试循环次数Async(CancellationToken ct = default) + => await QueryIntAsync("TEST:DYN:CYCL?", ct).ConfigureAwait(false); + + /// 设置动态测试休息时间,范围 0~36000 (TEST:DYN:TIM) + /// 休息时间 (单位: s) + /// 异步取消令牌 + public virtual async Task 设置动态测试休息时间Async(double seconds, CancellationToken ct = default) + => await SendCmdAsync($"TEST:DYN:TIM {Fmt(seconds)}", ct).ConfigureAwait(false); + + /// 查询动态测试休息时间 (TEST:DYN:TIM?) + /// 异步取消令牌 + /// 休息时间 (单位: s) + public virtual async Task 查询动态测试休息时间Async(CancellationToken ct = default) + => await QueryDoubleAsync("TEST:DYN:TIM?", ct).ConfigureAwait(false); + + #endregion + + #region 13. 组合便捷方法 + + /// 进入常规界面并以 CV 方式启动输出:依次设置功能模式、电压、正向电流限,然后启动输出 + /// 输出电压 (单位: V) + /// 正向限流 (单位: A) + /// 异步取消令牌 + public virtual async Task 启动CV输出Async(double volts, double currentLimit, CancellationToken ct = default) { - string resp = await WriteReadAsync($"MEAS:POW?{ScpiDelimiter}", ScpiDelimiter, ct); - return ExtractDouble(resp); + await 设置功能模式Async(ANEVH功能模式_枚举.常规, ct).ConfigureAwait(false); + await 设置电压Async(volts, ct).ConfigureAwait(false); + await 设置电流Async(currentLimit, ct).ConfigureAwait(false); + await 启动输出Async(ct).ConfigureAwait(false); + } + + /// 安全停止输出:先将电压设为 0(利用电压斜率缓降),再关闭输出 + /// 异步取消令牌 + public virtual async Task 缓降停止Async(CancellationToken ct = default) + { + await 设置电压Async(0, ct).ConfigureAwait(false); + await 停止输出Async(ct).ConfigureAwait(false); } #endregion diff --git a/DeviceCommand/Devices/IOBoardGroup.cs b/DeviceCommand/Devices/IOBoardGroup.cs index 3cffa4d..3b60a84 100644 --- a/DeviceCommand/Devices/IOBoardGroup.cs +++ b/DeviceCommand/Devices/IOBoardGroup.cs @@ -11,26 +11,36 @@ using System.ComponentModel; namespace DeviceCommand.Devices { /// - /// 系统控制功能类型枚举 (根据三工位 ACP接线图 更新) + /// 系统控制功能类型枚举 (根据 ACP硬件接线图.xlsx 三工位系统更新) /// public enum 功能动作 : byte { - 产品充电三相, - 产品放电三相, + /// 低压电源产品唤醒通断 KL30(三工位,模块1# Y1/Y3/Y5,KA2/KA4/KA6) KL30通断, + /// 低压电源产品唤醒通断 KL15(三工位,模块1# Y2/Y4/Y6,KA3/KA5/KA7) KL15通断, + /// 电子锁60Ω电阻通断(三工位,模块1# Y13/Y14/Y15) 电子锁60欧电阻, + /// 温度检测1KΩ电阻通断(三工位,模块3# Y1/Y2/Y3) 温度检测1K欧电阻, + /// CC信号串1KΩ电阻(三工位,模块2# Y1/Y5/Y9) CC信号串1K欧电阻, + /// CP信号串1KΩ电阻(三工位,模块2# Y13/Y14/Y15) CP信号串1K欧电阻, + /// CC信号串680Ω电阻(三工位,模块2# Y2/Y6/Y10) CC信号串680欧电阻, + /// CC信号串220Ω电阻(三工位,模块2# Y3/Y7/Y11) CC信号串220欧电阻, + /// CC信号串100Ω电阻(三工位,模块2# Y4/Y8/Y12) CC信号串100欧电阻, - CC信号空载, + /// 蜂鸣器阈值报警(三工位,模块1# Y10/Y11/Y12) 蜂鸣器报警, - 抛负载通断, // (接线图中标注于 Y14, KM8) - 短路测试HV, // (接线图中标注于 Y15, KM9) - 短路测试LV // (接线图中标注于 Y16, KM10) + /// 双向直流源(HV+)抛负载通断(仅一工位,模块1# Y7,KA8) + 抛负载通断, + /// 双向直流源(HV)短路测试通断(仅一工位,模块1# Y8,KA9) + 短路测试HV, + /// 低压源载一体机(LV)短路测试通断(仅一工位,模块1# Y9,KA10) + 短路测试LV } /// @@ -50,90 +60,75 @@ namespace DeviceCommand.Devices /// /// IO 板卡组(三工位统一调度),封装 3 块 IO 继电器板卡的访问。 - /// 根据 ACP 硬件接线图的点位映射字典,按台架序号路由到对应板卡的线圈地址, - /// 并内置充电/放电互锁保护,防止同时吸合造成短路。 + /// 根据 ACP硬件接线图.xlsx 的点位映射字典,按台架序号路由到对应板卡的线圈地址。 + /// 注意:模块1# 集中承载三工位的 KL30/KL15 唤醒、蜂鸣器、电子锁及一工位专属的 + /// 抛负载/短路测试;模块2# 承载三工位 CC/CP 引导信号电阻;模块3# 承载三工位温度检测电阻。 /// [ACPCommand] public class IOBoardGroup { - // 声明底层的 3 个 IO 板卡实例(对应三工位系统) + // 声明底层的 3 个 IO 板卡实例(对应接线图中的 IO继电器模块 1#/2#/3#) public IOBoard Board1 { get; private set; } public IOBoard Board2 { get; private set; } public IOBoard Board3 { get; private set; } private readonly byte _slaveAddress = 1; // 默认 Modbus 从站号为 1 - // 核心:根据 ACP硬件接线图 严格对齐的数据字典 (3个模块独立对应1-3工位) + // 核心:根据 ACP硬件接线图.xlsx 严格对齐的数据字典(按工位分组,点位跨模块路由) private static readonly Dictionary> IoMapping = new Dictionary>() { - // 1# 工位 -> IO继电器模块 1# + // 1# 工位(一工位) { 1, new Dictionary<功能动作, IoPortInfo> { - { 功能动作.产品充电三相, new IoPortInfo(1, 0) }, // Y1 -> 0 (KM2) - { 功能动作.产品放电三相, new IoPortInfo(1, 1) }, // Y2 -> 1 (KM3) - { 功能动作.KL30通断, new IoPortInfo(1, 2) }, // Y3 -> 2 - { 功能动作.KL15通断, new IoPortInfo(1, 3) }, // Y4 -> 3 - { 功能动作.电子锁60欧电阻, new IoPortInfo(1, 4) }, // Y5 -> 4 - { 功能动作.温度检测1K欧电阻, new IoPortInfo(1, 5) }, // Y6 -> 5 - { 功能动作.CC信号串1K欧电阻, new IoPortInfo(1, 6) }, // Y7 -> 6 - { 功能动作.CP信号串1K欧电阻, new IoPortInfo(1, 7) }, // Y8 -> 7 - { 功能动作.CC信号串680欧电阻, new IoPortInfo(1, 8) }, // Y9 -> 8 - { 功能动作.CC信号串220欧电阻, new IoPortInfo(1, 9) }, // Y10 -> 9 - { 功能动作.CC信号串100欧电阻, new IoPortInfo(1, 10) }, // Y11 -> 10 - { 功能动作.CC信号空载, new IoPortInfo(1, 11) }, // Y12 -> 11 - { 功能动作.蜂鸣器报警, new IoPortInfo(1, 12) }, // Y13 -> 12 - { 功能动作.抛负载通断, new IoPortInfo(3, 13) }, // Y14 -> 13 (KM8) - { 功能动作.短路测试HV, new IoPortInfo(3, 14) }, // Y15 -> 14 (KM9) - { 功能动作.短路测试LV, new IoPortInfo(3, 15) } // Y16 -> 15 (KM10) + { 功能动作.KL30通断, new IoPortInfo(1, 0) }, // 模块1# Y1 -> 0 (KA2, 低压电源KL30唤醒) + { 功能动作.KL15通断, new IoPortInfo(1, 1) }, // 模块1# Y2 -> 1 (KA3, 低压电源KL15唤醒) + { 功能动作.抛负载通断, new IoPortInfo(1, 6) }, // 模块1# Y7 -> 6 (KA8, 双向直流源HV+抛负载) + { 功能动作.短路测试HV, new IoPortInfo(1, 7) }, // 模块1# Y8 -> 7 (KA9, 双向直流源HV短路测试) + { 功能动作.短路测试LV, new IoPortInfo(1, 8) }, // 模块1# Y9 -> 8 (KA10, 低压源载一体机LV短路测试) + { 功能动作.蜂鸣器报警, new IoPortInfo(1, 9) }, // 模块1# Y10 -> 9 (1#蜂鸣器) + { 功能动作.电子锁60欧电阻, new IoPortInfo(1, 12) }, // 模块1# Y13 -> 12 (1#电子锁60Ω) + { 功能动作.CC信号串1K欧电阻, new IoPortInfo(2, 0) }, // 模块2# Y1 -> 0 (CC 1KΩ) + { 功能动作.CC信号串680欧电阻, new IoPortInfo(2, 1) }, // 模块2# Y2 -> 1 (CC 680Ω) + { 功能动作.CC信号串220欧电阻, new IoPortInfo(2, 2) }, // 模块2# Y3 -> 2 (CC 220Ω) + { 功能动作.CC信号串100欧电阻, new IoPortInfo(2, 3) }, // 模块2# Y4 -> 3 (CC 100Ω) + { 功能动作.CP信号串1K欧电阻, new IoPortInfo(2, 12) }, // 模块2# Y13 -> 12 (CP 1KΩ) + { 功能动作.温度检测1K欧电阻, new IoPortInfo(3, 0) } // 模块3# Y1 -> 0 (温度检测1KΩ) }}, - // 2# 工位 -> IO继电器模块 2# + // 2# 工位(二工位) { 2, new Dictionary<功能动作, IoPortInfo> { - { 功能动作.产品充电三相, new IoPortInfo(2, 0) }, // Y1 -> 0 (KM4) - { 功能动作.产品放电三相, new IoPortInfo(2, 1) }, // Y2 -> 1 (KM5) - { 功能动作.KL30通断, new IoPortInfo(2, 2) }, // Y3 -> 2 - { 功能动作.KL15通断, new IoPortInfo(2, 3) }, // Y4 -> 3 - { 功能动作.电子锁60欧电阻, new IoPortInfo(2, 4) }, // Y5 -> 4 - { 功能动作.温度检测1K欧电阻, new IoPortInfo(2, 5) }, // Y6 -> 5 - { 功能动作.CC信号串1K欧电阻, new IoPortInfo(2, 6) }, // Y7 -> 6 - { 功能动作.CP信号串1K欧电阻, new IoPortInfo(2, 7) }, // Y8 -> 7 - { 功能动作.CC信号串680欧电阻, new IoPortInfo(2, 8) }, // Y9 -> 8 - { 功能动作.CC信号串220欧电阻, new IoPortInfo(2, 9) }, // Y10 -> 9 - { 功能动作.CC信号串100欧电阻, new IoPortInfo(2, 10) }, // Y11 -> 10 - { 功能动作.CC信号空载, new IoPortInfo(2, 11) }, // Y12 -> 11 - { 功能动作.蜂鸣器报警, new IoPortInfo(2, 12) }, // Y13 -> 12 - { 功能动作.抛负载通断, new IoPortInfo(3, 13) }, // Y14 -> 13 (KM8) - { 功能动作.短路测试HV, new IoPortInfo(3, 14) }, // Y15 -> 14 (KM9) - { 功能动作.短路测试LV, new IoPortInfo(3, 15) } // Y16 -> 15 (KM10) + { 功能动作.KL30通断, new IoPortInfo(1, 2) }, // 模块1# Y3 -> 2 (KA4, 低压电源KL30唤醒) + { 功能动作.KL15通断, new IoPortInfo(1, 3) }, // 模块1# Y4 -> 3 (KA5, 低压电源KL15唤醒) + { 功能动作.蜂鸣器报警, new IoPortInfo(1, 10) }, // 模块1# Y11 -> 10 (2#蜂鸣器) + { 功能动作.电子锁60欧电阻, new IoPortInfo(1, 13) }, // 模块1# Y14 -> 13 (2#电子锁60Ω) + { 功能动作.CC信号串1K欧电阻, new IoPortInfo(2, 4) }, // 模块2# Y5 -> 4 (CC 1KΩ) + { 功能动作.CC信号串680欧电阻, new IoPortInfo(2, 5) }, // 模块2# Y6 -> 5 (CC 680Ω) + { 功能动作.CC信号串220欧电阻, new IoPortInfo(2, 6) }, // 模块2# Y7 -> 6 (CC 220Ω) + { 功能动作.CC信号串100欧电阻, new IoPortInfo(2, 7) }, // 模块2# Y8 -> 7 (CC 100Ω) + { 功能动作.CP信号串1K欧电阻, new IoPortInfo(2, 13) }, // 模块2# Y14 -> 13 (CP 1KΩ) + { 功能动作.温度检测1K欧电阻, new IoPortInfo(3, 1) } // 模块3# Y2 -> 1 (温度检测1KΩ) }}, - // 3# 工位 -> IO继电器模块 3# (包含额外的抛负载及短路测试控制) + // 3# 工位(三工位) { 3, new Dictionary<功能动作, IoPortInfo> { - { 功能动作.产品充电三相, new IoPortInfo(3, 0) }, // Y1 -> 0 (KM6) - { 功能动作.产品放电三相, new IoPortInfo(3, 1) }, // Y2 -> 1 (KM7) - { 功能动作.KL30通断, new IoPortInfo(3, 2) }, // Y3 -> 2 - { 功能动作.KL15通断, new IoPortInfo(3, 3) }, // Y4 -> 3 - { 功能动作.电子锁60欧电阻, new IoPortInfo(3, 4) }, // Y5 -> 4 - { 功能动作.温度检测1K欧电阻, new IoPortInfo(3, 5) }, // Y6 -> 5 - { 功能动作.CC信号串1K欧电阻, new IoPortInfo(3, 6) }, // Y7 -> 6 - { 功能动作.CP信号串1K欧电阻, new IoPortInfo(3, 7) }, // Y8 -> 7 - { 功能动作.CC信号串680欧电阻, new IoPortInfo(3, 8) }, // Y9 -> 8 - { 功能动作.CC信号串220欧电阻, new IoPortInfo(3, 9) }, // Y10 -> 9 - { 功能动作.CC信号串100欧电阻, new IoPortInfo(3, 10) }, // Y11 -> 10 - { 功能动作.CC信号空载, new IoPortInfo(3, 11) }, // Y12 -> 11 - { 功能动作.蜂鸣器报警, new IoPortInfo(3, 12) }, // Y13 -> 12 - { 功能动作.抛负载通断, new IoPortInfo(3, 13) }, // Y14 -> 13 (KM8) - { 功能动作.短路测试HV, new IoPortInfo(3, 14) }, // Y15 -> 14 (KM9) - { 功能动作.短路测试LV, new IoPortInfo(3, 15) } // Y16 -> 15 (KM10) + { 功能动作.KL30通断, new IoPortInfo(1, 4) }, // 模块1# Y5 -> 4 (KA6, 低压电源KL30唤醒) + { 功能动作.KL15通断, new IoPortInfo(1, 5) }, // 模块1# Y6 -> 5 (KA7, 低压电源KL15唤醒) + { 功能动作.蜂鸣器报警, new IoPortInfo(1, 11) }, // 模块1# Y12 -> 11 (3#蜂鸣器) + { 功能动作.电子锁60欧电阻, new IoPortInfo(1, 14) }, // 模块1# Y15 -> 14 (3#电子锁60Ω) + { 功能动作.CC信号串1K欧电阻, new IoPortInfo(2, 8) }, // 模块2# Y9 -> 8 (CC 1KΩ) + { 功能动作.CC信号串680欧电阻, new IoPortInfo(2, 9) }, // 模块2# Y10 -> 9 (CC 680Ω) + { 功能动作.CC信号串220欧电阻, new IoPortInfo(2, 10) }, // 模块2# Y11 -> 10 (CC 220Ω) + { 功能动作.CC信号串100欧电阻, new IoPortInfo(2, 11) }, // 模块2# Y12 -> 11 (CC 100Ω) + { 功能动作.CP信号串1K欧电阻, new IoPortInfo(2, 14) }, // 模块2# Y15 -> 14 (CP 1KΩ) + { 功能动作.温度检测1K欧电阻, new IoPortInfo(3, 2) } // 模块3# Y3 -> 2 (温度检测1KΩ) }} }; /// - /// 构造函数,注入三个工位的 IO 板卡实例。 + /// 构造函数,注入三个 IO 板卡实例。 /// - /// 1# 工位 IO 板卡实例 - /// 2# 工位 IO 板卡实例 - /// 3# 工位 IO 板卡实例 + /// IO继电器模块 1# 板卡实例 + /// IO继电器模块 2# 板卡实例 + /// IO继电器模块 3# 板卡实例 /// 任一块板卡实例为空时抛出 - // 修改构造函数以支持 3 个板块 public IOBoardGroup(IOBoard board1, IOBoard board2, IOBoard board3) { Board1 = board1 ?? throw new ArgumentNullException(nameof(board1), "IOBoard Board1 实例不能为空。"); @@ -142,7 +137,7 @@ namespace DeviceCommand.Devices } /// - /// 执行指定台架的功能动作控制(带高低电平开关及底层安全互锁) + /// 执行指定台架的功能动作控制(按接线图字典跨模块路由到对应线圈地址) /// /// 台架/工位序号 (1 - 3) /// 控制功能类型 @@ -153,29 +148,10 @@ namespace DeviceCommand.Devices // 1. 根据传入的台架序号和动作检索字典映射关系 if (!IoMapping.TryGetValue(台架序号, out var 动作字典) || !动作字典.TryGetValue(动作, out var io信息)) { - throw new ArgumentException($"未找到台架 [{台架序号}] 对应功能 [{动作}] 的 IO 点位映射配置。请注意抛负载及短路测试仅存在于 3# 工位。"); + throw new ArgumentException($"未找到台架 [{台架序号}] 对应功能 [{动作}] 的 IO 点位映射配置。请注意抛负载及短路测试(HV/LV)仅存在于 1# 工位。"); } - // 2. 软件防错高危互锁逻辑:防止同时执行充电和放电 - if (开关状态) - { - if (动作 == 功能动作.产品充电三相) - { - if (IoMapping[台架序号].TryGetValue(功能动作.产品放电三相, out var 放电点位)) - { - await GetBoardInstance(放电点位.ModuleIndex).写输出开关(_slaveAddress, 放电点位.Address, false); - } - } - else if (动作 == 功能动作.产品放电三相) - { - if (IoMapping[台架序号].TryGetValue(功能动作.产品充电三相, out var 充电点位)) - { - await GetBoardInstance(充电点位.ModuleIndex).写输出开关(_slaveAddress, 充电点位.Address, false); - } - } - } - - // 3. 动态获取目标板卡实例并直接驱动开关端口 + // 2. 动态获取目标板卡实例并直接驱动开关端口 IOBoard 目标板卡 = GetBoardInstance(io信息.ModuleIndex); await 目标板卡.写输出开关(_slaveAddress, io信息.Address, 开关状态); } @@ -212,4 +188,4 @@ namespace DeviceCommand.Devices return board ?? throw new InvalidOperationException($"IO板卡模块 [{moduleIndex}#] 尚未完成初始化,无法建立总线通信。"); } } -} \ No newline at end of file +} diff --git a/DeviceCommand/Devices/S7200.cs b/DeviceCommand/Devices/S7200.cs index f0a2397..669d685 100644 --- a/DeviceCommand/Devices/S7200.cs +++ b/DeviceCommand/Devices/S7200.cs @@ -236,7 +236,8 @@ namespace DeviceCommand.Devices /// 取消令牌 public async Task 设置CV正向电流(double 电流, CancellationToken ct = default) { - await SendAsync($"CURRent:LIMit:POSitive {电流}{ScpiDelimiter}", ct); + await SendAsync($"VOLTage:ILIMit {电流}{ScpiDelimiter}", ct); + } /// @@ -247,7 +248,7 @@ namespace DeviceCommand.Devices public async Task 设置CV反向电流(double 电流, CancellationToken ct = default) { // 载模式限制需要负数,若传入正数建议在外部转换为负值 - await SendAsync($"CURRent:LIMit:NEGative {电流}{ScpiDelimiter}", ct); + await SendAsync($"VOLTage:ILIMit:NEGative {电流}{ScpiDelimiter}", ct); } ///