#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/timer.h"
#include "hardware/irq.h"
#include "pico/critical_section.h"
#include "pico/cyw43_arch.h"
#define A_PIN 11
#define B_PIN 13
#define C_PIN 17
#define D_PIN 15
#define E_PIN 14
#define F_PIN 12
#define G_PIN 16
const uint SEGMENTS[7] = {A_PIN,B_PIN,C_PIN,D_PIN,E_PIN,F_PIN,G_PIN};
#define D1_PIN 18 // décimas
#define D2_PIN 19 // unidades
#define D3_PIN 20 // decenas
#define D4_PIN 21 // centenas
#define DP_PIN 10
const uint DIGITS[4] = {D1_PIN,D2_PIN,D3_PIN,D4_PIN};
#define START_STOP_PIN 28
#define RESET_PIN 27
#define SET_PIN 9
#define INCREASE_PIN 22
const uint BTN[4] = {START_STOP_PIN, RESET_PIN, SET_PIN, INCREASE_PIN};
const uint8_t segmentTable[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
volatile uint tiempo_decimas = 0; // 0-9999
volatile uint8_t digits[4] = {0};
volatile bool cronometro_activo = false;
volatile bool cuenta_up = true; // true = asc, false = desc
volatile bool editing = false;
volatile uint8_t edit_idx = 0;
volatile bool blink_500 = false;
volatile uint8_t alarm_left = 0; // 10 → 5 s de parpadeo
static uint32_t last_us_start=0,last_us_reset=0,last_us_set=0,last_us_inc=0;
static void gpio_setup(void);
static void update_digits_from_val(uint16_t v);
static uint16_t digits_to_val(void);
static void clear_all(void);
static void display_digit(uint8_t d,uint8_t idx);
static bool t_mux (repeating_timer_t*);
static bool t_tick (repeating_timer_t*);
static bool t_blink(repeating_timer_t*);
static void __isr gpio_btn_isr(uint gpio,uint32_t events);
int main(void)
{
stdio_init_all();
gpio_setup();
update_digits_from_val(0);
repeating_timer_t tmux, ttick, tblink;
add_repeating_timer_ms(2, t_mux, NULL,&tmux);
add_repeating_timer_ms(100, t_tick, NULL,&ttick);
add_repeating_timer_ms(500, t_blink, NULL,&tblink);
while (true) tight_loop_contents();
}
static void gpio_setup(void)
{
/* segmentos y dígitos */
for(int i=0;i<7;i++){
gpio_init(SEGMENTS[i]);
gpio_set_dir(SEGMENTS[i],GPIO_OUT);
gpio_put(SEGMENTS[i],1);}
for(int i=0;i<4;i++){
gpio_init(DIGITS[i]);
gpio_set_dir(DIGITS[i],GPIO_OUT);
gpio_put(DIGITS[i],0);}
gpio_init(DP_PIN);
gpio_set_dir(DP_PIN,GPIO_OUT);
gpio_put(DP_PIN,1);
for(int i=0;i<4;i++){
gpio_init(BTN[i]);
gpio_set_dir(BTN[i],GPIO_IN);
gpio_pull_down(BTN[i]); }
//callback para los 4 pines
gpio_set_irq_enabled_with_callback(START_STOP_PIN, GPIO_IRQ_EDGE_RISE, true, gpio_btn_isr);
gpio_set_irq_enabled (RESET_PIN, GPIO_IRQ_EDGE_RISE, true);
gpio_set_irq_enabled (SET_PIN, GPIO_IRQ_EDGE_RISE, true);
gpio_set_irq_enabled (INCREASE_PIN, GPIO_IRQ_EDGE_RISE, true);
}
static void __isr gpio_btn_isr(uint gpio,uint32_t events)
{
uint32_t now=time_us_32();
/* Start / Stop */
if(gpio==START_STOP_PIN && now-last_us_start>200000){
if(editing){ // salir de edición
tiempo_decimas = digits_to_val();
cuenta_up = (tiempo_decimas==0);
editing = false;
}
cronometro_activo = !cronometro_activo;
last_us_start = now;
}
/* Reset */
else if(gpio==RESET_PIN && now-last_us_reset>200000){
cronometro_activo = false;
editing=false;
alarm_left=0;
tiempo_decimas=0;
update_digits_from_val(0);
last_us_reset = now;
}
/* Set: seleccionar dígito */
else if(gpio==SET_PIN && now-last_us_set>200000){
if(!editing){ editing=true; edit_idx=0; }
else { edit_idx=(edit_idx+1)&3; }
last_us_set = now;
}
/* Increase */
else if(gpio==INCREASE_PIN && now-last_us_inc>200000){
if(editing){
digits[edit_idx]=(digits[edit_idx]+1)%10;
}
last_us_inc = now;
}
}
static bool t_mux(repeating_timer_t*)
{
static uint8_t idx=0;
display_digit(digits[idx],idx);
idx=(idx+1)&3;
return true;
}
static bool t_tick(repeating_timer_t*)
{
if(!cronometro_activo) return true;
if(cuenta_up){
if(++tiempo_decimas==10000) tiempo_decimas=0;
}else{
if(tiempo_decimas>0) --tiempo_decimas;
if(tiempo_decimas==0){
cronometro_activo=false;
alarm_left=10; // 5 s / 0.5 s
}
}
if(!editing) update_digits_from_val(tiempo_decimas);
return true;
}
static bool t_blink(repeating_timer_t*)
{
blink_500 = !blink_500;
if(alarm_left){
alarm_left--;
if(!alarm_left) update_digits_from_val(0);
}
return true;
}
static void update_digits_from_val(uint16_t v){
digits[0]= v%10;
digits[1]=(v/10)%10;
digits[2]=(v/100)%10;
digits[3]=(v/1000)%10;
}
static uint16_t digits_to_val(void){
return digits[0]+digits[1]*10+digits[2]*100+digits[3]*1000;
}
static void clear_all(void){
for(int i=0;i<4;i++) gpio_put(DIGITS[i],0);
for(int i=0;i<7;i++) gpio_put(SEGMENTS[i],1);
gpio_put(DP_PIN,1);
}
static void display_digit(uint8_t d,uint8_t idx)
{
clear_all();
/* Punto decimal */
if(idx==1){
bool dp = (!editing && cronometro_activo) ||
(!editing && !cronometro_activo && blink_500);
if(dp) gpio_put(DP_PIN,0);
}
// alarma de fin y blink de edición
if((alarm_left && !blink_500) ||
(editing && idx==edit_idx && !blink_500))
return;
uint8_t seg=segmentTable[d];
gpio_put(A_PIN,!(seg&0x01));
gpio_put(B_PIN,!(seg&0x02));
gpio_put(C_PIN,!(seg&0x04));
gpio_put(D_PIN,!(seg&0x08));
gpio_put(E_PIN,!(seg&0x10));
gpio_put(F_PIN,!(seg&0x20));
gpio_put(G_PIN,!(seg&0x40));
gpio_put(DIGITS[idx],1);
}