Objetivo y caso de uso
Qué construirás: Un prototipo funcional de un panel de acceso seguro utilizando la detección táctil capacitiva integrada del ESP32, indicadores visuales LED y retroalimentación acústica por zumbador.
Por qué es importante / Casos de uso
- Interfaces sin desgaste: Elimina la degradación mecánica, haciéndolo ideal para paneles de acceso de alto tráfico, salas blancas o teclados de exteriores expuestos a los elementos.
- Automatización segura de edificios: Demuestra la lógica fundamental de validación de secuencias y gestión de estados requerida en los sistemas de seguridad comercial de primera línea.
- Retroalimentación de usuario integrada: Combina señales visuales (LED) y acústicas (zumbador) para una HMI robusta, garantizando que los usuarios sepan que la entrada fue registrada con una latencia de respuesta inferior a 50 ms.
- Máquinas de estado no bloqueantes: Gestiona la entrada humana asíncrona sin detener el microcontrolador, manteniendo una capacidad de respuesta constante del sistema.
Resultado esperado
- Detección táctil confiable y eliminación de rebotes (debouncing) por software utilizando el hardware capacitivo interno del ESP32.
- Una máquina de estados no bloqueante capaz de procesar entradas secuenciales y rechazar códigos inválidos al instante.
- Actuación GPIO sincronizada y de baja latencia para controlar la retroalimentación del LED y el zumbador en función del estado de acceso.
Audiencia: Ingenieros de sistemas embebidos, desarrolladores de IoT; Nivel: Intermedio
Arquitectura/flujo: Pines táctiles capacitivos del ESP32 → Filtro de eliminación de rebotes por software → Validador de secuencias no bloqueante → Actuación GPIO (LED/Zumbador)
Nota educativa de validación
Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. Para este perfil ESP32 DevKitC, el proyecto se comprobó como proyecto PlatformIO: el validador extrajo platformio.ini y src/main.cpp, creó un proyecto temporal y ejecutó pio run contra platform = espressif32, board = esp32dev y framework = arduino. También revisó la estructura del artículo, que los comandos sean copiables con guiones ASCII, y que no aparezcan stacks no soportados como ESP-IDF directo o placas ESP32 no acotadas.
Evidencia de validación publicada
- Resultado automático: PASS.
- Estructura parseada: 3 apartados, 2 tablas y 2 bloques de código detectados antes de publicar.
- Código comprobado: 1 PlatformIO config + 1 ESP32 source/pio run.
- Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo y los stacks no soportados bloquean la publicación.
- Hallazgos del informe: sin hallazgos bloqueantes.
Esta validación confirma compatibilidad sintáctica y de herramientas para el código publicado, pero no sustituye la prueba física sobre tu placa ESP32 DevKitC exacta, tu cableado, alimentación y entorno WiFi local.
Nota educativa de seguridad
Este proyecto es un prototipo educativo, no un producto certificado. Antes de encender la configuración, verifique la asignación de pines de su revisión exacta de la placa ULX3S, mantenga las señales de E/S de la FPGA a 3.3 V, nunca conecte 5 V directamente a los pines de E/S, desconecte la alimentación antes de cambiar el cableado y use fuentes externas adecuadas para cargas, motores o servos mientras comparte la tierra solo cuando el cableado lo requiera.
Diagrama de bloques conceptual
Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.
Arquitectura funcional
Flujo conceptual de señales y responsabilidades entre bloques del dispositivo.
Ruta de validación
Resumen conceptual de las herramientas usadas para comprobar el material publicado.
Requisitos previos
Para completar este tutorial con éxito, necesitará:
* Comprensión básica de la programación en C++ (variables, arreglos, lógica condicional y funciones).
* Visual Studio Code instalado con la extensión PlatformIO IDE.
* Familiaridad con la creación de prototipos en protoboard y componentes electrónicos básicos.
* Un cable micro-USB o USB-C (dependiendo de su variante específica de ESP32 DevKitC) capaz de transferir tanto energía como datos.
Materiales
Debe utilizar los componentes exactos enumerados a continuación para garantizar que el código y las instrucciones de cableado proporcionados funcionen sin modificaciones:
* Microcontrolador: ESP32 DevKitC (versión estándar de 38 o 30 pines).
* Entrada: Almohadillas táctiles capacitivas. (Puede usar módulos de almohadillas táctiles comerciales dedicados, o crear fácilmente los suyos propios usando cinta de cobre, papel de aluminio o monedas metálicas soldadas a cables puente).
* Salida (Visual): 1x LED de estado estándar de 5 mm (por ejemplo, rojo o verde) y 1x resistencia limitadora de corriente de 220Ω a 330Ω.
* Salida (Audio): 1x Zumbador piezoeléctrico (se prefiere el tipo pasivo para tonos variables, aunque un zumbador activo funcionará para pitidos simples).
* Prototipado: 1x Protoboard sin soldadura y un surtido de cables puente macho-macho.
Nota de configuración de hardware: Asegúrese de que su computadora tenga instalados los controladores de puente USB a UART adecuados (generalmente CP210x o CH34x, dependiendo del fabricante de su ESP32 DevKitC) para que PlatformIO pueda comunicarse con la placa.
Configuración/Conexión
El ESP32 cuenta con hardware de detección táctil interno dedicado en varios pines GPIO. Estos pines miden la capacitancia del circuito conectado. Cuando un dedo humano toca la almohadilla, la capacitancia cambia, lo que el ESP32 detecta como una caída en el valor analógico sin procesar.
Debido a que el ESP32 maneja la medición de capacitancia internamente, no necesita resistencias pull-up o pull-down externas para las almohadillas táctiles. Conecte los componentes de acuerdo con la siguiente tabla.
Tabla de asignación de pines
| Componente | Pin ESP32 DevKitC | Detalles y Conexiones |
|---|---|---|
| Almohadilla táctil 1 (Tecla 1) | GPIO 4 (Touch 0) | Conectar directamente a la almohadilla metálica/moneda. |
| Almohadilla táctil 2 (Tecla 2) | GPIO 2 (Touch 2) | Conectar directamente a la almohadilla metálica/moneda. |
| Almohadilla táctil 3 (Tecla 3) | GPIO 15 (Touch 3) | Conectar directamente a la almohadilla metálica/moneda. |
| Ánodo del LED de estado (+) | GPIO 21 | Conectar a través de una resistencia de 220Ω al GPIO 21. |
| Cátodo del LED de estado (-) | GND | Conectar directamente al pin de Tierra (GND) del ESP32. |
| Zumbador piezoeléctrico (+) | GPIO 22 | Conectar al GPIO 22. |
| Zumbador piezoeléctrico (-) | GND | Conectar al pin de Tierra (GND) del ESP32. |
Construcción de las almohadillas táctiles: Si no tiene almohadillas táctiles comerciales, corte tres cuadrados idénticos de cinta de cobre o use tres monedas idénticas. Suelde o pegue firmemente con cinta un cable puente a cada una. Sepárelas al menos 2 centímetros en su escritorio o protoboard para evitar la capacitancia cruzada (donde tocar una almohadilla activa accidentalmente una adyacente).
Código validado
Los siguientes archivos constituyen el proyecto completo y compilable. El proyecto se gestiona a través de PlatformIO.
platformio.ini
Cree o sobrescriba el archivo platformio.ini en la raíz de su directorio de proyecto con la siguiente configuración. Esto asegura que se apunte a la placa y el framework correctos.
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
src/main.cpp
Cree o sobrescriba el archivo main.cpp en su directorio src con el siguiente código. La lógica implementa una máquina de estados no bloqueante, maneja la eliminación de rebotes táctiles y gestiona la secuencia de validación de acceso.
Vista pública parcial del archivo validado. El código completo se muestra a miembros y en PDF/Print.
#include <Arduino.h>
// --------------------------------------------------------
// Pin Definitions
// --------------------------------------------------------
const int TOUCH_PAD_1 = 4; // GPIO 4 (Touch 0)
const int TOUCH_PAD_2 = 2; // GPIO 2 (Touch 2)
const int TOUCH_PAD_3 = 15; // GPIO 15 (Touch 3)
const int LED_PIN = 21; // Status LED
const int BUZZER_PIN = 22; // Piezo Buzzer
// --------------------------------------------------------
// System Configuration & Thresholds
// --------------------------------------------------------
// A typical untouched ESP32 pin reads ~50-80.
// A touched pin drops below 20. Adjust this if your pads differ.
const int TOUCH_THRESHOLD = 30;
// Access Control Sequence Configuration
const int SEQUENCE_LENGTH = 4;
const int SECRET_PIN[SEQUENCE_LENGTH] = {1, 2, 3, 2}; // The correct access code
int inputSequence[SEQUENCE_LENGTH];
int inputIndex = 0;
// State Machine Variables
enum SystemState { LOCKED, INPUTTING, UNLOCKED };
SystemState currentState = LOCKED;
unsigned long unlockTimestamp = 0;
const unsigned long UNLOCK_DURATION = 5000; // Keep unlocked for 5 seconds
// Debouncing Variables
bool pad1_wasTouched = false;
bool pad2_wasTouched = false;
bool pad3_wasTouched = false;
// --------------------------------------------------------
// Function Prototypes
// --------------------------------------------------------
void processTouch();
void handleKeyPress(int keyNumber);
void evaluateSequence();
void triggerSuccess();
void triggerFailure();
void lockSystem();
void playTone(int frequency, int duration);
// --------------------------------------------------------
// Setup
// --------------------------------------------------------
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); } // Wait for serial connection
Serial.println("\n--- Capacitive Touch Access Panel Initialized ---");
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
lockSystem(); // Ensure system starts in locked state
}
// --------------------------------------------------------
// Main Loop
// --------------------------------------------------------
void loop() {
// Handle state timeouts (Auto-lock)
if (currentState == UNLOCKED) {
if (millis() - unlockTimestamp >= UNLOCK_DURATION) {
Serial.println("Auto-locking system due to timeout.");
lockSystem();
}
} else {
// Only process touch inputs if the system is not currently unlocked
processTouch();
}
// Small delay to yield to the underlying RTOS
delay(10);
}
// --------------------------------------------------------
// Touch Processing & Debouncing
// --------------------------------------------------------
void processTouch() {
// Read raw capacitance values
int val1 = touchRead(TOUCH_PAD_1);
int val2 = touchRead(TOUCH_PAD_2);
int val3 = touchRead(TOUCH_PAD_3);
// Evaluate Pad 1
bool pad1_isTouched = (val1 < TOUCH_THRESHOLD);
if (pad1_isTouched && !pad1_wasTouched) {
handleKeyPress(1);
}
pad1_wasTouched = pad1_isTouched;
// Evaluate Pad 2
bool pad2_isTouched = (val2 < TOUCH_THRESHOLD);
if (pad2_isTouched && !pad2_wasTouched) {
handleKeyPress(2);
}
// ... continúa para miembros en el código completo validado ...
#include <Arduino.h>
// --------------------------------------------------------
// Pin Definitions
// --------------------------------------------------------
const int TOUCH_PAD_1 = 4; // GPIO 4 (Touch 0)
const int TOUCH_PAD_2 = 2; // GPIO 2 (Touch 2)
const int TOUCH_PAD_3 = 15; // GPIO 15 (Touch 3)
const int LED_PIN = 21; // Status LED
const int BUZZER_PIN = 22; // Piezo Buzzer
// --------------------------------------------------------
// System Configuration & Thresholds
// --------------------------------------------------------
// A typical untouched ESP32 pin reads ~50-80.
// A touched pin drops below 20. Adjust this if your pads differ.
const int TOUCH_THRESHOLD = 30;
// Access Control Sequence Configuration
const int SEQUENCE_LENGTH = 4;
const int SECRET_PIN[SEQUENCE_LENGTH] = {1, 2, 3, 2}; // The correct access code
int inputSequence[SEQUENCE_LENGTH];
int inputIndex = 0;
// State Machine Variables
enum SystemState { LOCKED, INPUTTING, UNLOCKED };
SystemState currentState = LOCKED;
unsigned long unlockTimestamp = 0;
const unsigned long UNLOCK_DURATION = 5000; // Keep unlocked for 5 seconds
// Debouncing Variables
bool pad1_wasTouched = false;
bool pad2_wasTouched = false;
bool pad3_wasTouched = false;
// --------------------------------------------------------
// Function Prototypes
// --------------------------------------------------------
void processTouch();
void handleKeyPress(int keyNumber);
void evaluateSequence();
void triggerSuccess();
void triggerFailure();
void lockSystem();
void playTone(int frequency, int duration);
// --------------------------------------------------------
// Setup
// --------------------------------------------------------
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); } // Wait for serial connection
Serial.println("\n--- Capacitive Touch Access Panel Initialized ---");
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
lockSystem(); // Ensure system starts in locked state
}
// --------------------------------------------------------
// Main Loop
// --------------------------------------------------------
void loop() {
// Handle state timeouts (Auto-lock)
if (currentState == UNLOCKED) {
if (millis() - unlockTimestamp >= UNLOCK_DURATION) {
Serial.println("Auto-locking system due to timeout.");
lockSystem();
}
} else {
// Only process touch inputs if the system is not currently unlocked
processTouch();
}
// Small delay to yield to the underlying RTOS
delay(10);
}
// --------------------------------------------------------
// Touch Processing & Debouncing
// --------------------------------------------------------
void processTouch() {
// Read raw capacitance values
int val1 = touchRead(TOUCH_PAD_1);
int val2 = touchRead(TOUCH_PAD_2);
int val3 = touchRead(TOUCH_PAD_3);
// Evaluate Pad 1
bool pad1_isTouched = (val1 < TOUCH_THRESHOLD);
if (pad1_isTouched && !pad1_wasTouched) {
handleKeyPress(1);
}
pad1_wasTouched = pad1_isTouched;
// Evaluate Pad 2
bool pad2_isTouched = (val2 < TOUCH_THRESHOLD);
if (pad2_isTouched && !pad2_wasTouched) {
handleKeyPress(2);
}
pad2_wasTouched = pad2_isTouched;
// Evaluate Pad 3
bool pad3_isTouched = (val3 < TOUCH_THRESHOLD);
if (pad3_isTouched && !pad3_wasTouched) {
handleKeyPress(3);
}
pad3_wasTouched = pad3_isTouched;
}
// --------------------------------------------------------
// Logic Handling
// --------------------------------------------------------
void handleKeyPress(int keyNumber) {
// Provide immediate acoustic feedback
playTone(1000, 100);
Serial.print("Key Pressed: ");
Serial.println(keyNumber);
// Update state
currentState = INPUTTING;
// Store the input
inputSequence[inputIndex] = keyNumber;
inputIndex++;
// Check if we have collected enough inputs
if (inputIndex >= SEQUENCE_LENGTH) {
evaluateSequence();
}
}
void evaluateSequence() {
Serial.println("Evaluating entered sequence...");
bool isMatch = true;
for (int i = 0; i < SEQUENCE_LENGTH; i++) {
if (inputSequence[i] != SECRET_PIN[i]) {
isMatch = false;
break;
}
}
if (isMatch) {
triggerSuccess();
} else {
triggerFailure();
}
// Reset input index for the next attempt
inputIndex = 0;
}
// --------------------------------------------------------
// Output & Feedback Generators
// --------------------------------------------------------
void triggerSuccess() {
Serial.println("ACCESS GRANTED.");
currentState = UNLOCKED;
unlockTimestamp = millis();
// Visual indicator: LED ON
digitalWrite(LED_PIN, HIGH);
// Acoustic indicator: Success Melody
playTone(1200, 150);
delay(50);
playTone(1500, 150);
delay(50);
playTone(2000, 300);
}
void triggerFailure() {
Serial.println("ACCESS DENIED. Incorrect PIN.");
// Acoustic indicator: Error Tone
playTone(300, 400);
delay(100);
playTone(300, 400);
// Return to locked state immediately
lockSystem();
}
void lockSystem() {
currentState = LOCKED;
inputIndex = 0; // Clear any partial inputs
digitalWrite(LED_PIN, LOW); // LED OFF indicates locked
Serial.println("System LOCKED. Ready for input.");
}
// Helper function for the buzzer
void playTone(int frequency, int duration) {
tone(BUZZER_PIN, frequency, duration);
// The tone function in Arduino is non-blocking, but for this HMI
// we want the beep to complete before proceeding in feedback sequences.
delay(duration);
}
Comandos de compilación/flasheo/ejecución
Para compilar, cargar y monitorear el proyecto, abra la terminal en Visual Studio Code (Terminal -> Nueva terminal) y asegúrese de estar en el directorio raíz de su proyecto (donde se encuentra platformio.ini).
Use los siguientes comandos:
| Comando | Acción |
|---|---|
pio run |
Compila el código fuente en C++ y verifica si hay errores de sintaxis/enlace. |
pio run --target upload |
Compila y flashea el firmware compilado en el ESP32 DevKitC. |
pio device monitor |
Abre el monitor serie para ver los registros en tiempo real del ESP32. |
Flujo de trabajo numerado:
1. Conecte el ESP32 DevKitC a su computadora a través de USB.
2. Ejecute pio run para verificar que el código se compila limpiamente.
3. Ejecute pio run --target upload para flashear la placa. (Nota: En algunos modelos de ESP32 DevKitC, es posible que deba mantener presionado el botón «BOOT» en la placa cuando la terminal muestre «Connecting…» para permitir que comience el proceso de flasheo).
4. Ejecute pio device monitor para interactuar con el dispositivo y ver la salida serie.
Validación paso a paso
Realice las siguientes comprobaciones físicas mientras observa el monitor serie para validar la funcionalidad del prototipo.
- Punto de control 1: Inicialización base
- Acción: Reinicie el ESP32 (presione el botón EN) mientras observa el monitor serie.
- Observación esperada: El monitor serie imprime «— Capacitive Touch Access Panel Initialized —» seguido de «System LOCKED. Ready for input.». El LED de estado debe permanecer apagado.
- Condición de aprobación: Secuencia de arranque limpia sin bucles de reinicio ni bloqueos.
- Punto de control 2: Detección de un solo toque y eliminación de rebotes
- Acción: Toque firmemente la Almohadilla táctil 1 una vez y suéltela inmediatamente.
- Observación esperada: El zumbador emite un pitido corto de 100 ms. El monitor serie registra «Key Pressed: 1».
- Condición de aprobación: Solo se registra una pulsación por toque físico. Si se registran múltiples pulsaciones, es posible que el
TOUCH_THRESHOLDnecesite ajuste.
- Punto de control 3: Rechazo de secuencia incorrecta
- Acción: Toque las almohadillas en una secuencia incorrecta (por ejemplo, Almohadilla 1, Almohadilla 1, Almohadilla 1, Almohadilla 1).
- Observación esperada: En el cuarto toque, el monitor serie registra «Evaluating entered sequence…» seguido de «ACCESS DENIED. Incorrect PIN.». El zumbador reproduce dos tonos de error bajos y largos. El LED permanece apagado.
- Condición de aprobación: El sistema identifica correctamente una discrepancia y vuelve al estado «System LOCKED».
- Punto de control 4: Autorización de secuencia correcta
- Acción: Toque las almohadillas en la secuencia correcta definida en el código (Almohadilla 1, Almohadilla 2, Almohadilla 3, Almohadilla 2).
- Observación esperada: El monitor serie registra «ACCESS GR
Encuentra este producto y/o libros sobre este tema en Amazon
Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.







