From 4e0fd05ccc70042a94cc3006b06cba0acce9d32d Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 5 Jul 2026 21:51:31 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=84=20FNIRSI=20LCR-ST1=E7=94=B5?= =?UTF-8?q?=E6=A1=A5=E9=95=8A=E5=AD=90=E9=80=86=E5=90=91=E5=88=86=E6=9E=90?= =?UTF-8?q?=EF=BC=9ABOM=E4=BC=B0=E7=AE=97+DFT=E7=AE=97=E6=B3=95+=E8=BD=AF?= =?UTF-8?q?=E4=BB=B6=E5=AE=9E=E7=8E=B0=E8=AF=A6=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FNIRSI_LCR-ST1_逆向分析.md | 831 +++++++++++++++++++++++++++++++++++++ 1 file changed, 831 insertions(+) create mode 100644 FNIRSI_LCR-ST1_逆向分析.md diff --git a/FNIRSI_LCR-ST1_逆向分析.md b/FNIRSI_LCR-ST1_逆向分析.md new file mode 100644 index 0000000..a3a1e58 --- /dev/null +++ b/FNIRSI_LCR-ST1_逆向分析.md @@ -0,0 +1,831 @@ +# FNIRSI LCR-ST1 电桥镊子逆向分析 —— 硬件方案、BOM 估算与算法软件详解 + +> **作者:** 小德 +> **分类:** 产品逆向 · LCR 电桥 · 嵌入式 +> **版本:** V1.0 +> **日期:** 2026-07-05 +> **参考零售价:** ¥138(京东) +> **声明:** 以下分析基于公开的产品规格、该品类通用设计模式和工程经验推导,未经实测拆解验证,仅供技术研究参考。 + +--- + +## 概览 + +FNIRSI LCR-ST1 是一款手持式 LCR 电桥镊子,定位于"能用就行"的入门级元器件测试仪。¥138 的售价决定了它的每一步设计都在成本和性能之间做权衡。本文从硬件架构、BOM 估算、测量原理、算法实现四个层面展开逐级拆解。 + +--- + +## 一、已知规格与功能反推 + +### 1.1 公开规格 + +| 参数 | 标注值 | 可信度判断 | +|------|--------|-----------| +| 测量参数 | L / C / R / Q / D / ESR | 可信 | +| 测试频率 | 100Hz / 1kHz / 10kHz | 可信(三频点标准) | +| 量程 | L: 0.01μH~10H, C: 0.1pF~10mF, R: 0.01Ω~10MΩ | 可信 | +| 精度 | 1%(典型) | 可信(¥138 级别) | +| 显示 | 0.96" OLED 128×64 | 可信 | +| 供电 | CR2032 ×1 或 2×LR44 | 待确认(CR2032 概率大) | +| 镊子开口 | 2~3mm | 可信 | +| 自动关机 | 有 | 可信 | + +### 1.2 从规格反推硬件框架 + +``` +三频点(100Hz/1kHz/10kHz)+ 自动量程 + 1% 精度 + OLED 显示 + ¥138 成本 + ↓ +必须用 MCU 产生测试信号 + 做 DFT 解调 +必须用 I-V 转换法(非电桥平衡法,后者成本太高) +MCU 只能是国产 Cortex-M 或 RISC-V +模拟前端只能用通用运放,不可能用 AD8302/AD5933 等专用芯片 + ↓ +典型方案 = MCU (PWM+DAC) + 双运放 + 模拟开关 + OLED +``` + +--- + +## 二、硬件方案推理(最可能的 BOM) + +### 2.1 核心芯片选型 + +#### MCU:GD32F103C8T6 或 APM32F103C8T6 + +``` +为什么选它: + 72MHz Cortex-M3 + 64KB Flash / 20KB RAM — 够跑 DFT + OLED 驱动 + 双 12bit ADC(1Msps) — 同时采电压和电流 + 双 12bit DAC — 产生测试正弦波(或 PWM+LPF) + 多个定时器 — 精确控制采样时序 + 价格 ¥5~8 — 比 STM32 便宜一半 + +替代可能: + - CH32V103 (RISC-V, ¥3~5) — 更便宜,但生态弱 + - AT32F403 (Cortex-M4, ¥6~10) — 有 FPU,计算更快 +``` + +#### 显示:0.96" OLED SSD1306 + +``` +接口:I2C (¥6~8) 或 SPI (¥6~8) +分辨率:128×64 +驱动芯片:SSD1306 +价格:¥6~8(模块)、¥2~4(裸屏 COG) +``` + +#### 双运放:LMV358 或 SGM358 + +``` +用途: + 运放A:I-V 转换器(跨阻放大器),将被测件电流转为电压 + 运放B:电压缓冲/跟随器,提供参考电压 + +为什么选 LMV358: + 轨到轨输出(适合 3.3V 单电源) + 增益带宽积 1MHz(1kHz/10kHz 没问题,100Hz 更是轻松) + 价格 ¥0.5~1.0 + SGM358 是国产替代,¥0.3~0.5 +``` + +#### 模拟开关:74HC4051 或 CD4051 + +``` +用途:自动量程切换——选择不同的参考电阻 R_ref +通道:8 选 1,对应 8 个量程档位 + +量程电阻(典型值): + Ch0: 10Ω (低阻 R 测量) + Ch1: 100Ω (中低阻) + Ch2: 1kΩ (中阻) + Ch3: 10kΩ (中高阻 / 一般 L/C) + Ch4: 100kΩ (高阻) + Ch5: 1MΩ (极高阻 / 小电容) + Ch6: 10MΩ (超高阻 / 极小电容) + Ch7: 空/校准位 + +价格:¥0.5~1.0 +``` + +#### 其他关键器件 + +| 器件 | 型号 | 数量 | 单价 | 用途 | +|------|------|------|------|------| +| 参考电阻 | 0805 1% 金属膜 | 8 | ¥0.08 | 量程网络 | +| 去耦电容 | 0805 100nF + 10μF | 10 | ¥0.03 | 电源去耦 | +| 电池座 | CR2032 贴片 | 1 | ¥1.5 | 供电 | +| 升压 | HT7750 或 S-8351 | 1 | ¥1~2 | 3V→5V(为运放供电) | +| 晶振 | 8MHz 无源 | 1 | ¥0.3 | MCU 主时钟 | +| 按键 | 贴片轻触 | 2 | ¥0.2 | 功能/保持 | +| 镊子 | 镀金磷铜 | 1对 | ¥2~3 | 被测件接触 | +| PCB | 双面板 1.6mm FR4 | 1 | ¥3~4 | 约 60mm×20mm | +| 电池 | CR2032 | 1 | ¥1 | 零售送电池 | + +--- + +### 2.2 系统框图(推理) + +``` + ┌───────────┐ + ┌───┤ CR2032 ├───┐ + │ │ 3V │ │ + │ └───────────┘ │ + ▼ ▼ + ┌───────────┐ ┌───────────┐ + │ 升压 DC-DC │ │ --- │ + │ HT7750 5V │ │ 直接 3.3V │ + │ (供运放) │ │ (供MCU) │ + └─────┬─────┘ └───────────┘ + │ 5V + ▼ +┌─────────────────────────────────────────────────┐ +│ GD32F103C8T6 │ +│ │ +│ DAC0 ──→ LPF ──→ 量程开关(4051) ──→ 镊子探头──┐ │ +│ (选择 R_ref) ↓ │ │ +│ ↓ │ │ +│ ADC0 ←── 运放A(跨阻) ←── 电流信号 ←──┘ │ │ +│ ADC1 ←── 运放B(缓冲) ←── 电压信号 ←─────────┘ │ +│ │ +│ I2C ──→ OLED SSD1306 (128×64) │ +│ GPIO ──→ 按键×2 │ +│ GPIO ──→ ADC 量程切换 LED 指示 │ +│ TIM ──→ 定时触发 ADC 采样 │ +└─────────────────────────────────────────────────┘ +``` + +### 2.3 模拟前端完整拓扑 + +``` + ┌─────────────────────┐ + DAC0 ─── 二阶 LPF ──┬──────┤ 4051 量程开关 │ + (正弦波) (f_c≈30kHz) │ 选择 R_ref[0..7] │ + │ │ │ + │ │ OUT ──┬── 镊子 + │ + │ │ │ │ + │ │ GND │ + │ └─────────────────────┘ + │ │ + │ │ I_dut + │ ▼ + │ ┌──────────┐ + │ │ 运放A │ + │ │ LMV358 │ + │ │ 跨阻放大器│ + │ │ V_I = I │ + │ │ ×Rf │ + │ └────┬─────┘ + │ │ + │ ADC0_CH0 + │ (电流信号) + │ + │ V_dut (经由另一引线取) + │ + └─────────── 运放B ──┬── ADC0_CH1 + LMV358 │ (电压信号) + 缓冲器 │ +``` + +**注意:** 单 ADC 芯片、双通道同时采样,需要 STM32 的 ADC 双规则组模式或注入模式。 + +### 2.4 信号产生(DAC + LPF) + +MCU DAC 生成正弦波,需要经过低通滤波器滤除采样阶梯: + +``` +DAC 输出(12bit,120kHz 更新率 → 每个正弦周期 12 个阶梯): + │ ████ + │ █ ██ ██ + │█ ██ ██ + └──────────────── + +经 2 阶 LPF 后(f_c ≈ 30kHz): + │ ~~~~~~~~ + │ ~~~~~~~~ + │~~~~~~~~ + └──────────────── → 干净正弦波 + +LPF 参数(二阶巴特沃斯,f_c=30kHz): + 运放:用第三个运放(LMV358 是双运放,不够) + 所以 LPF 用无源 RC: + R=1k, C=5.6nF → f_c ≈ 28.4kHz(一阶) + 再加一级 RC:R=1k, C=3.3nF → 二阶共衰减 ~40dB@120kHz +``` + +这里有个问题:LMV358 只有双运放,一个做跨阻(运放A),一个做缓冲(运放B),没有第三个运放做有源 LPF。最可能的做法是: + +1. **无源 RC LPF**:两级 RC 做正弦波滤波(DAC → RC → RC → 4051) +2. **或者直接用 PWM + 有源 LPF**:省掉 DAC,用 MCU 的定时器 PWM 输出,经二阶有源 LPF 得到正弦波——需要一个额外运放 +3. **或者 MCU 内置 DAC 直接输出** + 无源 RC 凑合用 + +¥138 级别的产品,最可能是方案1(无源 RC)。 + +--- + +### 2.5 总体 BOM 成本估算 + +| 编号 | 器件 | 参考型号 | 数量 | 单价¥ | 小计¥ | +|------|------|---------|------|-------|-------| +| 1 | MCU | GD32F103C8T6 | 1 | 6.5 | 6.5 | +| 2 | 运放 | LMV358 / SGM358 | 2 | 0.6 | 1.2 | +| 3 | 模拟开关 | 74HC4051 | 1 | 0.6 | 0.6 | +| 4 | OLED 屏幕 | SSD1306 0.96" 128×64 | 1 | 8.0 | 8.0 | +| 5 | DC-DC 升压 | HT7750 (3V→5V) | 1 | 1.5 | 1.5 | +| 6 | 量程电阻 | 0805 1% 10Ω~10MΩ×8 | 8 | 0.08 | 0.64 | +| 7 | 无源元件 | R/C 若干 | 20 | 0.03 | 0.6 | +| 8 | 晶振 | 8MHz 无源 | 1 | 0.3 | 0.3 | +| 9 | 按键 | 贴片轻触 4pin | 2 | 0.2 | 0.4 | +| 10 | 电池座 | CR2032 贴片 | 1 | 1.5 | 1.5 | +| 11 | 镊子 | 镀金磷铜 | 1对 | 2.5 | 2.5 | +| 12 | PCB | 双面板 60×20mm | 1 | 3.5 | 3.5 | +| 13 | 外壳 | 开模注塑(摊销量) | 1 | 3.0 | 3.0 | +| 14 | 其他(排针、焊锡、包装) | — | 套 | 2.0 | 2.0 | +| | | | | | **¥32.7** | + +**BOM 估算结论:** 硬件 BOM 约 **¥30~35/台**(含外壳、包装),零售 ¥138,毛利约 75%。扣除运营、物流、平台抽成(~15%)、人工,净利润约 35~40%。 + +作为对比,如果换用 AD8302 方案,BOM 将飙升至 ¥60+,¥138 的零售价无法支撑。 + +--- + +## 三、测量原理——I-V 转换 + DFT 方法 + +### 3.1 基本原理 + +LCR-ST1 采用 **I-V 转换法**(也称伏安法、V-I 法): + +``` +向被测件 DUT 注入正弦波 V_source + ↓ +测量 DUT 两端的电压 V_dut +测量流过 DUT 的电流 I_dut(通过跨阻放大器转换为 V_I = I_dut × R_f) + ↓ +计算复阻抗 Z = V_dut / I_dut = R + jX +``` + +**与方案B的核心关系:** LCR-ST1 使用的就是我们在前面讨论的 **DDS 注入 + 阻抗分析** 方法!只不过用 MCU 内置 DAC 替代了独立 DDS 芯片,用通用运放替代了 AD8302/AD8333,是**极致成本优化的方案C的数字IQ + 廉价前端的实现**。 + +### 3.2 测量模型 + +``` + 4051 选通的 R_ref + DAC ──┬─ R_ref ──┬───────── 镊子正极 ──┬── V_dut + │ │ │ + │ ▼ │ + │ ┌──────────┐ │ + │ │ 运放A(跨阻)│ │ + │ │ V_I = I │ │ + │ │ ×R_ref│ │ + │ └──────────┘ │ + │ │ I_dut │ + │ ADC0_CH0 │ + │ │ + │ ADC0_CH1 + └──────────────────────────── 参考地 + + 镊子负极 ───────────────────────── 参考地 +``` + +**重要细节:** 电流测量用的是"跨阻放大器"接法——也就是将运放接成电流→电压转换形式,DUT 电流流过反馈电阻 R_f,产生 V_out = -I_dut × R_f。R_f 就是 4051 选通的量程电阻。 + +### 3.3 等效电路 + +``` + ┌───────────────────┐ + │ DUT │ + │ ┌───────────┐ │ + │ │ │ │ + ├──┤ R_dut+jX │────┤ + │ │ │ │ + │ └───────────┘ │ + └───────────────────┘ + +测量的是 DUT 的复阻抗 Z_dut = V_dut / I_dut + +对于不同 DUT: + 电阻:Z = R + 电感:Z = jωL = j2πfL + 电容:Z = 1/(jωC) = -j/(2πfC) +``` + +### 3.4 自动量程逻辑 + +``` +上电后默认从最大量程(R_ref=10MΩ)开始: + 1. 施加测试信号 + 2. 测量 V_dut 和 V_I + 3. 如果 V_dut < 满量程×0.1 → 切换高一档(R_ref 变小,电流增大) + 4. 如果 V_dut > 满量程×0.9 → 切换低一档(R_ref 变大,电流减小) + 5. 建立稳定后再做 DFT → 计算 L/C/R/Q/D + +量程切换判断:占用 50~200ms +测量+计算:每个频点需 100~500ms +三个频点扫描一次:约 0.5~2s +``` + +--- + +## 四、算法与软件实现详解 + +### 4.1 信号采样与 DFT 解调 + +这是 LCR-ST1 软件的核心。基于 MCU 的 DAC+ADC,通过 DFT 提取幅度和相位。 + +#### 采样时序 + +``` +测试频率 f₀ = 1kHz(举例) + +ADC 采样率 f_s:被配置为 f₀ × 64 = 64kHz + → 每个正弦周期采 64 个点 + → 采样周期 T_s = 15.625μs + → 采集 N = 128 个周期 → 共 8192 个点 → 耗时 128ms + +DAC 更新率:同样是 64kHz,与 ADC 同步 + → DAC 每周期输出 64 个阶梯 ≈ 12 个阶梯已足够平滑 +``` + +#### DFT 计算 + +```c +// ============================================================ +// LCR-ST1 核心:单频 DFT 解调 +// 输入:V_dut[N] 和 V_I[N] 的 ADC 采样值 +// 输出:幅度和相位 +// ============================================================ + +#define F_SAMPLE 64000 // 64kHz 采样率 +#define N_SAMPLES 8192 // 128 个周期 +#define F_SIG 1000 // 1kHz 测试信号 + +// 预计算 sin/cos 表(半波对称压缩) +// 实际上 MCU Flash 够大,可以直接存 64 个点(一个周期) +// 用查表 + 循环索引,避免运行时计算三角函数 +int16_t cos_table[64]; // cos(2π×k/64), k=0..63 +int16_t sin_table[64]; // sin(2π×k/64), k=0..63 + +void DFT_Init(void) { + for (int i = 0; i < 64; i++) { + cos_table[i] = (int16_t)(cosf(2*PI*i/64) * 32767); + sin_table[i] = (int16_t)(sinf(2*PI*i/64) * 32767); + } +} + +// 注意:N_SAMPLES 必须能被样周期数 64 整除! +// 这里 N_SAMPLES = 8192 = 128 × 64 ✅ + +void DFT_Demodulate( + uint16_t *v_dut, // 电压通道采样数组 + uint16_t *v_i, // 电流通道采样数组 + float *mag_dut, // 输出电压幅度 + float *mag_i, // 输出电流幅度 + float *phase_diff // 输出相位差(弧度) +) { + int64_t I_dut = 0, Q_dut = 0; + int64_t I_i = 0, Q_i = 0; + + for (int i = 0; i < N_SAMPLES; i++) { + int tbl_idx = i & 63; // i % 64,查表索引 + + // 电压通道 DFT + I_dut += (int64_t)v_dut[i] * cos_table[tbl_idx]; + Q_dut += (int64_t)v_dut[i] * sin_table[tbl_idx]; + + // 电流通道 DFT + I_i += (int64_t)v_i[i] * cos_table[tbl_idx]; + Q_i += (int64_t)v_i[i] * sin_table[tbl_idx]; + } + + // 归一化为幅度 + // |V| = sqrt(I² + Q²) × 2/N_SAMPLES + float mag_I_dut = sqrtf(I_dut*I_dut + Q_dut*Q_dut); + float mag_I_i = sqrtf(I_i*I_i + Q_i*Q_i); + + float norm = 2.0f / (float)N_SAMPLES * (3.3f / 4096.0f); + // 注意:12bit ADC,满量程 3.3V,4096 码值 + + *mag_dut = mag_I_dut * norm; // V_dut 幅度(伏) + *mag_i = mag_I_i * norm; // V_i 幅度(伏) + + // 相位差 = atan2(Q, I) 的差值 + float phase_dut = atan2f(Q_dut, I_dut); + float phase_i = atan2f(Q_i, I_i); + *phase_diff = phase_i - phase_dut; + + // 归一化到 -π ~ π 范围 + if (*phase_diff > PI) *phase_diff -= 2*PI; + if (*phase_diff < -PI) *phase_diff += 2*PI; +} + +// 对 GD32F103(无 FPU)运行的优化: +// 以上计算中有 sqrtf、atan2f 等浮点运算,FPU 在 M3 下不存在 +// 实际实现中,多半用查表 + CORDIC 或 Q15 定点数运算 +``` + +#### 无 FPU 定点数优化方案 + +GD32F103 是 Cortex-M3,**无硬件 FPU**。用软件浮点计算 8192 点 DFT 会非常慢(可能耗时 > 1s)。实际产品必须用定点数: + +```c +// 定点数 DFT(Q15 格式) +// 用 32bit 累加器防溢出 + +int32_t I_dut = 0, Q_dut = 0; + +for (int i = 0; i < N_SAMPLES; i++) { + // ADC 12bit 无符号 → 减去偏置 2048 转为有符号 + int16_t vsig = (int16_t)v_dut[i] - 2048; + + // 与查表 Q15 值相乘,64 位累加 + I_dut += ((int32_t)vsig * cos_table[i & 63]) >> 15; + Q_dut += ((int32_t)vsig * sin_table[i & 63]) >> 15; +} + +// 幅度用 |I| + |Q| 最大值近似(省掉 sqrt) +// 对 1% 精度 LCR,足够 +int32_t mag_approx = (abs(I_dut) > abs(Q_dut)) + ? abs(I_dut) + abs(Q_dut) / 4 + : abs(Q_dut) + abs(I_dut) / 4; +// 这给出了带 ±0.5% 误差的幅度估计 + +// 相位用查表法:theta = atan2(Q, I) +// 预存 256 点 arctan 表 +// 因为 I/Q 对称性,只需要存 0~45° +int16_t phase_lut[256]; +// 通过象限映射 + 查表得到相位 +``` + +### 4.2 阻抗计算 + +```c +// 从 DFT 结果计算阻抗 + +// 电流通道:V_I = -I_dut × R_ref +// 所以 I_dut = -V_I / R_ref +// 取模:|I_dut| = |V_I| / R_ref + +// DUT 复阻抗: +// Z_dut = V_dut / I_dut +// = -V_dut × R_ref / V_I +// 取模: +// |Z_dut| = |V_dut| × R_ref / |V_I| +// +// 相位: +// θ_z = phase(V_dut) - phase(V_I) +// = -(phase_i - phase_dut) = -phase_diff + +float Z_mag = mag_dut * R_ref / mag_i; // |Z| (Ω) +float theta = -(*phase_diff); // ∠Z (rad) + +// 分解为电阻和电抗 +float R = Z_mag * cosf(theta); // 等效串联电阻 ESR (Ω) +float X = Z_mag * sinf(theta); // 电抗 (Ω) + +// 识别元件类型 +if (fabsf(X) < fabsf(R) * 0.01f) { + // 纯电阻 + R_display = R; + type = TYPE_RESISTOR; + +} else if (X > 0) { + // 感性:L = X / (2πf) + float L = X / (2.0f * PI * F_SIG); + L_display = L; // 电感值 (H) + Q_display = fabsf(X) / R; // 品质因数 Q + type = TYPE_INDUCTOR; + +} else { + // 容性:C = -1 / (2πf × X) + float C = -1.0f / (2.0f * PI * F_SIG * X); + C_display = C; // 电容值 (F) + D_display = R / fabsf(X); // 损耗因数 D + type = TYPE_CAPACITOR; +} +``` + +### 4.3 多频点策略 + +LCR-ST1 在三个频点之间循环测量: + +``` +100Hz:适合大电容(>1μF)、大电感(>1H) +1kHz:通用频点 +10kHz:适合小电容(<1nF)、小电感(<10μH) +``` + +**频点切换实现:** + +```c +// 三个频点共用同一套 DFT 代码 +// 唯一区别:DAC 波形表更新速率和 ADC 采样率 + +typedef struct { + uint32_t freq; // 测试频率 (Hz) + uint32_t sample_rate; // ADC/DAC 采样率 (Hz) + uint32_t periods; // DFT 采集周期数 + uint32_t total_samples; // 总采样点数 = periods × 64 +} TestFrequency_t; + +TestFrequency_t freqs[] = { + { 100, 6400, 32, 2048}, // 100Hz → 6.4kHz 采样 → 2048 点 → 320ms + { 1000, 64000, 64, 4096}, // 1kHz → 64kHz 采样 → 4096 点 → 64ms + {10000, 640000, 128, 8192}, // 10kHz → 640kHz → 8192 点 → 12.8ms +}; + +// 注意:10kHz 需要 ADC 采样率 640kHz! +// GD32F103 ADC 最大 1Msps → 640kHz 可行 +// 但 DAC 更新频率同样 640kHz → 每个点 ~1.56μs,DMA 驱动 +``` + +### 4.4 自动量程切换(软件实现) + +```c +// 量程电阻表(与 4051 通道对应) +// 选择原则:使 V_dut 接近 ADC 满量程的 30%~80% +// 电压信号过小 → SNR 差 → 精度下降 +// 电压信号过大 → 超出 ADC 范围 → 削波失真 + +const float R_range[] = { + 10.0f, // Ch0: 低阻测量 + 100.0f, // Ch1 + 1000.0f, // Ch2 + 10000.0f, // Ch3 + 100000.0f, // Ch4 + 1000000.0f, // Ch5 + 10000000.0f,// Ch6: 超高阻 + 0.0f // Ch7: 空(校准位) +}; + +uint8_t current_range = 4; // 从 100kΩ 开始 + +uint8_t AutoRange(uint16_t *v_dut, uint16_t *v_i) { + // 计算 V_dut 峰值 + uint16_t v_max = 0, v_min = 4095; + for (int i = 0; i < 64; i++) { // 一个周期的快速检测 + if (v_dut[i] > v_max) v_max = v_dut[i]; + if (v_dut[i] < v_min) v_min = v_dut[i]; + } + uint16_t v_pp = v_max - v_min; + + // 判断是否在最佳区间(ADC 满量程的 20%~80%) + // 12bit ADC → 满量程 4096 → 20%=819, 80%=3277 + if (v_pp < 819 && current_range < 6) { + current_range++; // 增大 R_ref → 电流更小 → V_dut 变大 + return RANGE_CHANGED; + } else if (v_pp > 3277 && current_range > 0) { + current_range--; // 减小 R_ref → 电流更大 → V_dut 变小 + return RANGE_CHANGED; + } + return RANGE_OK; +} +``` + +### 4.5 校准与补偿 + +#### 开路校准(Open Cal) + +``` +不连接 DUT,镊子悬空 → 测量系统偏移量 + Z_open = 非常大 → 近似为 0 电流 + 记录 V_dut_open(运放的失调电压 + 串扰) + 记录相位偏移 + +存储到 EEPROM: + V_dut_offset[频点][量程] + phase_offset[频点][量程] +``` + +#### 短路校准(Short Cal) + +``` +短路镊子 → 测量系统零位阻抗 + 记录 Z_short(导线电阻 + 接触电阻) + +存储到 EEPROM: + R_short[量程] + L_short[量程](引线电感) +``` + +#### 实时校正公式 + +```c +// 每次测量后做校正 + +// Step 1: 减去开路偏移 +V_dut_corrected = V_dut_raw - V_dut_offset[freq][range]; +V_I_corrected = V_I_raw - V_I_offset[freq][range]; + +// Step 2: 减去短路残留 +if (type == TYPE_RESISTOR || type == TYPE_INDUCTOR) { + R_meas = R_meas - R_short[range]; +} + +if (type == TYPE_INDUCTOR) { + L_meas = L_meas - L_short[range]; +} + +// Step 3: 相位校正 +phase_corrected = phase_raw - phase_offset[freq][range]; +``` + +### 4.6 OLED 显示与 UI 逻辑 + +```c +// 显示刷新率:~4Hz(250ms 一次) + +typedef struct { + float value; // 测量值 + uint8_t type; // 元件类型 + float secondary; // 第二参数(Q/D/ESR) + float frequency; // 当前频率 + uint8_t range_idx; // 当前量程 + uint8_t stable; // 读数稳定标志 + uint32_t auto_off_timer;// 自动关机计时 +} DisplayData_t; + +void Display_Update(DisplayData_t *d) { + OLED_Clear(); + + // 主数值(大字体,2 行高度) + char main_val[16]; + FormatValue(d->value, main_val, + (d->type == TYPE_CAPACITOR) ? "F" : + (d->type == TYPE_INDUCTOR) ? "H" : "Ω"); + OLED_PrintBig(0, 0, main_val); + + // 第二参数 + char sec_val[16]; + if (d->type == TYPE_RESISTOR) { + // 电阻模式不显示第二参数 + } else if (d->type == TYPE_INDUCTOR) { + sprintf(sec_val, "Q=%.2f", d->secondary); + } else if (d->type == TYPE_CAPACITOR) { + sprintf(sec_val, "D=%.2f", d->secondary); + } + OLED_PrintSmall(0, 32, sec_val); + + // 频率 + 量程指示 + char info[16]; + sprintf(info, "%dHz", (int)d->frequency); + OLED_PrintSmall(80, 48, info); + + OLED_Display(); +} + +// 数值格式化(自动单位前缀) +void FormatValue(float val, char *out, char *unit) { + char prefix = ' '; + float disp = val; + + if (val >= 1e6f) { disp = val/1e6f; prefix = 'M'; } + else if (val >= 1e3f) { disp = val/1e3f; prefix = 'k'; } + else if (val >= 1.0f) { /* 无前缀 */ } + else if (val >= 1e-3f) { disp = val*1e3f; prefix = 'm'; } + else if (val >= 1e-6f) { disp = val*1e6f; prefix = 'μ'; } + else if (val >= 1e-9f) { disp = val*1e9f; prefix = 'n'; } + else { disp = val*1e12f; prefix = 'p'; } + + sprintf(out, "%.2f %c%s", disp, prefix, unit); +} + +// 自动关机(10 分钟无操作) +void AutoOff_Check(void) { + if (HAL_GetTick() - last_key_press > 600000) { // 10 分钟 + OLED_Clear(); + OLED_PrintCenter("OFF"); + OLED_Display(); + HAL_Delay(1000); + Enter_DeepSleep(); + } +} +``` + +--- + +## 五、整机软件流程图 + +``` + 上电 + │ + 初始化系统 + (RCC/GPIO/DAC/ADC/DMA/TIM/I2C/OLED) + │ + 显示 LOGO "FNIRSI" + 短蜂鸣器响应 + │ + 加载校准参数 + (EEPROM → 开路/短路数据) + │ + 镊子类型检测? + ┌──── 短路检测?→ 进入校准模式 ────┐ + │ (长按按键启动) │ + │ │ + ▼ │ + ┌─────────┐ │ + │ 主测量循环│ │ + └────┬────┘ │ + │ │ + ┌────┴────┐ │ + │ 自动量程 │ │ + │(4051切换)│ │ + └────┬────┘ │ + │ │ + ┌────┴────┐ │ + │ DAC 输出│ │ + │ 正弦激励 │ │ + └────┬────┘ │ + │ │ + ┌────┴────┐ │ + │ ADC采样 │ │ + │ V_dut+V_I│ │ + │ (DMA) │ │ + └────┬────┘ │ + │ │ + ┌────┴────┐ │ + │ DFT解调 │ │ + │ 幅度+相位 │ │ + └────┬────┘ │ + │ │ + ┌────┴────┐ │ + │ 阻抗计算 │ │ + │ R / L / C│ │ + └────┬────┘ │ + │ │ + ┌────┴────┐ │ + │ 校准补偿 │ │ + │ 开路/短路 │ │ + └────┬────┘ │ + │ │ + ┌────┴────┐ │ + │ OLED显示 │ │ + └────┬────┘ │ + │ │ + ┌────┴────┐ │ + │按键扫描 │──→ 功能切换/锁定 │ + │自动关机 │──→ 超时休眠 │ + └────┬────┘ │ + │ │ + ┌────┴────┐ │ + │频点切换 │──→ 100Hz/1kHz/10kHz │ + └────┬────┘ │ + │ │ + └──→ 循环 ────────────────────────┘ +``` + +--- + +## 六、与方案B(AD8333 路径)的对比 + +| 对比项 | LCR-ST1 (MCU+DAC+运放) | 我们设计的方案B (AD8333) | +|--------|----------------------|------------------------| +| 激励产生 | MCU DAC + 无源 LPF | DDS AD9834 + 有源 LPF + 变压器 | +| 解调方式 | MCU DFT 定点数 | AD8333 硬件 IQ 解调 | +| ADC 需求 | 12bit × 2ch @ 640kHz | 12bit × 2ch @ 1kHz | +| MCU 算力 | 无 FPU 定点数,50% 占满 | 有 FPU(STM32G4),<10% | +| 测量精度 | ~1%(典型) | ~0.1%(理论) | +| ΔR 分辨率 | ~1~2mΩ | ~0.1~0.3mΩ | +| 动态范围 | ~50~55dB | ~80dB | +| SNR(铝车架场景) | 不可用(<10dB) | 可用(>30dB) | +| 铝制车架检测 | ❌ 不适用 | ✅ 95~99% | + +**核心差异:** LCR-ST1 适用于**离线的、已知好坏的元器件**测量(有足够信号、无强干扰),而我们的方案B需要处理**在线、弱信号、强干扰**的实车检测——两者的 SNR 需求差了两个数量级。 + +具体来说,LCR-ST1 在测量一个 10μH 电感时,信号幅度可能有几百 mV,SNR > 40dB。而方案B在检测铝制车架的 0.3μH 变化时,信号幅度仅几个 mV,环境噪声(发动机、变频器、电源纹波)可达几十 mV——这就需要 AD8333 的差分架构和 80dB 动态范围来应对。 + +--- + +## 七、小结 + +### 7.1 LCR-ST1 的设计哲学 + +``` +¥138 造价 × 75% 毛利 × 30万/年销量 + → BOM ¥30×30万 = ¥900 万/年 + → 生产良率 98%+ + → 退换率 < 5% + +每个元器件选型的边际优化 ¥0.05 都值得做: + 用 1% 电阻而非 0.1% → 省 ¥0.3 + 用 GD32 而非 STM32 → 省 ¥3 + 用 LMV358 而非 OPA2188 → 省 ¥1.5 + 用 CR2032 而非锂电池+充电 → 省 ¥5 +``` + +### 7.2 对我们方案B的启示 + +``` +LCR-ST1 证明了 "MCU·DAC + 通用运放" 的 I-V 法可以做到 1% 精度。 + → 这意味着方案B的核心算法(DFT 解调)在原理上是成熟的。 + +但 LCR-ST1 做不到的事: + ① 无法检测百毫欧级的 ΔR(铝制车架需要 0.1mΩ 分辨率) + ② 无法在线抑制发动机/变频器/电源的共模噪声 + ③ 无法在 3V 单电池供电下驱动大动态范围前端 + +所以 LCR-ST1 是 "够用就好" 的消费级设计, +而我们的方案B是 "不惜成本保信号" 的工业级设计——两者定位完全不同。 +``` + +--- + +## 文档结束