#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/gpio.h"

// Definir los pines de los segmentos
#define PIN_A 11
#define PIN_B 13
#define PIN_C 17
#define PIN_D 15
#define PIN_E 14
#define PIN_F 12
#define PIN_G 16
const uint SEGMENTOS[7] = {PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_F, PIN_G};

// Definir los pines de los dígitos
#define PIN_D1 18  // décimas
#define PIN_D2 19  // unidades
#define PIN_D3 20  // decenas
#define PIN_D4 21  // centenas
#define PIN_DP 10
const uint DIGITOS[4] = {PIN_D1, PIN_D2, PIN_D3, PIN_D4};

// Definir pines para ADC
#define ADC_AMPERAJE     28   // Pin del ADC para corriente (ADC2)
#define ADC_VOLTAJE      27   // Pin del ADC para voltaje (ADC1)
#define BOTON_SELECCION  22   // Botón para seleccionar Voltaje o Corriente

// Tabla de segmentos para dígitos 0-9
const uint8_t tablaSegmentos[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};

// Variables globales
volatile uint8_t digitos[4] = {0};
volatile bool lectura_voltaje = true; // True = leer voltaje, False = leer corriente
volatile bool actualizar_display = false;

static uint32_t ultimo_tiempo_us = 0;

// Variables para filtrado de lecturas
#define TAMAÑO_FILTRO 21

static float buffer_voltaje[TAMAÑO_FILTRO] = {0};
static float buffer_corriente[TAMAÑO_FILTRO] = {0};
static uint8_t indice_buffer = 0;

// Declaración de funciones
static void configurar_gpio(void);
static void actualizar_digitos_desde_valor(uint16_t v);
static uint16_t digitos_a_valor(void);
static void limpiar_todo(void);
static void mostrar_digito(uint8_t d, uint8_t idx);
static bool temporizador_multiplexado(repeating_timer_t *);
static bool temporizador_leer_adc(repeating_timer_t *);
static void __isr interrupcion_boton(uint gpio, uint32_t events);
static float leer_adc(uint pin_adc);
static uint16_t convertir_a_valor_display(float voltaje);
static float aplicar_filtro_promedio_movil(float nuevo_valor, bool es_voltaje);

int main(void) {
    stdio_init_all();
    configurar_gpio();
    actualizar_digitos_desde_valor(0);

    // Timer para multiplexado del display (cada 2ms)
    repeating_timer_t tmux;
    add_repeating_timer_ms(2, temporizador_multiplexado, NULL, &tmux);

    // Timer para lectura del ADC (cada 50ms para mejor respuesta del filtro)
    repeating_timer_t tadc;
    add_repeating_timer_ms(50, temporizador_leer_adc, NULL, &tadc);

    while (true) {
        tight_loop_contents();
    }
}

static void configurar_gpio(void) {
    // Configuración de pines de segmentos
    for (int i = 0; i < 7; i++) {
        gpio_init(SEGMENTOS[i]);
        gpio_set_dir(SEGMENTOS[i], GPIO_OUT);
        gpio_put(SEGMENTOS[i], 1); // Común ánodo - 1 para apagar
    }

    // Configuración de pines de dígitos
    for (int i = 0; i < 4; i++) {
        gpio_init(DIGITOS[i]);
        gpio_set_dir(DIGITOS[i], GPIO_OUT);
        gpio_put(DIGITOS[i], 0); // Apagar todos los dígitos
    }

    // Configuración del punto decimal
    gpio_init(PIN_DP);
    gpio_set_dir(PIN_DP, GPIO_OUT);
    gpio_put(PIN_DP, 1); // Apagar punto decimal

    // Configuración de ADC
    adc_init();
    adc_gpio_init(ADC_AMPERAJE); // GP28 = ADC2
    adc_gpio_init(ADC_VOLTAJE);  // GP27 = ADC1

    // Configuración de botón de selección (V/A)
    gpio_init(BOTON_SELECCION);
    gpio_set_dir(BOTON_SELECCION, GPIO_IN);
    gpio_pull_down(BOTON_SELECCION);
    gpio_set_irq_enabled_with_callback(BOTON_SELECCION, GPIO_IRQ_EDGE_RISE, true, interrupcion_boton);
}

static void __isr interrupcion_boton(uint gpio, uint32_t events) {
    uint32_t ahora = time_us_32();

    if (gpio == BOTON_SELECCION && ahora - ultimo_tiempo_us > 50000) { // Antirrebote de 50ms
        // Alternar entre lectura de voltaje y corriente
        lectura_voltaje = !lectura_voltaje;
        ultimo_tiempo_us = ahora;
    }
}

