com display

This commit is contained in:
XupaMisto 2025-11-23 18:15:56 +00:00
parent d5bbf905a4
commit b7f03c7bf6
12 changed files with 303 additions and 2 deletions

View File

@ -12,7 +12,9 @@ idf_component_register(
"eeprom_animacao.c" "eeprom_animacao.c"
"led_task.c" "led_task.c"
"creditos.c" "creditos.c"
"premios.c"
"i2c_helper.c"
"display.c"
INCLUDE_DIRS INCLUDE_DIRS
"include" "include"

67
main/display.c Normal file
View File

@ -0,0 +1,67 @@
#include "driver/i2c.h"
#include "esp_log.h"
#include "display.h"
#define DISP_ADDR 0x70
#define I2C_PORT I2C_NUM_0
// Tabela de segmentos para 09
static const uint8_t segtbl[10] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
void display_init(void)
{
// Oscillator ON
uint8_t cmd1 = 0x21;
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, &cmd1, 1, 20 / portTICK_PERIOD_MS);
// Display ON, no blink
uint8_t cmd2 = 0x81;
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, &cmd2, 1, 20 / portTICK_PERIOD_MS);
// Brilho máximo
uint8_t cmd3 = 0xEF;
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, &cmd3, 1, 20 / portTICK_PERIOD_MS);
display_clear();
}
void display_clear(void)
{
uint8_t buf[17] = {0};
buf[0] = 0x00;
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, buf, sizeof(buf), 20 / portTICK_PERIOD_MS);
}
void display_digit(int pos, uint8_t val)
{
if (pos < 0 || pos > 3) return;
if (val > 9) val = 0;
uint8_t buf[2];
buf[0] = pos * 2; // endereço interno do dígito
buf[1] = segtbl[val]; // segmentos da tabela
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, buf, 2, 20 / portTICK_PERIOD_MS);
}
void display_number(int num)
{
if (num < 0) num = 0;
if (num > 9999) num = 9999;
display_digit(3, num % 10);
display_digit(2, (num / 10) % 10);
display_digit(1, (num / 100) % 10);
display_digit(0, (num / 1000) % 10);
}

20
main/i2c_helper.c Normal file
View File

@ -0,0 +1,20 @@
#include "driver/i2c.h"
#define SDA_PIN 21
#define SCL_PIN 22
#define I2C_PORT I2C_NUM_0
void i2c_init(void)
{
i2c_config_t cfg = {
.mode = I2C_MODE_MASTER,
.sda_io_num = SDA_PIN,
.scl_io_num = SCL_PIN,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000
};
i2c_param_config(I2C_PORT, &cfg);
i2c_driver_install(I2C_PORT, cfg.mode, 0, 0, 0);
}

7
main/include/display.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
void display_init(void);
void display_clear(void);
void display_digit(int pos, uint8_t value);
void display_number(int num);

View File

@ -0,0 +1,3 @@
#pragma once
void i2c_init(void);

View File

@ -4,6 +4,7 @@
void led_all_on(uint8_t r, uint8_t g, uint8_t b); void led_all_on(uint8_t r, uint8_t g, uint8_t b);
void led_all_off(void); void led_all_off(void);
void led_anim_03(void);
void led_idle_animation(void); void led_idle_animation(void);
void led_jackpot_animation(void); void led_jackpot_animation(void);

6
main/include/premios.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <stdint.h>
extern uint16_t premios[60];
uint16_t premio_da_posicao(int pos);

View File

