docs: 将散落的技术文档统一迁移至docs/集中管理
This commit is contained in:
@@ -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是 "不惜成本保信号" 的工业级设计——两者定位完全不同。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文档结束
|
||||
Reference in New Issue
Block a user