com display
This commit is contained in:
parent
d5bbf905a4
commit
b7f03c7bf6
@ -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
67
main/display.c
Normal 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 0–9
|
||||||
|
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
20
main/i2c_helper.c
Normal 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
7
main/include/display.h
Normal 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);
|
||||||
3
main/include/i2c_helper.h
Normal file
3
main/include/i2c_helper.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void i2c_init(void);
|
||||||
@ -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
6
main/include/premios.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern uint16_t premios[60];
|
||||||
|
|
||||||
|
uint16_t premio_da_posicao(int pos);
|
||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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));
|
||||||
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
56
main/main.c
56
main/main.c
@ -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
29
main/premios.c
Normal 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];
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user