Módulo 2

Pull-up y pull-down internos

GPIO y Control Digital

ESP32 Mecatrónica IoT UNAM

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
Importante: Los GPIOs 34-39 del ESP32 son solo de entrada (input-only) y NO tienen resistencias pull-up ni pull-down internas disponibles.

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:

C++ - Arduino IDE
// 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

1

Botón con Pull-up Interno

Principiante 15 min Hardware

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

2

Sensor con Pull-down Interno

Intermedio 25 min Sensores

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

3

Sistema I2C con Pull-up

Avanzado 40 min Comunicación

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 emergencia
Red de Sensores
I2C con pull-up para múltiples dispositivos
Control de Procesos
Pull-down para sensores de activación

Diagnó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

Referencias y Recursos Adicionales