@ -4,6 +4,8 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include <string.h> #include <string.h>
#include "premios.h"
#define LED_PIN 18 // <-- CERTIFICA-TE disto #define LED_PIN 18 // <-- CERTIFICA-TE disto
#define RMT_RESOLUTION_HZ 10000000 // 10 MHz (1 tick = 0.1us) #define RMT_RESOLUTION_HZ 10000000 // 10 MHz (1 tick = 0.1us)
@ -113,16 +115,19 @@ int led_get_count(void)
{ {
return LED_COUNT; return LED_COUNT;
} }
void led_spin_to(uint16_t target, int min_spins, int max_spins, int base_delay_ms) void led_spin_to(uint16_t target, int min_spins, int max_spins, int base_delay_ms)
{ {
int n = LED_COUNT; int n = LED_COUNT;
if (min_spins < 1) min_spins = 1; if (min_spins < 1) min_spins = 1;
if (max_spins < min_spins) max_spins = min_spins; if (max_spins < min_spins) max_spins = min_spins;
// passos aleatórios entre min e max
int extra = 0; int extra = 0;
if (max_spins > min_spins) if (max_spins > min_spins)
extra = rand() % (max_spins - min_spins + 1); extra = rand() % (max_spins - min_spins + 1);
// número total de passos até ao LED final
int total_steps = (min_spins + extra) * n + (target % n); int total_steps = (min_spins + extra) * n + (target % n);
int delay = base_delay_ms; int delay = base_delay_ms;
@ -131,18 +136,62 @@ void led_spin_to(uint16_t target, int min_spins, int max_spins, int base_delay_m
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
if (i == pos) if (i == pos)
led_set_pixel(i, 0, 40, 0); // verde fraco no cursor led_set_pixel(i, 0, 40, 0); // cursor verde
else else
led_set_pixel(i, 0, 0, 0); led_set_pixel(i, 0, 0, 0);
} }
led_show(); led_show();
// aceleração
if (step < total_steps / 3 && delay > 3) if (step < total_steps / 3 && delay > 3)
delay--; delay--;
// desaceleração
else if (step > (2 * total_steps) / 3) else if (step > (2 * total_steps) / 3)
delay++; delay++;
vTaskDelay(pdMS_TO_TICKS(delay)); vTaskDelay(pdMS_TO_TICKS(delay));
} }
// =======================================
// POSIÇÃO FINAL
// =======================================
int pos_final = total_steps % n;
// LED final destacado
led_set_pixel(pos_final, 0, 60, 0);
led_show();
vTaskDelay(pdMS_TO_TICKS(200));
// =======================================
// PRÉMIO FINAL
// =======================================
uint16_t premio = premio_da_posicao(pos_final);
if (premio > 0) {
// piscar o LED que deu prémio
for (int k = 0; k < 8; k++) {
if (k & 1)
led_set_pixel(pos_final, 0, 0, 0);
else
led_set_pixel(pos_final, 0, 0, 60); // azul prémio
led_show();
vTaskDelay(pdMS_TO_TICKS(120));
}
} else {
// sem prémio → pisca vermelho suave
for (int k = 0; k < 4; k++) {
if (k & 1)
led_set_pixel(pos_final, 0, 0, 0);
else
led_set_pixel(pos_final, 40, 0, 0);
led_show();
vTaskDelay(pdMS_TO_TICKS(120));
}
}
// (aqui no futuro vais mandar MQTT do prémio)
} }

View File

@ -5,6 +5,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include "mqtt_comandos.h" #include "mqtt_comandos.h"
#include "premios.h"
void led_all_on(uint8_t r, uint8_t g, uint8_t b) void led_all_on(uint8_t r, uint8_t g, uint8_t b)
@ -115,3 +116,60 @@ void led_clock_animation(void)
vTaskDelay(pdMS_TO_TICKS(200)); vTaskDelay(pdMS_TO_TICKS(200));
} }
void led_anim_03(void)
{
static int left = 0;
static int right = LED_COUNT - 1;
static bool meet = false;
int n = LED_COUNT;
// ------- Lista de prémios -------
// coloca as posições reais depois
static const int premios[] = { 3, 8, 15, 22, 31, 40, 47, 53 };
static const int total_premios = sizeof(premios) / sizeof(premios[0]);
// limpar tudo primeiro
led_clear();
if (!meet) {
// acende esquerda e direita
led_set_pixel(left, 0, 40, 0); // verde
led_set_pixel(right, 0, 40, 0);
left++;
right--;
// encontraram-se?
if (left >= right) {
meet = true;
}
}
else {
// ---- PISCAR PRÉMIOS ----
static bool on = false;
on = !on;
for (int i = 0; i < total_premios; i++) {
int p = premios[i] % n;
if (on)
led_set_pixel(p, 0, 0, 60); // azul forte
else
led_set_pixel(p, 0, 0, 10); // azul fraco
}
// durante alguns ciclos pisca antes de resetar
static int count = 0;
count++;
if (count > 20) { // ajusta aqui a duração do piscar
count = 0;
meet = false;
left = 0;
right = n - 1;
}
}
led_show();
vTaskDelay(pdMS_TO_TICKS(50));
}

