This ESP32-based metal detector uses electromagnetic induction to sense ferrous and conductive materials. The circuit generates a high-frequency pulse through a search coil, then measures the decay of the resulting magnetic field using an op-amp comparator and Schmitt-trigger logic. When metal enters the field, it dampens the decay, triggering an LED and piezo buzzer alarm.
This guide provides a complete wiring diagram, parts list, and step-by-step assembly instructions for building the detector on a breadboard. The included Arduino firmware handles coil driving, signal sampling, baseline calibration, and threshold detection. Builders will learn how inductive sensing works and gain a functional metal detector ready for field testing.
Wiring diagram

Gather all the parts
Assemble it in 8 steps
1. Alimenta la placa de pruebas
Con el ESP32 desconectado del USB, lleva 3V3 del ESP32 al carril rojo de la placa de pruebas y GND al carril azul. Todos los circuitos deben compartir ese mismo carril de tierra.
- Usa cables rojos para 3V3 y negros para GND para encontrar errores con facilidad.
- No conectes 5 V a los integrados ni a GPIO34: una señal de 5 V puede dañar el ESP32.
2. Coloca y alimenta los dos integrados
Pon el MCP602 y el 74HC14D atravesando la ranura central de la placa de pruebas. Conecta VDD del MCP602 y VCC del 74HC14D a 3V3 (alimentación), y VSS del MCP602 y GND del 74HC14D a GND (tierra). Coloca cap_mcp_1 y cap_hc14_1: cada condensador va entre 3V3 y GND, pegado a su integrado.
- El punto o muesca del encapsulado marca el extremo de la pata 1; consulta el dibujo de pines del fabricante antes de colocar cada chip.
- Una fila desplazada o alimentar el chip al revés puede calentarlo y dañarlo.
3. Termina las entradas que no se usan
En el MCP602, une OUTA con INA− y conecta OUTA a GPIO34 (señal). Une OUTB con INB− y conecta INB+ a GND para que el segundo amplificador no quede suelto. En el 74HC14D, conecta las entradas 2A, 3A, 4A, 5A y 6A a GND; deja sus salidas sin conectar.
- Una entrada suelta puede captar ruido y hacer que el montaje consuma de más o se comporte de forma errática.
4. Cablea la bobina y el transistor
Conecta coil_1 L1 a 3V3 (alimentación). Conecta coil_1 L2 al drenador D de mosfet_1 (señal). Conecta la fuente S del MOSFET a GND (tierra). Conecta diode_1 entre el mismo punto L2/D y 3V3: el extremo con raya, K, va a 3V3 (protección) y el otro extremo, A, va a L2/D (protección).
- Puedes hacer la bobina con unas 35 vueltas de hilo de cobre esmaltado de 0,4 a 0,6 mm sobre un aro no metálico de unos 10 cm. Raspa el esmalte de las dos puntas antes de insertarlas.
- No pongas la bobina sobre una mesa metálica ni uses un aro metálico: el propio soporte activará el detector.
5. Añade el control de la bobina
Conecta GPIO25 a 1A del hc14_1 (señal). Conecta 1Y del hc14_1 a un extremo de r_gate_1, y el otro extremo de r_gate_1 a G de mosfet_1 (señal). Conecta r_pulldown_1 entre G de mosfet_1 y GND (mantiene apagada la bobina durante el arranque).
- El MOSFET AO3400A en formato SOT-23 es muy pequeño; sigue su dibujo de patas del vendedor o usa un adaptador SOT-23 a placa de pruebas.
- Confundir las patas G, D y S del MOSFET puede dejar la bobina encendida y calentar el transistor.
6. Lleva la señal protegida al ESP32
Conecta r_div_top_1 entre el punto común coil_1 L2 / mosfet_1 D y el punto de lectura. Conecta r_div_bottom_1 entre ese punto de lectura y GND. Conecta el punto de lectura a INA+ del mcp602_1; la salida OUTA del MCP602 ya va a GPIO34 (señal).
- Mantén estos cables cortos y separados del cable de GPIO25 para que la lectura tenga menos ruido.
- No conectes el punto de la bobina directamente a GPIO34: los picos de la bobina podrían dañar la entrada del ESP32.
7. Conecta la luz y el zumbador
Conecta GPIO26 a un extremo de r_led_1 y el otro extremo a la pata larga A de led_1 (luz). Conecta la pata corta K del LED a GND (tierra). Conecta el terminal + de piezo_1 a GPIO27 (sonido) y el terminal − a GND (tierra).
- Si el LED no enciende, gira solo el LED; su lado plano y pata corta van a GND.
- No quites r_led_1: sin esa resistencia el LED puede dañarse.
8. Enciende y calibra lejos del metal
Revisa que no haya hilos sueltos, conecta el ESP32 por USB y mantén la bobina lejos de monedas, herramientas, la mesa metálica y tus manos durante unos tres segundos al encender. Después acerca una moneda a la bobina para comprobar que se enciende la luz y suena el zumbador.
- Si detecta siempre o no detecta nada, mueve el valor DETECT_THRESHOLD en el programa: bájalo para más sensibilidad o súbelo para ignorar ruido.
Review all connections
1. Connections between "mcp602_1" and "ESP32"
2. Connections between "hc14_1" and "ESP32"
3. Connections between "coil_1" and "ESP32"
4. Connections between "mosfet_1" and "ESP32"
5. Connections between "diode_1" and "ESP32"
6. Connections between "r_gate_1" and "ESP32"
7. Connections between "r_pulldown_1" and "ESP32"
8. Connections between "r_div_top_1" and "ESP32"
9. Connections between "r_div_bottom_1" and "ESP32"
10. Connections between "cap_mcp_1" and "ESP32"
11. Connections between "cap_hc14_1" and "ESP32"
12. Connections between "led_1" and "ESP32"
13. Connections between "r_led_1" and "ESP32"
14. Connections between "piezo_1" and "ESP32"
Deploy the firmware
#include <Arduino.h>
// Forward declarations
int takeCoilReading();
void setAlarm(bool on);
constexpr int COIL_DRIVE_PIN = 25;
constexpr int LED_PIN = 26;
constexpr int BUZZER_PIN = 27;
constexpr int SENSE_PIN = 34;
constexpr uint32_t PULSE_ON_US = 260;
constexpr uint32_t SETTLE_US = 12;
constexpr uint32_t SAMPLE_INTERVAL_MS = 20;
constexpr int CALIBRATION_SAMPLES = 180;
constexpr float DETECT_THRESHOLD = 35.0f;
float baseline = 0.0f;
float filteredReading = 0.0f;
bool metalPresent = false;
uint32_t lastSampleMs = 0;
int takeCoilReading() {
// The 74HC14 inverts this signal: LOW turns the MOSFET on, HIGH releases it.
digitalWrite(COIL_DRIVE_PIN, LOW);
delayMicroseconds(PULSE_ON_US);
digitalWrite(COIL_DRIVE_PIN, HIGH);
delayMicroseconds(SETTLE_US);
long total = 0;
for (int i = 0; i < 4; ++i) {
total += analogRead(SENSE_PIN);
}
return total / 4;
}
void setAlarm(bool on) {
digitalWrite(LED_PIN, on ? HIGH : LOW);
if (on) {
ledcWriteTone(BUZZER_PIN, 1800);
} else {
ledcWriteTone(BUZZER_PIN, 0);
}
}
void setup() {
Serial.begin(115200);
pinMode(COIL_DRIVE_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
analogReadResolution(12);
analogSetPinAttenuation(SENSE_PIN, ADC_11db);
// Keep the coil unpowered while the ESP32 starts.
digitalWrite(COIL_DRIVE_PIN, HIGH);
setAlarm(false);
delay(300);
long total = 0;
for (int i = 0; i < CALIBRATION_SAMPLES; ++i) {
total += takeCoilReading();
delay(10);
}
baseline = total / (float)CALIBRATION_SAMPLES;
filteredReading = baseline;
Serial.printf("Referencia inicial: %.1f\n", baseline);
}
void loop() {
const uint32_t now = millis();
if (now - lastSampleMs < SAMPLE_INTERVAL_MS) {
return;
}
lastSampleMs = now;
const int raw = takeCoilReading();
filteredReading = filteredReading * 0.78f + raw * 0.22f;
const float change = fabsf(filteredReading - baseline);
metalPresent = change > DETECT_THRESHOLD;
setAlarm(metalPresent);
// Slowly follow temperature and supply changes only when no metal is detected.
if (!metalPresent) {
baseline = baseline * 0.998f + filteredReading * 0.002f;
}
Serial.printf("lectura=%d referencia=%.1f cambio=%.1f %s\n",
raw, baseline, change, metalPresent ? "METAL" : "libre");
}Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace, diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.




