#include <Arduino.h>
#include <STM32FreeRTOS.h>
// ===== Configuración de pines =====
const uint8_t PINES_SEGMENTOS[7] = { D2, D3, D4, D5, D6, D7, D8 }; // a b c d e f g
const uint8_t PIN_BOTON = D9; // botón a GND (INPUT_PULLUP)
const uint8_t PIN_ENTROPIA = A0; // analógico SIN CONECTAR
// ===== Display: CÁTODO COMÚN =====
#define ENCENDER_SEGMENTO HIGH
#define APAGAR_SEGMENTO LOW
// Patrones de segmentos para dígitos 0-9 (a,b,c,d,e,f,g)
const uint8_t PATRONES_DIGITOS[10][7] = {
{1,1,1,1,1,1,0}, {0,1,1,0,0,0,0}, {1,1,0,1,1,0,1}, {1,1,1,1,0,0,1}, {0,1,1,0,0,1,1},
{1,0,1,1,0,1,1}, {1,0,1,1,1,1,1}, {1,1,1,0,0,0,0}, {1,1,1,1,1,1,1}, {1,1,1,1,0,1,1}
};
// ===== Estado global =====
volatile bool solicitudLanzamiento = false;
volatile uint8_t valorDadoActual = 0;
// ===== Funciones de control del display =====
void mostrarNumeroEnDisplay(uint8_t digito) {
if (digito > 9) digito = 0;
for (uint8_t indiceSegmento = 0; indiceSegmento < 7; indiceSegmento++)
digitalWrite(PINES_SEGMENTOS[indiceSegmento], PATRONES_DIGITOS[digito][indiceSegmento] ? ENCENDER_SEGMENTO : APAGAR_SEGMENTO);
}
void apagarDisplayCompletamente() {
for (uint8_t indiceSegmento = 0; indiceSegmento < 7; indiceSegmento++)
digitalWrite(PINES_SEGMENTOS[indiceSegmento], APAGAR_SEGMENTO);
}
// ===== Generador de números aleatorios =====
static uint32_t estadoGeneradorAleatorio = 0xA5A5A5A5;
static inline void mezclarEntropia(uint32_t valorEntropia){
estadoGeneradorAleatorio ^= valorEntropia + 0x9E3779B9u + (estadoGeneradorAleatorio << 6) + (estadoGeneradorAleatorio >> 2);
}
static inline uint32_t siguienteNumeroAleatorio(){
uint32_t x = estadoGeneradorAleatorio;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
estadoGeneradorAleatorio = x ? x : 0x1u;
return estadoGeneradorAleatorio;
}
static inline uint8_t generarNumeroDado(){
uint32_t entropia = (uint32_t)micros();
entropia ^= (uint32_t)xTaskGetTickCount() << 16;
entropia ^= ((uint32_t)analogRead(PIN_ENTROPIA) & 0x3FFu) << 2;
mezclarEntropia(entropia);
uint32_t numeroAleatorio = siguienteNumeroAleatorio();
return (uint8_t)(numeroAleatorio % 6u) + 1u;
}
// ===== Tareas FreeRTOS =====
void tareaLecturaBoton(void * parametro){
const TickType_t PERIODO_MUESTREO = pdMS_TO_TICKS(10);
const uint8_t LECTURAS_CONSECUTIVAS = 3;
uint8_t contadorEstabilidad = 0;
int estadoAnterior = HIGH, estadoEstable = HIGH;
TickType_t ultimoDespertar = xTaskGetTickCount();
for(;;){
int lecturaActual = digitalRead(PIN_BOTON);
if (lecturaActual == estadoAnterior) {
if (contadorEstabilidad < LECTURAS_CONSECUTIVAS) contadorEstabilidad++;
} else {
contadorEstabilidad = 0;
estadoAnterior = lecturaActual;
}
if (contadorEstabilidad == LECTURAS_CONSECUTIVAS) {
if (estadoEstable == HIGH && lecturaActual == LOW) solicitudLanzamiento = true;
estadoEstable = lecturaActual;
}
vTaskDelayUntil(&ultimoDespertar, PERIODO_MUESTREO);
}
}
void tareaControlDado(void * parametro){
for(;;){
if (solicitudLanzamiento){
Serial.println("Lanzando dado...");
// Animación de "ruleta" antes del resultado
for (uint8_t iteracion = 0; iteracion < 12; ++iteracion){
mostrarNumeroEnDisplay((iteracion % 6) + 1);
vTaskDelay(pdMS_TO_TICKS(45));
}
// Generar y mostrar resultado final
valorDadoActual = generarNumeroDado();
mostrarNumeroEnDisplay(valorDadoActual);
Serial.print("Resultado del dado: ");
Serial.println(valorDadoActual);
solicitudLanzamiento = false;
}
vTaskDelay(pdMS_TO_TICKS(20));
}
}
// ===== Configuración inicial =====
void setup(){
// Configuración de pines GPIO
pinMode(PIN_BOTON, INPUT_PULLUP);
for (uint8_t indicePin = 0; indicePin < 7; indicePin++){
pinMode(PINES_SEGMENTOS[indicePin], OUTPUT);
digitalWrite(PINES_SEGMENTOS[indicePin], APAGAR_SEGMENTO);
}
pinMode(PIN_ENTROPIA, INPUT);
// Configuración comunicación serial
Serial.begin(9600);
Serial.println("\n=== DADO ELECTRÓNICO ===");
Serial.println("Presione el botón para lanzar el dado");
Serial.println("Display: 7 segmentos - Cátodo común");
Serial.println("Esperando lanzamiento...");
// Inicialización del generador aleatorio
uint32_t semilla1 = micros() ^ (uint32_t)HAL_GetUIDw0();
uint32_t semilla2 = (uint32_t)HAL_GetUIDw1() ^ (uint32_t)analogRead(PIN_ENTROPIA);
uint32_t semilla3 = (uint32_t)HAL_GetUIDw2() ^ (uint32_t)xTaskGetTickCount();
mezclarEntropia(semilla1);
mezclarEntropia(semilla2);
mezclarEntropia(semilla3);
// Creación de tareas FreeRTOS
xTaskCreate(tareaLecturaBoton, "Boton", 256, NULL, tskIDLE_PRIORITY + 2, NULL);
xTaskCreate(tareaControlDado, "Dado", 256, NULL, tskIDLE_PRIORITY + 1, NULL);
vTaskStartScheduler();
}
void loop(){}