#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
pi-pico-w