#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/irq.h"
#include "hardware/timer.h"
#define NUM_DIGITS 3
#define SEGMENTS 8
// Pines de segmentos (A, B, C, D, E, F, G, DP) - según tu JSON
const uint SEGMENT_PINS[SEGMENTS] = {0, 1, 2, 3, 4, 5, 6, 7};
// Pines de cátodos comunes (DIG1, DIG2, DIG3)
const uint DIGIT_PINS[NUM_DIGITS] = {8, 9, 10};
// ADCs
#define VOLTAGE_ADC 0 // GP26
#define CURRENT_ADC 1 // GP27
// Botón
#define MODE_BUTTON 15
volatile bool mode_voltage = true;
volatile int display_value = 0;
volatile int active_digit = 0;
// Mapa CORREGIDO de segmentos para display de cátodo común
// Orden: A, B, C, D, E, F, G, DP (LSB to MSB)
const uint8_t digits7seg[10] = {
0b11111100, // 0 - ABCDEF (DP apagado)
0b01100000, // 1 - BC
0b11011010, // 2 - ABGED
0b11110010, // 3 - ABGCD
0b01100110, // 4 - FGBC
0b10110110, // 5 - AFGCD
0b10111110, // 6 - AFGCDE
0b11100000, // 7 - ABC
0b11111110, // 8 - ABCDEFG
0b11110110 // 9 - ABCDFG
};
// Timer ISR para multiplexado
bool timer_callback(repeating_timer_t *rt) {
// Apaga todos los dígitos primero (cátodo común: 1 = OFF)
for (int i = 0; i < NUM_DIGITS; i++) {
gpio_put(DIGIT_PINS[i], 1);
}
// Extrae cada dígito
int digits[NUM_DIGITS];
digits[0] = (display_value / 100) % 10; // Centenas
digits[1] = (display_value / 10) % 10; // Decenas
digits[2] = display_value % 10; // Unidades
// Enciende los segmentos para el dígito actual
uint8_t segs = digits7seg[digits[active_digit]];
// Manejo de segmentos (cátodo común: 0 = ON, 1 = OFF)
for (int s = 0; s < SEGMENTS-1; s++) { // Todos menos el DP
gpio_put(SEGMENT_PINS[s], !(segs & (1 << (7 - s))));
}
// Manejo especial del punto decimal (solo en el segundo dígito)
gpio_put(SEGMENT_PINS[7], (active_digit == 1) ? 0 : 1);
// Activa el dígito actual (cátodo común: 0 = ON)
gpio_put(DIGIT_PINS[active_digit], 0);
// Avanza al siguiente dígito
active_digit = (active_digit + 1) % NUM_DIGITS;
return true;
}
// ISR para el botón (debounce básico)
void gpio_callback(uint gpio, uint32_t events) {
static absolute_time_t last_press = 0;
absolute_time_t now = get_absolute_time();
if (gpio == MODE_BUTTON && absolute_time_diff_us(last_press, now) > 200000) {
mode_voltage = !mode_voltage;
last_press = now;
}
}
int main() {
stdio_init_all();
// Inicializa pines de segmentos
for (int i = 0; i < SEGMENTS; i++) {
gpio_init(SEGMENT_PINS[i]);
gpio_set_dir(SEGMENT_PINS[i], GPIO_OUT);
gpio_put(SEGMENT_PINS[i], 1); // Apagado inicial (cátodo común)
}
// Inicializa pines de dígitos
for (int i = 0; i < NUM_DIGITS; i++) {
gpio_init(DIGIT_PINS[i]);
gpio_set_dir(DIGIT_PINS[i], GPIO_OUT);
gpio_put(DIGIT_PINS[i], 1); // Apagado inicial (cátodo común)
}
// Configura el botón con pull-up
gpio_init(MODE_BUTTON);
gpio_set_dir(MODE_BUTTON, GPIO_IN);
gpio_pull_up(MODE_BUTTON);
gpio_set_irq_enabled_with_callback(MODE_BUTTON, GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
// Inicializa ADC
adc_init();
adc_gpio_init(26); // ADC0
adc_gpio_init(27); // ADC1
adc_select_input(VOLTAGE_ADC);
// Timer para multiplexado (3ms por dígito = ~100Hz refresco total)
static repeating_timer_t timer;
add_repeating_timer_ms(3, timer_callback, NULL, &timer);
while (true) {
// Lee el ADC según el modo
adc_select_input(mode_voltage ? VOLTAGE_ADC : CURRENT_ADC);
uint16_t adc_raw = adc_read();
// Convierte a voltaje (0-3.3V)
float voltage = (adc_raw * 3.3f) / 4095.0f;
// Escala a formato XXX (ej: 2.34V -> 234)
display_value = (int)(voltage * 100);
// Limita el valor a 3 dígitos
if (display_value > 999) display_value = 999;
if (display_value < 0) display_value = 0;
sleep_ms(50); // Tasa de actualización de 20Hz
}
}