Programación de GPIO e Interrupciones en Arduino-Pico: Control de Entradas/Salidas Digitales, Analógicas y Sensores de Temperatura

Configuración del entorno de desarrollo

Para comenzar a trabajar con el núcleo Arduino-Pico en el RP2040 o RP2350, es necesario configurar el IDE de Arduino. Accede a las preferencias y añade la URL del gestor de placas correspondiente. Una vez actualizado el índice, instala el paquete "Raspberry Pi Pico/RP2040" desde el gestor de placas.

Tras la instalación, selecciona tu modelo específico de placa (Pico, Pico W, o variantes RP2350) y el puerto de comunicación adecuado.

Arquitectura de pines GPIO del RP2040

El microcontrolador RP2040 dispone de 26 pines GPIO multifunción, cada uno configurable hasta en 5 modos alternativos. Esta flexibliidad permite asignar periféricos (UART, SPI, I2C, PWM) a diferentes pines físicos según las necesidades del diseño.

Pin Función 0 Función 1 Función 2 Función 3 Función 4
GPIO0 SPI0 RX UART0 TX I2C0 SDA PWM0 A SIO
GPIO1 SPI0 CSn UART0 RX I2C0 SCL PWM0 B SIO
GPIO26-29 ADC SPI1 I2C1 PWM SIO

Manejo de señales digitales

Configuración de modos de operación

La función pinMode() admite configuraciones avanzadas de resistencia interna y capacidad de corriente:

// Modos de entrada
pinMode(PIN_ENTRADA, INPUT);           // Alta impedancia
pinMode(PIN_ENTRADA, INPUT_PULLUP);    // Resistencia pull-up interna (~50kΩ)
pinMode(PIN_ENTRADA, INPUT_PULLDOWN);  // Resistencia pull-down interna (~50kΩ)

// Modos de salida con control de corriente
pinMode(PIN_SALIDA, OUTPUT);           // Corriente por defecto (4mA)
pinMode(PIN_SALIDA, OUTPUT_2MA);       // Bajo consumo
pinMode(PIN_SALIDA, OUTPUT_4MA);       // Estándar
pinMode(PIN_SALIDA, OUTPUT_8MA);       // Alta capacidad
pinMode(PIN_SALIDA, OUTPUT_12MA);      // Máxima capacidad

Operaciones de lectura y escritura

// Control de salida
digitalWrite(PIN_RELE, HIGH);   // Activar relé
digitalWrite(PIN_RELE, LOW);    // Desactivar relé

// Lectura de entrada
bool estado_pulsador = digitalRead(PIN_PULSADOR);

Sistema de interrupciones externas

Todos los pines GPIO del RP2040 pueden generar interrupciones, con detección de flancos configurable a nivel de hardware.

Implementación básica de interrupciones

// Variable volatile para comunicación ISR-loop
volatile bool evento_detectado = false;
uint32_t contador_eventos = 0;

void manejadorInterrupcion() {
    // Operación mínima: solo activar bandera
    evento_detectado = true;
}

void configuracion() {
    Serial.begin(115200);
    pinMode(PIN_SENSOR, INPUT_PULLUP);
    
    // Asociar función a interrupción
    attachInterrupt(
        digitalPinToInterrupt(PIN_SENSOR),
        manejadorInterrupcion,
        FALLING  // Disparo en flanco descendente
    );
}

void cicloPrincipal() {
    if (evento_detectado) {
        evento_detectado = false;
        contador_eventos++;
        Serial.printf("Evento #%lu detectado\n", contador_eventos);
    }
}

Modos de disparo disponibles

  • RISING: Flanco ascendente (0 → 1)
  • FALLING: Flanco descendente (1 → 0)
  • CHANGE: Cualquier transición de nivel
  • LOW: Nivel bajo sostenido (limitado a ciertos pines)
  • HIGH: Nivel alto sostenido (limitado a ciertos pines)

Conversión analógica-digital (ADC)

El RP2040 integra un ADC de 12 bits con cinco canales: cuatro externos (GPIO26-29) y un canal dedicado al sensor de temperatura interno.

Configuración y lectura del ADC

// Precisión configurable
analogReadResolution(12);  // Rango 0-4095 (resolución nativa)
analogReadResolution(10);  // Rango 0-1023 (compatibilidad Arduino)

// Lectura con conversión a voltaje
uint16_t valor_crudo = analogRead(CANAL_LUZ);
float voltaje = valor_crudo * 3.3f / 4095.0f;

Lectura del sensor térmico integrado

El sensor de temperatura del RP2040 se basa en una referencia de bandgap de silicio, con compensación de voltaje de alimentación:

// Lectura con referencia por defecto (3.3V)
float temperatura = analogReadTemp();

// Lectura con referencia personalizada (para mayor precisión)
float temp_calibrada = analogReadTemp(3.0f);  // Si VREF real es 3.0V

Especificaciones del sensor:

  • Rango operativo: -20°C a +85°C
  • Precisión típica: ±1°C
  • Resolución: aproximadamente 0.05°C/LSB

Técnicas de filtrado y estabilización

Antirrebote por software

volatile bool interrupcion_valida = false;
unsigned long ultimo_tiempo_evento = 0;
const unsigned long TIEMPO_ANTIRREBOTE = 25;  // ms

