1. 项目概述从零开始理解金属探测几年前我在整理老房子时总想找一种简单的方法来检查墙里有没有埋着旧水管或者地板下有没有掉落的钉子买专业设备不划算于是萌生了自己动手做一个的念头。用 Arduino 打造一个简易金属探测器听起来像是电子爱好者的入门项目但它背后涉及的原理和调试过程远比点亮一个LED灯复杂和有趣得多。这个项目的核心是利用一个电感线圈和 Arduino 的简单电路来感知周围金属物体引起的电磁场变化最终通过声音或灯光提示我们。它适合谁呢如果你是刚接触 Arduino 和电子制作的新手想找一个比“流水灯”更有挑战性、更能体现模拟电路与数字世界交互的项目那这个再合适不过了。对于有经验的爱好者你可以把它当作一个传感器融合和信号处理的小实验平台去优化探测灵敏度、区分金属类型甚至做成手持探宝仪的外形。整个项目成本极低核心元件就是一个线圈、几个电阻电容和一个运算放大器Arduino 负责“大脑”的工作处理信号并做出反应。简单来说我们要做的是一个基于“感应平衡”Induction Balance原理的探测器。线圈通上交变电流会产生一个交变磁场当金属物体进入这个磁场时会在金属内部产生涡流这个涡流又会产生一个反向磁场从而干扰原线圈的电磁特性。我们的电路就是捕捉这个微小的干扰并把它放大、转换成 Arduino 能读懂的信号。下面我就把从电路设计、线圈绕制、代码编写到调试优化的完整过程以及我踩过的那些坑详细地分享出来。2. 核心原理与电路设计拆解2.1 感应平衡原理与LC振荡电路金属探测器的灵魂在于其探测线圈。我们采用最常见的平行线圈或称双D线圈设计它由两个并排的、部分重叠的圆形或D形线圈组成。这两个线圈在电气上连接但物理上分开。在无金属状态下通过精细调节使两个线圈产生的磁场相互抵消达到一个“平衡”状态此时接收线圈的输出电压理论上为零。这个平衡的载体是一个LC振荡电路。L是线圈的电感C是我们并联在线圈上的电容。电感和电容共同决定了电路的谐振频率 f 1 / (2π√LC)。当有金属物体靠近时如果是铁磁性金属如铁、钢它会增强线圈的磁场相当于增大了电感L从而导致谐振频率降低。如果是非铁磁性但导电良好的金属如铜、铝其内部产生的涡流会抵消原磁场相当于减小了有效电感L从而导致谐振频率升高。我们的目标就是检测这个频率的微小偏移。然而直接让 Arduino 测量高频的LC振荡频率变化既复杂又不精准。更实用的方法是将这个LC振荡电路作为一个“探头”将其频率变化先转换成电压变化。这里就引入了“拍频”检测法。我们制作两个几乎完全相同的LC振荡器一个作为探测振荡器频率随金属靠近而变化另一个作为参考振荡器频率固定。将这两个高频信号混合会产生一个低频的“差频”信号。这个差频信号的频率正比于两个振荡器的频率差。当探测线圈频率因金属靠近而偏移时差频信号的频率就会发生明显变化。Arduino 测量这个低频差频信号的变化就容易多了。2.2 核心电路模块详解我们的电路主要由三大部分构成LC振荡器、混频器/检波器、以及信号放大与调理电路。整个系统的供电可以由 Arduino 的5V引脚提供但为了稳定性特别是给运算放大器供电建议使用独立的9V电池并通过7805等线性稳压芯片降压到5V。1. LC振荡器与线圈制作探测线圈需要自己绕制。我建议用直径0.3-0.5mm的漆包线在一个直径约15-20cm的圆形模板比如塑料餐盘上紧密绕制20-30圈。绕好后用胶带固定形状并引出两根线。线圈的电感量大约在几百微亨级别。你需要并联一个可变电容如5-60pF的可调电容和一个固定电容如1nF的CBB电容来组成谐振电容。通过调节可变电容可以将振荡频率设定在100-300kHz的范围内。参考振荡器使用另一个相同的线圈和电容组或者使用一个固定的电感与可调电容组成将其调节到与探测振荡器非常接近的频率。注意两个线圈在安装时必须保持物理隔离且相对位置固定避免相互干扰。探测线圈应安装在探盘的最外侧参考线圈则可以放在电路板附近并用屏蔽罩隔离。2. 混频与检波电路这里我们使用一个非常经典的芯片NE567 音调解码器或者用模拟乘法器原理。但为了更直观和易于理解我们可以采用二极管检波方案。将两个LC振荡器的输出信号通过电容耦合后分别输入到一个二极管如1N4148的阳极二极管的阴极连接在一起再通过一个电阻接地并从连接点取出信号。这个点得到的信号就包含了高频载波和低频差频分量。随后经过一个RC低通滤波器例如1kΩ电阻和0.1μF电容将高频成分滤除剩下的就是我们的差频信号。这个信号非常微弱可能只有几毫伏到几十毫伏。3. 放大与调理电路微弱的差频信号需要被放大到 Arduino 的模拟输入引脚可以清晰读取的范围0-5V。这里我们需要一个运算放大器。我强烈推荐使用 LM358 双运放因为它价格低廉、单电源供电正好用5V且完全满足需求。第一级运放接成同相放大器增益设置在100倍左右由反馈电阻决定例如 Rf100kΩ Rg1kΩ增益 Av 1 Rf/Rg 101。放大后的信号可能包含负电压部分而 Arduino 的 ADC 不能读取负电压。因此我们需要第二级运放构成一个电压跟随器并引入一个2.5V的偏置电压用两个10kΩ电阻对5V分压得到将信号整体抬升到以2.5V为中心。这样无金属时的静态输出就在2.5V左右当金属靠近引起频率变化时输出电压就会在2.5V上下波动。3. 元器件选型、清单与焊接要点3.1 详细物料清单与替代方案一张清晰的物料清单是成功的一半。以下是我多次制作后总结出的清单并附上了选型理由和可能的替代品。类别元器件名称规格/参数数量备注与选型理由核心控制Arduino Uno 或 Nano-1Uno更易接线Nano更小巧。本质都是ATmega328P。探测线圈漆包线直径0.3-0.5mm约5米直径越粗电阻越小Q值越高但越硬不易绕制。谐振电容可调电容5-60pF 或 10-100pF2用于精细调节两个振荡器的谐振频率至一致。CBB电容1nF (102)2与可调电容并联确定大致的频率范围。振荡与检波三极管2N3904 或 S80502用于构建简单的电容三点式振荡电路起振容易。电阻10kΩ, 100kΩ各2-4用于三极管偏置和负载。二极管1N41482用于检波开关速度快结电容小。信号放大运算放大器LM3581双运放单电源供电满足放大和电压跟随需求。电阻1kΩ, 10kΩ, 100kΩ若干用于运放增益设置和分压。精度最好为1%。电容0.1μF (104), 10μF 电解若干用于电源退耦和信号耦合。电源9V电池及扣-1为整个系统供电避免从Arduino取电引入噪声。稳压芯片78051将9V稳至5V需加散热片。其他蜂鸣器或有源喇叭5V1用于声音报警。LED任意颜色1-2用于视觉指示。洞洞板/PCB-1建议用洞洞板先实验稳定后可设计PCB。杜邦线、导线-若干用于连接。选型心得线圈漆包线我试过0.2mm的线虽然绕起来圈数可以更多电感量大但线太细电阻大Q值不高探测距离受影响。0.5mm的线性能好但绕制时线圈不易保持平整。0.3-0.4mm是平衡点。可调电容一定要选用陶瓷微调电容空气介质的当然更好但昂贵。它的稳定性直接决定了探测器的零点漂移。焊接后调节螺丝要用热熔胶固定防止震动导致参数变化。运算放大器LM358是性价比之王。如果你想追求更低的噪声和更好的性能可以升级为TL072双运放但需要双电源供电电路会复杂或 MCP602轨到轨运放单电源性能优异。但对于入门LM358完全足够。3.2 电路焊接与布局的避坑指南焊接不是简单的连接布局决定了成败。强烈建议先在面包板上搭建整个电路进行测试确认功能正常后再转移到洞洞板上焊接。1. 电源去耦是生命线模拟电路对电源噪声极其敏感。必须在7805稳压芯片的输入和输出端就近并联一个10-100μF的电解电容滤低频和一个0.1μF的瓷片电容滤高频。同样在运放LM358的电源引脚第8脚Vcc第4脚GND附近也要并联一个0.1μF的电容到地。这些电容能有效吸收电源线上的毛刺防止电路自激或输出不稳定。2. 地线布局的艺术模拟地AGND和数字地DGND最好分开走线。具体来说振荡器、检波电路、运放电路的地线走在一起最终汇聚到一点再连接到电源地。Arduino的地也接到这个点。千万不要形成“地线环路”即地线像网一样到处连接这很容易引入干扰。采用“星型接地”或单点接地是最稳妥的。3. 信号线的屏蔽与最短路径从探测线圈到电路板的引线是接收微弱信号的关键通道。这段线最好使用屏蔽线音频线即可屏蔽层单端接地接电路板端。信号线在板上的走线也要尽可能短远离电源线和数字信号线如通往蜂鸣器、LED的线。4. 线圈的固定与保护绕制好的线圈非常脆弱。你需要用胶带或热缩管将其紧密包裹固定然后可以将其粘贴在一个坚固的圆形基板如塑料板、亚克力板上。最后可以在线圈表面覆盖一层环氧树脂胶或绝缘清漆既能防潮又能防止线圈变形。探盘的柄可以用PVC水管制作将电路板和电池盒安装在手柄内。4. Arduino 程序编写与信号处理4.1 基础代码读取电压与阈值判断电路搭建好后运放的输出端连接至 Arduino 的某个模拟输入引脚例如 A0。我们的首要任务是读取这个电压值并判断其是否偏离了无金属时的基准值约2.5V。// 金属探测器基础检测代码 const int sensorPin A0; // 连接运放输出的引脚 const float baselineVoltage 2.5; // 无金属时的理论中心电压 const float threshold 0.3; // 探测阈值单位伏特。需根据实测调整 const int buzzerPin 8; // 蜂鸣器引脚 const int ledPin 13; // LED引脚 void setup() { Serial.begin(9600); // 初始化串口用于调试 pinMode(buzzerPin, OUTPUT); pinMode(ledPin, OUTPUT); // 初始状态关闭报警 digitalWrite(buzzerPin, LOW); digitalWrite(ledPin, LOW); } void loop() { // 1. 读取模拟值并转换为电压 int sensorValue analogRead(sensorPin); float voltage sensorValue * (5.0 / 1023.0); // 2. 计算与基准电压的差值绝对值 float deviation abs(voltage - baselineVoltage); // 3. 串口打印调试信息完成后可注释掉 Serial.print(Voltage: ); Serial.print(voltage); Serial.print(V, Deviation: ); Serial.print(deviation); Serial.println(V); // 4. 判断是否检测到金属 if (deviation threshold) { // 检测到金属触发报警 digitalWrite(ledPin, HIGH); tone(buzzerPin, 1000); // 发出1kHz声音 // 可以增加高级功能例如根据deviation大小改变音调 // int frequency 500 (deviation * 500); // 动态音调示例 // tone(buzzerPin, frequency); } else { // 未检测到金属关闭报警 digitalWrite(ledPin, LOW); noTone(buzzerPin); } delay(50); // 短暂延迟控制检测频率 }这段代码实现了最基本的功能。baselineVoltage和threshold是两个关键参数。上电后在无金属环境下你应该通过串口监视器观察voltage的实际值并用它来修正baselineVoltage。threshold则需要通过实验确定拿一个小金属物体慢慢靠近线圈观察deviation的变化取一个能稳定触发报警且不易受环境干扰的值。4.2 高级优化数字滤波与灵敏度提升直接读取单次电压值非常不稳定容易受随机噪声干扰导致误报。我们必须引入数字滤波。1. 移动平均滤波这是最简单有效的滤波方法。连续采样N次求其平均值作为本次的有效值。const int numReadings 10; // 采样次数 float readings[numReadings]; // 采样数组 int readIndex 0; // 当前索引 float total 0; // 总和 float average 0; // 平均值 void setup() { // ... 其他初始化 // 初始化数组为0 for (int i 0; i numReadings; i) { readings[i] 0; } } void loop() { // 减去最早的读数加上最新的读数 total total - readings[readIndex]; readings[readIndex] analogRead(sensorPin) * (5.0 / 1023.0); total total readings[readIndex]; readIndex (readIndex 1) % numReadings; // 循环索引 average total / numReadings; // 计算移动平均值 float deviation abs(average - baselineVoltage); // ... 后续判断逻辑 delay(10); // 采样间隔可以更短 }2. 自动基准校准环境温度变化、电池电压缓慢下降都会导致baselineVoltage漂移。我们可以让程序自动学习并更新这个基准值。思路是在长时间未检测到金属时比如连续若干秒deviation都很小缓慢地将当前average值向baselineVoltage靠拢。float baselineVoltage 2.5; // 初始值 const float learningRate 0.001; // 学习率越小则基准变化越慢 unsigned long lastMetalDetectTime 0; const unsigned long calibrationInterval 5000; // 5秒内无金属则开始校准 void loop() { // ... 计算 average 和 deviation ... if (deviation threshold) { // 检测到金属 lastMetalDetectTime millis(); // ... 触发报警 ... } else { // 未检测到金属 if (millis() - lastMetalDetectTime calibrationInterval) { // 超过校准间隔开始缓慢校准基准 baselineVoltage baselineVoltage (average - baselineVoltage) * learningRate; } // ... 关闭报警 ... } }3. 差分放大与软件增益如果硬件放大倍数有限我们还可以在软件里进一步提升灵敏度。不是直接判断deviation而是计算deviation的变化率微分或者与近期历史平均值的差异。当金属突然靠近时电压会有一个快速变化这个变化率可能比绝对差值更明显。5. 组装、调试与性能优化全流程5.1 分步组装与静态调试独立测试振荡器先不连接 Arduino只搭建两个LC振荡器用三极管和外围电路。用示波器或频率计探头如果没有可以用一个简单的收音机调到无台处靠近线圈听啸叫声来定性判断测量振荡器输出调节可调电容确保两个振荡器都能稳定起振且频率在可听范围外100kHz以上。记录下此时两个可调电容的大致位置。连接检波与放大电路将两个振荡器的输出接入检波电路再将检波输出接入运放放大电路。用万用表测量运放最终的输出端电压。在无金属时精细调节参考振荡器的可调电容使运放输出电压尽可能接近2.5V。这个过程需要耐心可能反复调节多次才能找到平衡点。接入 Arduino将运放输出接至 Arduino A0上传基础测试代码打开串口绘图器Serial Plotter。用手在线圈附近移动观察波形是否有毛刺。此时应该是一条相对平稳的直线。拿一个硬币慢慢靠近线圈观察电压曲线的变化。你应该能看到一个清晰的脉冲。确定阈值根据串口监视器读取的数值确定无金属时的电压波动范围比如2.48V-2.52V。将threshold设置为略大于这个波动范围的值比如0.05V。然后用小金属物体测试逐步调整threshold直到能稳定触发报警且不易误报。5.2 动态调试与灵敏度提升技巧问题探测距离太近只有1-2厘米。检查线圈Q值用万用表测量线圈的直流电阻电阻应尽可能小几欧姆以内。如果电阻过大说明线圈绕得不够紧或漆包线太细需要重绕。提高振荡电路的电源电压例如从5V提高到9V也能增强磁场但要注意三极管和运放的耐压。优化谐振电容尝试不同的并联固定电容值用频率计找到使振荡幅度最大的那个谐振点。振荡越强产生的磁场越强灵敏度越高。增加硬件放大倍数提高第一级运放的增益。将反馈电阻 Rf 增大如从100kΩ增至1MΩ但要注意增益过高会导致噪声也被放大电路可能不稳定。可以在反馈电阻上并联一个小电容如10pF来抑制高频噪声。问题不稳定容易误报数值跳动大。加强电源滤波检查所有电源去耦电容是否焊好特别是运放和振荡器部分的0.1μF电容必须紧贴芯片电源引脚。优化软件滤波增加移动平均的采样点数numReadings比如从10增加到30或50。但点数太多会导致响应变慢。可以尝试更复杂的滤波算法如中值滤波或卡尔曼滤波对于Arduino Uno来说稍重。检查接地与屏蔽确保信号屏蔽线的屏蔽层良好接地。尝试将整个电路板用金属盒如铝制饭盒屏蔽起来只引出必要的线。远离干扰源让探测器远离电脑显示器、手机、节能灯、变频家电等强电磁干扰源。问题无法区分金属类型。简易探测器很难精准区分但可以做粗略判断。铁磁性金属铁、钢通常会使频率降低在我们的电路里可能表现为电压向一个方向变化而非铁磁性导电金属铜、铝则使频率升高电压向反方向变化。你可以在代码中不取绝对值的deviation而是判断(voltage - baselineVoltage)的正负。为正时触发一种声光模式如长响为负时触发另一种如短促响。但这需要电路非常对称和稳定且金属物体要足够大、足够近。5.3 外观整合与最终测试当电路和代码都调试稳定后就可以进行最终组装了。将电路板、电池妥善地固定在PVC手柄内。探盘与手柄的连接要牢固线缆要留有余量并用扎带固定。可以在手柄上安装一个拨动开关控制总电源再安装一个按键用于模式切换如常开/常闭报警模式。最终测试时找一个干净的场地避免地下有钢筋用不同材质和大小的金属物体硬币、钥匙、铁片、铝罐进行探测记录最远探测距离。在室内不同位置走动测试其抗干扰能力。这样一个由你亲手打造的、功能完善的简易金属探测器就诞生了。它不仅是一个工具更是一个融合了模拟电路、数字采集和软件算法的综合实践项目其中的调试经验和解决问题的过程才是最宝贵的收获。