// Temporizador para multiplexado del display
static bool temporizador_multiplexado(repeating_timer_t *rt) {
    static uint8_t idx = 0;
    mostrar_digito(digitos[idx], idx);
    idx = (idx + 1) & 3; // Rotar entre 0-3
    return true;
}

// Temporizador para lectura del ADC
static bool temporizador_leer_adc(repeating_timer_t *rt) {
    float voltaje_crudo;
    float voltaje_filtrado;
    uint16_t valor_display;
    
    if (lectura_voltaje) {
        // Leer voltaje del pin ADC1 (GP27)
        voltaje_crudo = leer_adc(1); // ADC1
        voltaje_filtrado = aplicar_filtro_promedio_movil(voltaje_crudo, true);
        valor_display = convertir_a_valor_display(voltaje_filtrado);
        actualizar_digitos_desde_valor(valor_display);

        }
    else {
        // Leer corriente del pin ADC2 (GP28)
        voltaje_crudo = leer_adc(2); // ADC2
        voltaje_filtrado = aplicar_filtro_promedio_movil(voltaje_crudo, false);
        
        valor_display = convertir_a_valor_display(voltaje_filtrado);
        actualizar_digitos_desde_valor(valor_display);

        }
    
    return true;
}

static void actualizar_digitos_desde_valor(uint16_t v) {
    // Limitar el valor a 9999
    if (v > 9999) v = 9999;
    
    digitos[0] = v % 10;           // Décimas
    digitos[1] = (v / 10) % 10;    // Unidades
    digitos[2] = (v / 100) % 10;   // Decenas
    digitos[3] = (v / 1000) % 10;  // Centenas
}

static uint16_t digitos_a_valor(void) {
    return digitos[0] + digitos[1] * 10 + digitos[2] * 100 + digitos[3] * 1000;
}

static void limpiar_todo(void) {
    // Apagar todos los dígitos
    for (int i = 0; i < 4; i++) {
        gpio_put(DIGITOS[i], 0);
    }
    // Apagar todos los segmentos 
    for (int i = 0; i < 7; i++) {
        gpio_put(SEGMENTOS[i], 1);
    }
    gpio_put(PIN_DP, 1);
}

static void mostrar_digito(uint8_t d, uint8_t idx) {
    limpiar_todo();

    if (idx == 3) {
        gpio_put(PIN_DP, 0);  // Encender punto decimal
    }

    // Obtener el patrón de segmentos para el dígito
    uint8_t seg = tablaSegmentos[d];
    
    // Configurar cada segmento (invertir porque es común ánodo)
    gpio_put(PIN_A, !(seg & 0x01));
    gpio_put(PIN_B, !(seg & 0x02));
    gpio_put(PIN_C, !(seg & 0x04));
    gpio_put(PIN_D, !(seg & 0x08));
    gpio_put(PIN_E, !(seg & 0x10));
    gpio_put(PIN_F, !(seg & 0x20));
    gpio_put(PIN_G, !(seg & 0x40));

    // Activar el dígito correspondiente
    gpio_put(DIGITOS[idx], 1);
}

// Función para leer el ADC
static float leer_adc(uint canal_adc) {
    adc_select_input(canal_adc);
    uint16_t resultado = adc_read();
    // Convertir a voltaje (0-3.3V)
    return (resultado * 3.3f) / 4095.0f; //4095 = 2^12 - 1, resolución de 12 bits
}

// Convertir voltaje a valor para mostrar en display
static uint16_t convertir_a_valor_display(float voltaje) {
    uint16_t valor = (uint16_t)(voltaje * 1000);
    
    // Limitar a 4 dígitos (máximo 9.999V)
    if (valor > 9999) valor = 9999;
    
    return valor;
}

// Filtro de promedio móvil
static float aplicar_filtro_promedio_movil(float nuevo_valor, bool es_voltaje) {
    float *buffer = es_voltaje ? buffer_voltaje : buffer_corriente;
    float suma = 0.0f;
    
    // Añadir nuevo valor al buffer circular
    buffer[indice_buffer] = nuevo_valor;
    indice_buffer = (indice_buffer + 1) % TAMAÑO_FILTRO;
    
    // Calcular promedio
    for (int i = 0; i < TAMAÑO_FILTRO; i++) {
        suma += buffer[i];
    }
    
    return suma / TAMAÑO_FILTRO;
}
Loading
pi-pico-w