Concepto de Resistencias Pull-up y Pull-down
Las resistencias pull-up y pull-down son elementos fundamentales en los circuitos digitales que garantizan estados lógicos definidos en las entradas de los microcontroladores. Estas resistencias evitan los estados flotantes o indefinidos, que pueden causar comportamiento errático en sistemas mecatrónicos e IoT.
En el ESP32, estas resistencias están integradas internamente y pueden ser activadas mediante software, simplificando significativamente el diseño del circuito y reduciendo la cantidad de componentes externos necesarios.
Pull-up (Elevación)
- Fuerza la entrada a HIGH (3.3V)
- Valor típico: 45kΩ
- Activación:
INPUT_PULLUP
- Uso común: Botones y switches
Pull-down (Sujeción)
- Fuerza la entrada a LOW (GND)
- Valor típico: 45kΩ
- Activación:
INPUT_PULLDOWN
- Uso común: Sensores activos en alto
Funcionamiento y Estados Lógicos
Configuración Pull-up
Estado por defecto: HIGH (1)
La resistencia interna conecta el GPIO a VCC (3.3V)
Activación externa:
- Botón liberado: GPIO = HIGH
- Botón presionado: GPIO = LOW (conexión a GND)
pinMode(pin, INPUT_PULLUP);
Configuración Pull-down
Estado por defecto: LOW (0)
La resistencia interna conecta el GPIO a GND
Activación externa:
- Switch liberado: GPIO = LOW
- Switch cerrado: GPIO = HIGH (conexión a VCC)
pinMode(pin, INPUT_PULLDOWN);
Implementación Práctica
El siguiente ejemplo demuestra el uso de ambos tipos de resistencias internas para crear un sistema de control robusto:
// Demostración de resistencias pull-up y pull-down internas en ESP32
#define BUTTON_PULLUP_PIN 21 // GPIO 21 - Botón con pull-up interno
#define BUTTON_PULLDOWN_PIN 22 // GPIO 22 - Botón con pull-down interno
#define LED_PIN 2 // GPIO 2 - LED indicador
#define RELAY_PIN 4 // GPIO 4 - Control de relé
// Variables para anti-rebote (debounce)
bool lastPullupState = HIGH;
bool lastPulldownState = LOW;
bool currentPullupState = HIGH;
bool currentPulldownState = LOW;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;
// Estados del sistema
bool systemEnabled = false;
bool ledState = false;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n=== Demostración Pull-up y Pull-down ESP32 ===");
// Configuración de GPIOs con resistencias internas
pinMode(BUTTON_PULLUP_PIN, INPUT_PULLUP); // Pull-up interno activado
pinMode(BUTTON_PULLDOWN_PIN, INPUT_PULLDOWN); // Pull-down interno activado
pinMode(LED_PIN, OUTPUT); // LED como salida
pinMode(RELAY_PIN, OUTPUT); // Relé como salida
// Estados iniciales
digitalWrite(LED_PIN, LOW);
digitalWrite(RELAY_PIN, LOW);
Serial.println("Configuración completada:");
Serial.printf("GPIO %d: INPUT_PULLUP (Botón de control)\n", BUTTON_PULLUP_PIN);
Serial.printf("GPIO %d: INPUT_PULLDOWN (Botón de activación)\n", BUTTON_PULLDOWN_PIN);
Serial.printf("GPIO %d: OUTPUT (LED indicador)\n", LED_PIN);
Serial.printf("GPIO %d: OUTPUT (Control de relé)\n", RELAY_PIN);
// Mostrar estados iniciales
Serial.println("\nEstados iniciales:");
Serial.printf("Pull-up pin: %s (esperado: HIGH)\n",
digitalRead(BUTTON_PULLUP_PIN) ? "HIGH" : "LOW");
Serial.printf("Pull-down pin: %s (esperado: LOW)\n",
digitalRead(BUTTON_PULLDOWN_PIN) ? "HIGH" : "LOW");
Serial.println("\nSistema listo. Presiona los botones para probar...\n");
}
void loop() {
// Lectura de estados actuales
currentPullupState = digitalRead(BUTTON_PULLUP_PIN);
currentPulldownState = digitalRead(BUTTON_PULLDOWN_PIN);
// Verificar cambios en cualquier botón para aplicar debounce
if (currentPullupState != lastPullupState ||
currentPulldownState != lastPulldownState) {
lastDebounceTime = millis();
}
// Aplicar anti-rebote
if ((millis() - lastDebounceTime) > debounceDelay) {
// Procesar botón pull-up (activo en LOW)
if (currentPullupState != lastPullupState) {
lastPullupState = currentPullupState;
if (currentPullupState == LOW) { // Botón presionado
if (systemEnabled) {
ledState = !ledState; // Alternar LED
digitalWrite(LED_PIN, ledState);
Serial.printf("Botón pull-up presionado - LED %s\n",
ledState ? "ENCENDIDO" : "APAGADO");
} else {
Serial.println("Sistema deshabilitado. Active primero con el botón pull-down.");
}
}
}
// Procesar botón pull-down (activo en HIGH)
if (currentPulldownState != lastPulldownState) {
lastPulldownState = currentPulldownState;
if (currentPulldownState == HIGH) { // Botón presionado
systemEnabled = !systemEnabled; // Alternar sistema
digitalWrite(RELAY_PIN, systemEnabled);
Serial.printf("Botón pull-down presionado - Sistema %s\n",
systemEnabled ? "ACTIVADO" : "DESACTIVADO");
// Si se desactiva el sistema, apagar LED
if (!systemEnabled && ledState) {
ledState = false;
digitalWrite(LED_PIN, LOW);
Serial.println("LED apagado automáticamente");
}
}
}
}
// Reporte periódico del estado (cada 5 segundos)
static unsigned long lastReport = 0;
if (millis() - lastReport > 5000) {
Serial.println("=== Estado del Sistema ===");
Serial.printf("Pull-up pin (GPIO %d): %s\n", BUTTON_PULLUP_PIN,
digitalRead(BUTTON_PULLUP_PIN) ? "HIGH" : "LOW");
Serial.printf("Pull-down pin (GPIO %d): %s\n", BUTTON_PULLDOWN_PIN,
digitalRead(BUTTON_PULLDOWN_PIN) ? "HIGH" : "LOW");
Serial.printf("Sistema: %s\n", systemEnabled ? "HABILITADO" : "DESHABILITADO");
Serial.printf("LED: %s\n", ledState ? "ENCENDIDO" : "APAGADO");
Serial.printf("Relé: %s\n", digitalRead(RELAY_PIN) ? "ACTIVO" : "INACTIVO");
Serial.println("=========================\n");
lastReport = millis();
}
// Pequeña pausa para estabilidad
delay(10);
}
// Función auxiliar para verificar capacidades de los pines
void verificarPinesGPIO() {
Serial.println("=== Verificación de Pines GPIO ===");
// Lista de pines que NO soportan pull-up/pull-down
int pinesSoloEntrada[] = {34, 35, 36, 39};
int numPines = sizeof(pinesSoloEntrada) / sizeof(pinesSoloEntrada[0]);
Serial.println("Pines solo de entrada (sin pull-up/pull-down):");
for (int i = 0; i < numPines; i++) {
Serial.printf("GPIO %d\n", pinesSoloEntrada[i]);
}
Serial.println("\nPines recomendados para pull-up/pull-down:");
Serial.println("GPIO 0, 2, 4, 5, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27");
Serial.println("====================================\n");
}
Ejercicios Prácticos
Objetivo: Implementar un botón que funcione correctamente usando la resistencia pull-up interna del ESP32.
Materiales necesarios:
- ESP32 DevKit
- Pulsador normalmente abierto
- LED (opcional para indicación visual)
- Resistencia de 220Ω para LED
- Protoboard y cables
Conexiones: Botón entre GPIO21 y GND, LED en GPIO2
Estado esperado: Sin pulsar = HIGH, Pulsado = LOW
Objetivo: Simular un sensor digital que se activa conectando a VCC usando pull-down interno.
Configuración:
- GPIO22 configurado como INPUT_PULLDOWN
- Switch conecta GPIO22 a 3.3V cuando se activa
- Relé o actuador controlado por la detección
- Monitoreo por Serial de cambios de estado
Aplicación: Sensores de proximidad, finales de carrera
Objetivo: Implementar comunicación I2C aprovechando las resistencias pull-up internas del ESP32.
Características:
- Configuración I2C con pull-up interno
- Comunicación con sensor MPU6050 o similar
- Lectura de datos del sensor por I2C
- Visualización de datos en tiempo real
- Manejo de errores de comunicación
Aplicación: Sensores industriales, IMUs, displays I2C
Aplicaciones en Sistemas Mecatrónicos
Importancia en Control Industrial
Las resistencias pull-up y pull-down son críticas en sistemas industriales donde la confiabilidad y la estabilidad de las señales digitales son fundamentales para la operación segura.
Aplicaciones Pull-up:
- Paradas de emergencia - Botones normalmente cerrados
- Sensores de puerta - Contactos reed normalmente abiertos
- Buses I2C/SPI - Líneas de comunicación
- Interfaces de usuario - Teclados matriciales
Aplicaciones Pull-down:
- Sensores ópticos - Detectores de presencia
- Sensores magnéticos - Hall effect
- Termostatos digitales - Contactos de temperatura
- Reset activo alto - Circuitos de reinicio
Casos de Uso Específicos
Sistema de Seguridad
Pull-up para botones de parada de emergenciaRed de Sensores
I2C con pull-up para múltiples dispositivosControl de Procesos
Pull-down para sensores de activaciónDiagnóstico y Solución de Problemas
Problemas Frecuentes
Entradas flotantes
Síntomas: Lecturas errática, cambios espontáneos de estado
Solución: Activar pull-up o pull-down apropiado para definir estado por defecto
Corriente excesiva
Causa: Cortocircuito directo entre VCC y GND
Prevención: Verificar conexiones, usar resistencias limitadoras
Pines incompatibles
Error: Usar GPIOs 34-39 con pull-up/down
Solución: Usar resistencias externas o cambiar de pin
Mejores Prácticas
Diseño Robusto
- Siempre definir estado por defecto de entradas
- Usar pull-up para botones normalmente abiertos
- Implementar anti-rebote en software
- Documentar polaridad de sensores
Validación de Diseño
- Probar estados sin conexión externa
- Verificar respuesta a activación
- Monitorear consumo de corriente
- Validar en condiciones extremas