// Cronómetro Digital Programable - Raymond Then - ID: 1105619
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/timer.h"
// Definiciones
const uint SEGMENTS[8] = {0, 1, 2, 3, 4, 5, 6, 7}; // 7 - punto decimal
const uint DIGITS[4] = {8, 9, 10, 11};
// Botones asignados:
// BOTONES[0] -> Start/Stop (pin 12)
// BOTONES[1] -> Set (pin 13)
// BOTONES[2] -> Increase (pin 14)
// BOTONES[3] -> Reset (pin 15)
const uint BUTTONS[4] = {12, 13, 14, 15};
// Variables globales
volatile bool button_pressed[4] = {false, false, false, false}; // Ningún botón ha sido presionado
volatile bool running = false; // Indica si el cronómetro está en marcha
volatile bool countdown = false; // Indica si el cronómetro está contando hacia atrás
volatile uint display_digits[4] = {0, 0, 0, 0}; // Valores actuales de los displays - default
volatile int selected_digit = -1; // -1 indica que no hay dígito seleccionado
volatile bool blink = false; // Indica si el dígito seleccionado o el display completo debe parpadear
volatile bool timer_finished = false; // Indica si el cronómetro ha alcanzado su final y debe iniciar el parpadeo de los dígitos
volatile uint blink_counter = 0; // Lleva la cuenta de cuántas veces ha parpadeado el display después de que el cronómetro ha finalizado
// Mapa de segmentos para ánodo común
const uint SEGMENT_MAP[10] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
// Declaraciones de funciones
void display_update(volatile uint display_digits[4]); // Actualiza el display de 7 segmentos con los valores actuales de los dígitos
bool timer_callback(struct repeating_timer *t); // Actualiza el estado del cronómetro y maneja el parpadeo de los dígitos
void button_callback(uint gpio, uint32_t events); // Maneja las interrupciones generadas por los botones
void gpio_setup(); // Configura los pines GPIO necesarios para los segmentos del display, los dígitos y los botones
void handle_buttons(); // Procesa el estado de los botones y realiza las acciones correspondientes
int main() {
stdio_init_all();
gpio_setup();
struct repeating_timer timer;
add_repeating_timer_ms(10, timer_callback, NULL, &timer); // Tasa de refresco de 10 ms
while (1) {
handle_buttons();
display_update(display_digits);
}
return 0;
}
// Configuración GPIO
void gpio_setup() {
for (int i = 0; i < 8; i++) {
gpio_init(SEGMENTS[i]);
gpio_set_dir(SEGMENTS[i], GPIO_OUT);
}
for (int i = 0; i < 4; i++) {
gpio_init(DIGITS[i]);
gpio_set_dir(DIGITS[i], GPIO_OUT);
gpio_init(BUTTONS[i]);
gpio_set_dir(BUTTONS[i], GPIO_IN);
gpio_pull_up(BUTTONS[i]);
gpio_set_irq_enabled_with_callback(BUTTONS[i], GPIO_IRQ_EDGE_FALL, true, button_callback);
}
}
// Actualizar display
void display_update(volatile uint display_digits[4]) {
for (int i = 0; i < 4; i++) {
if (timer_finished && blink) {
for (int j = 0; j < 8; j++) {
gpio_put(SEGMENTS[j], 1);
}
} else if (i == selected_digit && blink) {
for (int j = 0; j < 8; j++) {
gpio_put(SEGMENTS[j], 1);
}
} else {
uint digit = display_digits[i];
for (int j = 0; j < 7; j++) {
gpio_put(SEGMENTS[j], !((SEGMENT_MAP[digit] >> j) & 1));
}
if (i == 1) {
gpio_put(SEGMENTS[7], 0);
} else {
gpio_put(SEGMENTS[7], 1);
}
}
gpio_put(DIGITS[3 - i], 1);
sleep_ms(5);
gpio_put(DIGITS[3 - i], 0);
}
}
// Timer callback para actualizar el estado del cronómetro
bool timer_callback(struct repeating_timer *t) {
static uint tenth_counter = 0; // Contador para 0.1 segundos
static uint half_second_counter = 0; // Contador para 0.5 segundos
if (timer_finished) {
half_second_counter++;
if (half_second_counter >= 50) {
half_second_counter = 0;
blink = !blink;
blink_counter++;
if (blink_counter >= 10) {
timer_finished = false;
blink_counter = 0;
blink = false;
}
}
} else if (running) {
tenth_counter++;
if (tenth_counter >= 10) {
tenth_counter = 0;
if (countdown) {
if (display_digits[0] == 0 && display_digits[1] == 0 && display_digits[2] == 0 && display_digits[3] == 0) {
running = false;
timer_finished = true;
} else {
if (display_digits[0] == 0) {
display_digits[0] = 9;
if (display_digits[1] == 0) {
display_digits[1] = 9;
if (display_digits[2] == 0) {
display_digits[2] = 9;
if (display_digits[3] != 0) {
display_digits[3]--;
}
} else {
display_digits[2]--;
}
} else {
display_digits[1]--;
}
} else {
display_digits[0]--;
}
}
} else {
display_digits[0]++;
for (int i = 0; i < 3; i++) {
if (display_digits[i] >= 10) {
display_digits[i] = 0;
display_digits[i + 1]++;
}
}
if (display_digits[3] >= 10) {
display_digits[3] = 0;
}
}
}
}
if (selected_digit != -1) {
half_second_counter++;
if (half_second_counter >= 25) {
half_second_counter = 0;
blink = !blink;
}
}
return true;
}
// Interrupción para manejar botones
void button_callback(uint gpio, uint32_t events) {
for (int i = 0; i < 4; i++) {
if (gpio == BUTTONS[i]) {
button_pressed[i] = true;
break;
}
}
}
// Procesar botones
void handle_buttons() {
if (button_pressed[0]) {
if (selected_digit != -1) {
running = true;
countdown = true;
selected_digit = -1;
} else {
running = !running;
}
button_pressed[0] = false;
}
if (button_pressed[1]) {
selected_digit = (selected_digit + 1) % 4;
button_pressed[1] = false;
}
if (button_pressed[2] && selected_digit != -1) {
display_digits[selected_digit] = (display_digits[selected_digit] + 1) % 10;
button_pressed[2] = false;
}
if (button_pressed[3]) {
running = false;
countdown = false;
for (int i = 0; i < 4; i++) {
display_digits[i] = 0;
}
selected_digit = -1;
timer_finished = false;
blink_counter = 0;
blink = false;
button_pressed[3] = false;
}
}