30 KiB
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 |
可信 |
| 精度 | 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。最可能的做法是:
- 无源 RC LPF:两级 RC 做正弦波滤波(DAC → RC → RC → 4051)
- 或者直接用 PWM + 有源 LPF:省掉 DAC,用 MCU 的定时器 PWM 输出,经二阶有源 LPF 得到正弦波——需要一个额外运放
- 或者 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.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)。实际产品必须用定点数:
// 定点数 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 阻抗计算
// 从 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μs,DMA 驱动
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 逻辑
// 显示刷新率:~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 分辨率 | ||
| 动态范围 | ~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是 "不惜成本保信号" 的工业级设计——两者定位完全不同。