Files
xdeSpace/docs/FNIRSI_LCR-ST1_逆向分析.md

30 KiB
Raw Permalink Blame History

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μH10H, C: 0.1pF10mF, 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 核心芯片选型

MCUGD32F103C8T6 或 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 单电源)
  增益带宽积 1MHz1kHz/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(一阶)
    再加一级 RCR=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%)、人工,净利润约 3540%。

作为对比,如果换用 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 计算

// ============================================================
// 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.3V4096 码值
    
    *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)。实际产品必须用定点数:

// 定点数 DFTQ15 格式)
// 用 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 阻抗计算

// 从 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

频点切换实现:

// 三个频点共用同一套 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μsDMA 驱动

4.4 自动量程切换(软件实现)

// 量程电阻表(与 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[量程](引线电感)

实时校正公式

// 每次测量后做校正

// 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 逻辑

// 显示刷新率:~4Hz250ms 一次)

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% 占满 有 FPUSTM32G4),<10%
测量精度 ~1%(典型) ~0.1%(理论)
ΔR 分辨率 12mΩ 0.10.3mΩ
动态范围 5055dB ~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是 "不惜成本保信号" 的工业级设计——两者定位完全不同。

文档结束