void ISR_con_filtro() {
    unsigned long ahora = millis();
    if (ahora - ultimo_tiempo_evento > TIEMPO_ANTIRREBOTE) {
        ultimo_tiempo_evento = ahora;
        interrupcion_valida = true;
    }
}

Promediado móvil para ADC

float leerADC_promediado(uint8_t canal, uint8_t muestras) {
    uint32_t acumulador = 0;
    for (uint8_t i = 0; i < muestras; i++) {
        acumulador += analogRead(canal);
        delayMicroseconds(10);  // Tiempo de establecimiento
    }
    return (acumulador / (float)muestras) * 3.3f / 4095.0f;
}

Aplicación práctica: Monitor ambiental

#include <Arduino.h>

// Definiciones de hardware
const uint8_t PIN_TERMISTOR = A0;      // GPIO26
const uint8_t PIN_FOTORESISTENCIA = A1; // GPIO27
const uint8_t PIN_VENTILADOR = 16;      // GPIO16
const uint8_t PIN_INDICADOR = 25;       // LED integrado
const uint8_t PIN_ALARMA = 14;          // GPIO14 (pulsador/interrupción)

// Variables de estado
volatile bool modo_alarma = false;
float temperatura_umbral = 28.5f;
uint16_t brillo_ambiental = 0;

void activarAlarma() {
    modo_alarma = !modo_alarma;  // Conmutar estado
}

void inicializarHardware() {
    Serial.begin(115200);
    
    // Configurar salidas
    pinMode(PIN_VENTILADOR, OUTPUT_8MA);
    pinMode(PIN_INDICADOR, OUTPUT);
    
    // Configurar entrada con interrupción
    pinMode(PIN_ALARMA, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(PIN_ALARMA), activarAlarma, FALLING);
    
    // Precisión ADC
    analogReadResolution(12);
}

float obtenerTemperatura() {
    // Conversión del ADC a temperatura (aproximación lineal)
    float temp = analogReadTemp();
    // Compensación de autocalentamiento del chip
    return temp - 0.5f;
}

void controlClimatico(float temp_actual) {
    static bool estado_ventilador = false;
    
    if (temp_actual > temperatura_umbral) {
        if (!estado_ventilador) {
            digitalWrite(PIN_VENTILADOR, HIGH);
            digitalWrite(PIN_INDICADOR, HIGH);
            estado_ventilador = true;
            Serial.println("Ventilador ACTIVADO");
        }
    } else if (temp_actual < temperatura_umbral - 2.0f) {
        if (estado_ventilador) {
            digitalWrite(PIN_VENTILADOR, LOW);
            digitalWrite(PIN_INDICADOR, LOW);
            estado_ventilador = false;
            Serial.println("Ventilador DESACTIVADO");
        }
    }
}

void reportarSensores(float temp, uint16_t luz) {
    Serial.printf("Temp: %.2f°C | Luz: %u/4095 | Alarma: %s\n",
                  temp, luz, modo_alarma ? "ON" : "OFF");
}

void setup() {
    inicializarHardware();
    Serial.println("Sistema iniciado");
}

void loop() {
    // Lectura de sensores
    float temperatura = obtenerTemperatura();
    brillo_ambiental = analogRead(PIN_FOTORESISTENCIA);
    
    // Lógica de control
    controlClimatico(temperatura);
    
    // Verificar bandera de interrupción
    if (modo_alarma) {
        modo_alarma = false;  // Resetear para próxima activación
        Serial.println("*** ALARMA MANUAL ACTIVADA ***");
        // Acciones adicionales de alarma...
    }
    
    // Reporte periódico
    reportarSensores(temperatura, brillo_ambiental);
    
    delay(1000);
}

Optimización para aplicaciones de bajo consumo

// Desactivar pines no utilizados para reducir consumo
void desactivarPinesReserva() {
    for (uint8_t pin = 2; pin <= 13; pin++) {
        pinMode(pin, INPUT_PULLDOWN);  // Estado definido, mínima corriente
    }
}

// Reducir corriente de salida cuando sea posible
pinMode(PIN_LED_ESTADO, OUTPUT_2MA);  // Suficiente para LED indicador

Depuración con PlatformIO

Para proyectos avanzados, PlatformIO ofrece capacidades superiores:

  1. Crear proyecto con plataforma raspberrypi y board pico
  2. Configurar platformio.ini con opciones de depuración
  3. Utilizar Serial.printf() para formateo eficiente
  4. Implementar asserts para validación en tiempo de desarrollo
; platformio.ini de ejemplo
[env:pico]
platform = raspberrypi
board = pico
framework = arduino
build_flags = -D SERIAL_USB
monitor_speed = 115200

Resolución de problemas frecuentes

Síntoma Causa probable Solución
Lecturas ADC erráticas Referencia de voltaje inestable Agregar capacitor 100nF en VREF
Interrupciones múltiples espurias Rebote del interruptor Implementar antirrebote por hardware o software
Temperatura incorrecta Autocalentamiento del RP2040 Compensar con offset o usar promediado
Pines no responden Conflicto con periférico asignado Verificar tabla de multiplexación de funciones

Etiquetas: RP2040 RP2350 Arduino-Pico GPIO ADC

Publicado el 9-11 21:40