com display
This commit is contained in:
parent
d5bbf905a4
commit
b7f03c7bf6
@ -12,7 +12,9 @@ idf_component_register(
|
||||
"eeprom_animacao.c"
|
||||
"led_task.c"
|
||||
"creditos.c"
|
||||
|
||||
"premios.c"
|
||||
"i2c_helper.c"
|
||||
"display.c"
|
||||
INCLUDE_DIRS
|
||||
"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_off(void);
|
||||
void led_anim_03(void);
|
||||
|
||||
void led_idle_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/task.h"
|
||||
#include <string.h>
|
||||
#include "premios.h"
|
||||
|
||||
|
||||
#define LED_PIN 18 // <-- CERTIFICA-TE disto
|
||||
#define RMT_RESOLUTION_HZ 10000000 // 10 MHz (1 tick = 0.1us)
|
||||
@ -113,16 +115,19 @@ int led_get_count(void)
|
||||
{
|
||||
return LED_COUNT;
|
||||
}
|
||||
|
||||
void led_spin_to(uint16_t target, int min_spins, int max_spins, int base_delay_ms)
|
||||
{
|
||||
int n = LED_COUNT;
|
||||
if (min_spins < 1) min_spins = 1;
|
||||
if (max_spins < min_spins) max_spins = min_spins;
|
||||
|
||||
// passos aleatórios entre min e max
|
||||
int extra = 0;
|
||||
if (max_spins > min_spins)
|
||||
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 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++) {
|
||||
if (i == pos)
|
||||
led_set_pixel(i, 0, 40, 0); // verde fraco no cursor
|
||||
led_set_pixel(i, 0, 40, 0); // cursor verde
|
||||
else
|
||||
led_set_pixel(i, 0, 0, 0);
|
||||
}
|
||||
|
||||
led_show();
|
||||
|
||||
// aceleração
|
||||
if (step < total_steps / 3 && delay > 3)
|
||||
delay--;
|
||||
|
||||
// desaceleração
|
||||
else if (step > (2 * total_steps) / 3)
|
||||
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 <time.h>
|
||||
#include "mqtt_comandos.h"
|
||||
#include "premios.h"
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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
|
||||
led_jackpot_animation();
|
||||
break;
|
||||
case 3:
|
||||
led_anim_03(); // <-- AGORA É A PRINCIPAL
|
||||
break;
|
||||
|
||||
default:
|
||||
// fallback seguro
|
||||
|
||||
56
main/main.c
56
main/main.c
@ -27,6 +27,14 @@
|
||||
#include "creditos.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 uint32_t segundos = 0;
|
||||
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
|
||||
// ============================
|
||||
@ -115,6 +162,15 @@ void app_main(void) {
|
||||
animacao_load();
|
||||
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 --------
|
||||
wifi_config_t cfg;
|
||||
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