View File

@ -29,6 +29,9 @@ void led_task(void *pv)
// jackpot non-blocking // jackpot non-blocking
led_jackpot_animation(); led_jackpot_animation();
break; break;
case 3:
led_anim_03(); // <-- AGORA É A PRINCIPAL
break;
default: default:
// fallback seguro // fallback seguro

View File

@ -27,6 +27,14 @@
#include "creditos.h" #include "creditos.h"
#include "led_task.h" #include "led_task.h"
#include "driver/i2c.h"
#include "i2c_helper.h"
#include "display.h"
#define SDA_PIN 21
#define SCL_PIN 22
#define I2C_PORT I2C_NUM_0
static const char *TAG = "APP"; static const char *TAG = "APP";
static uint32_t segundos = 0; static uint32_t segundos = 0;
static bool wifi_ready = false; static bool wifi_ready = false;
@ -87,6 +95,45 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
} }
// Configuração básica do I2C
i2c_config_t cfg = {
.mode = I2C_MODE_MASTER,
.sda_io_num = SDA_PIN,
.scl_io_num = SCL_PIN,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000
};
void ht16_init()
{
uint8_t cmd1 = 0x21; // liga oscilador
i2c_master_write_to_device(I2C_PORT, 0x70, &cmd1, 1, 10 / portTICK_PERIOD_MS);
uint8_t cmd2 = 0x81; // display ON, sem piscar
i2c_master_write_to_device(I2C_PORT, 0x70, &cmd2, 1, 10 / portTICK_PERIOD_MS);
uint8_t cmd3 = 0xEF; // brilho máximo
i2c_master_write_to_device(I2C_PORT, 0x70, &cmd3, 1, 10 / portTICK_PERIOD_MS);
}
void ht16_test()
{
uint8_t buf[17] = {0};
buf[0] = 0x00; // endereço inicial
buf[7] = 0b0111111; // acende apenas o dígito 0
// (que mostra um "0" bonitinho)
// Os outros dígitos ficam a 0 = apagados
i2c_master_write_to_device(I2C_PORT, 0x70, buf, sizeof(buf), 20 / portTICK_PERIOD_MS);
}
// ============================ // ============================
// MAIN // MAIN
// ============================ // ============================
@ -115,6 +162,15 @@ void app_main(void) {
animacao_load(); animacao_load();
ESP_LOGI("ANIM", "🎨 Animação carregada = %u", animacao); ESP_LOGI("ANIM", "🎨 Animação carregada = %u", animacao);
//i2c scan
i2c_init(); // <- o helper entra aqui
display_init(); // <- inicializa o HT16K33
display_number(1234);
// -------- Wi-Fi -------- // -------- Wi-Fi --------
wifi_config_t cfg; wifi_config_t cfg;
bool have_creds = false; bool have_creds = false;

29
main/premios.c Normal file
View File

@ -0,0 +1,29 @@
#include "premios.h"
// ===============================
// Tabela de prémios (60 LEDs)
// ===============================
// 0 = sem prémio
// Aqui só mete valores de teste. Depois ajustamos tudo bonito.
//
uint16_t premios[60] = {
0, 0, 5, 0, 10, 0, 0, 20,
0, 0, 50, 0, 0,100, 0, 0,
5, 0, 0, 10, 0, 0,200, 0,
0, 0, 20, 0, 0, 0, 50, 0,
0, 0, 5, 0, 0,100, 0, 0,
10, 0, 0, 0, 20, 0, 0, 50,
0, 0,100, 0, 0,200, 0, 0
};
// ============================================
// Retorna o prémio associado a uma posição
// ============================================
uint16_t premio_da_posicao(int pos)
{
if (pos < 0 || pos >= 60)
return 0;
return premios[pos];
}