Refactor display driver: cleanup segment defines and headers
This commit is contained in:
parent
bf1499b73d
commit
419be3b929
510
main/display.c
510
main/display.c
@ -1,73 +1,54 @@
|
|||||||
#include "driver/i2c.h"
|
#include "driver/i2c.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define DISP_ADDR 0x70
|
|
||||||
#define I2C_PORT I2C_NUM_0
|
#define I2C_PORT I2C_NUM_0
|
||||||
|
|
||||||
|
// Endereços reais
|
||||||
|
#define DISP_TOP_ADDR 0x71 // display superior
|
||||||
|
#define DISP_BOTTOM_ADDR 0x70 // display inferior
|
||||||
|
static uint16_t rotate180(uint16_t m);
|
||||||
|
|
||||||
const char *TAG = "DISPLAY";
|
const char *TAG = "DISPLAY";
|
||||||
|
|
||||||
// Mapa de bits real do teu módulo
|
// =======================================================
|
||||||
#define SEG_A (1 << 0) // topo
|
// MAPA DE SEGMENTOS (mantido igual ao teu)
|
||||||
#define SEG_B (1 << 1) // cima direita
|
// =======================================================
|
||||||
#define SEG_C (1 << 2) // baixo direita
|
|
||||||
#define SEG_D (1 << 3) // baixo
|
|
||||||
#define SEG_E (1 << 4) // baixo esquerda
|
|
||||||
#define SEG_F (1 << 5) // cima esquerda
|
|
||||||
|
|
||||||
// verticais do meio
|
#define SEG_A (1 << 0)
|
||||||
#define SEG_ML (1 << 6) // meio-esquerda
|
#define SEG_B (1 << 1)
|
||||||
#define SEG_MR (1 << 7) // meio-direita
|
#define SEG_C (1 << 2)
|
||||||
|
#define SEG_D (1 << 3)
|
||||||
|
#define SEG_E (1 << 4)
|
||||||
|
#define SEG_F (1 << 5)
|
||||||
|
|
||||||
// parte alfanumérica (topo)
|
#define SEG_ML (1 << 6)
|
||||||
#define SEG_TL (1 << 8) // top-left extra
|
#define SEG_MR (1 << 7)
|
||||||
#define SEG_TM (1 << 9) // top-middle (horizontal)
|
|
||||||
#define SEG_TR (1 << 10) // top-right extra
|
|
||||||
|
|
||||||
// parte alfanumérica (baixo)
|
#define SEG_TL (1 << 8)
|
||||||
#define SEG_BL (1 << 11) // bottom-left extra
|
#define SEG_TM (1 << 9)
|
||||||
#define SEG_BM (1 << 12) // bottom-middle (horizontal)
|
#define SEG_TR (1 << 10)
|
||||||
#define SEG_BR (1 << 13) // bottom-right extra
|
|
||||||
|
|
||||||
#define SEG_DP (1 << 14) // ponto decimal
|
#define SEG_BL (1 << 11)
|
||||||
|
#define SEG_BM (1 << 12)
|
||||||
|
#define SEG_BR (1 << 13)
|
||||||
|
|
||||||
|
#define SEG_DP (1 << 14)
|
||||||
|
|
||||||
// "segmento do meio" clássico (g) = as duas barrinhas
|
|
||||||
#define SEG_G (SEG_ML | SEG_MR)
|
#define SEG_G (SEG_ML | SEG_MR)
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// FUNÇÕES GENÉRICAS PARA QUALQUER DISPLAY
|
||||||
|
// =======================================================
|
||||||
|
|
||||||
|
static void disp_send_cmd(uint8_t addr, uint8_t cmd)
|
||||||
// ------------------------------
|
|
||||||
// DISPLAY INIT
|
|
||||||
// ------------------------------
|
|
||||||
void display_init(void)
|
|
||||||
{
|
{
|
||||||
uint8_t cmd1 = 0x21; // oscillator ON
|
i2c_master_write_to_device(I2C_PORT, addr, &cmd, 1, 20 / portTICK_PERIOD_MS);
|
||||||
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, &cmd1, 1, 20 / portTICK_PERIOD_MS);
|
|
||||||
|
|
||||||
uint8_t cmd2 = 0x81; // display ON, blink OFF
|
|
||||||
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, &cmd2, 1, 20 / portTICK_PERIOD_MS);
|
|
||||||
|
|
||||||
uint8_t cmd3 = 0xEF; // brightness
|
|
||||||
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, &cmd3, 1, 20 / portTICK_PERIOD_MS);
|
|
||||||
|
|
||||||
display_clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
static void disp_raw(uint8_t addr, int pos, uint16_t mask)
|
||||||
// CLEAR DISPLAY
|
|
||||||
// ------------------------------
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
|
||||||
// RAW WRITE — 14 segmentos (cada dígito = 16 bits)
|
|
||||||
// --------------------------------------------------------
|
|
||||||
void display_raw(int pos, uint16_t mask)
|
|
||||||
{
|
{
|
||||||
if (pos < 0 || pos > 3) return;
|
if (pos < 0 || pos > 3) return;
|
||||||
|
|
||||||
@ -76,20 +57,119 @@ void display_raw(int pos, uint16_t mask)
|
|||||||
buf[1] = mask & 0xFF;
|
buf[1] = mask & 0xFF;
|
||||||
buf[2] = (mask >> 8) & 0xFF;
|
buf[2] = (mask >> 8) & 0xFF;
|
||||||
|
|
||||||
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, buf, 3, 20 / portTICK_PERIOD_MS);
|
i2c_master_write_to_device(I2C_PORT, addr, buf, 3, 20 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------
|
static void disp_clear(uint8_t addr)
|
||||||
// Tabela alfanumérica 14 segmentos
|
{
|
||||||
// (corrigido: H com os 2 segmentos horizontais g1/g2)
|
uint8_t buf[17] = {0};
|
||||||
// --------------------------------------------------------
|
buf[0] = 0x00;
|
||||||
|
i2c_master_write_to_device(I2C_PORT, addr, buf, sizeof(buf), 20 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// INIT PARA OS DOIS DISPLAYS (TOP 0x71 | BOTTOM 0x70)
|
||||||
|
// =======================================================
|
||||||
|
|
||||||
|
void display_init(void)
|
||||||
|
{
|
||||||
|
uint8_t cmd1 = 0x21; // oscillator ON
|
||||||
|
uint8_t cmd2 = 0x81; // display ON, blink OFF
|
||||||
|
uint8_t cmd3 = 0xEF; // brightness MAX
|
||||||
|
|
||||||
|
// TOP
|
||||||
|
disp_send_cmd(DISP_TOP_ADDR, cmd1);
|
||||||
|
disp_send_cmd(DISP_TOP_ADDR, cmd2);
|
||||||
|
disp_send_cmd(DISP_TOP_ADDR, cmd3);
|
||||||
|
disp_clear(DISP_TOP_ADDR);
|
||||||
|
|
||||||
|
// BOTTOM
|
||||||
|
disp_send_cmd(DISP_BOTTOM_ADDR, cmd1);
|
||||||
|
disp_send_cmd(DISP_BOTTOM_ADDR, cmd2);
|
||||||
|
disp_send_cmd(DISP_BOTTOM_ADDR, cmd3);
|
||||||
|
disp_clear(DISP_BOTTOM_ADDR);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "📟 Displays inicializados: TOP=0x71 BOTTOM=0x70");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// RAW PARA TOP E BOTTOM
|
||||||
|
// =======================================================
|
||||||
|
void display_raw_top(int pos, uint16_t mask)
|
||||||
|
{
|
||||||
|
int p = 3 - pos; // inverter ordem dos dígitos
|
||||||
|
uint16_t m = rotate180(mask); // rodar segmentos
|
||||||
|
disp_raw(DISP_TOP_ADDR, p, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void display_raw_bottom(int pos, uint16_t mask)
|
||||||
|
{
|
||||||
|
disp_raw(DISP_BOTTOM_ADDR, pos, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_clear_top(void)
|
||||||
|
{
|
||||||
|
disp_clear(DISP_TOP_ADDR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_clear_bottom(void)
|
||||||
|
{
|
||||||
|
disp_clear(DISP_BOTTOM_ADDR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
// ROTATE 180 para 14 segmentos REAL
|
||||||
|
// (mapa correto para o teu HT16K33)
|
||||||
|
// =====================
|
||||||
|
static uint16_t rotate180(uint16_t m)
|
||||||
|
{
|
||||||
|
uint16_t r = 0;
|
||||||
|
|
||||||
|
// A (topo) <-> D (baixo)
|
||||||
|
if (m & SEG_A) r |= SEG_D;
|
||||||
|
if (m & SEG_D) r |= SEG_A;
|
||||||
|
|
||||||
|
// B (top-right) <-> E (bottom-left)
|
||||||
|
if (m & SEG_B) r |= SEG_E;
|
||||||
|
if (m & SEG_E) r |= SEG_B;
|
||||||
|
|
||||||
|
// C (bottom-right) <-> F (top-left)
|
||||||
|
if (m & SEG_C) r |= SEG_F;
|
||||||
|
if (m & SEG_F) r |= SEG_C;
|
||||||
|
|
||||||
|
// Meio vertical ML ↔ MR
|
||||||
|
if (m & SEG_ML) r |= SEG_MR;
|
||||||
|
if (m & SEG_MR) r |= SEG_ML;
|
||||||
|
|
||||||
|
// Alfanuméricos topo TL/TM/TR ↔ BL/BM/BR
|
||||||
|
if (m & SEG_TL) r |= SEG_BL;
|
||||||
|
if (m & SEG_BL) r |= SEG_TL;
|
||||||
|
|
||||||
|
if (m & SEG_TM) r |= SEG_BM;
|
||||||
|
if (m & SEG_BM) r |= SEG_TM;
|
||||||
|
|
||||||
|
if (m & SEG_TR) r |= SEG_BR;
|
||||||
|
if (m & SEG_BR) r |= SEG_TR;
|
||||||
|
|
||||||
|
// DP é DP (ponto)
|
||||||
|
if (m & SEG_DP) r |= SEG_DP;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// CHARSET — mantido EXACTAMENTE como o teu
|
||||||
|
// =======================================================
|
||||||
|
|
||||||
static uint16_t charset(char c)
|
static uint16_t charset(char c)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
//------------------------------------------------------
|
// NÚMEROS
|
||||||
// NÚMEROS (PERFEITOS)
|
|
||||||
//------------------------------------------------------
|
|
||||||
case '0': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
|
case '0': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
|
||||||
case '1': return SEG_B | SEG_C;
|
case '1': return SEG_B | SEG_C;
|
||||||
case '2': return SEG_A | SEG_B | SEG_G | SEG_E | SEG_D;
|
case '2': return SEG_A | SEG_B | SEG_G | SEG_E | SEG_D;
|
||||||
@ -101,242 +181,139 @@ static uint16_t charset(char c)
|
|||||||
case '8': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
|
case '8': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
|
||||||
case '9': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G;
|
case '9': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G;
|
||||||
|
|
||||||
//------------------------------------------------------
|
// LETRAS COMPLETAS (mantidas)
|
||||||
// LETRAS A-Z (todas as possíveis)
|
case 'A': case 'a': return SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G;
|
||||||
//------------------------------------------------------
|
case 'B': case 'b': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
|
||||||
|
case 'C': case 'c': return SEG_A | SEG_F | SEG_E | SEG_D;
|
||||||
|
case 'D': case 'd': return SEG_B | SEG_C | SEG_D | SEG_E | SEG_G;
|
||||||
|
case 'E': case 'e': return SEG_A | SEG_F | SEG_G | SEG_E | SEG_D;
|
||||||
|
case 'F': case 'f': return SEG_A | SEG_F | SEG_G | SEG_E;
|
||||||
|
case 'G': case 'g': return SEG_A | SEG_F | SEG_E | SEG_D | SEG_C | SEG_G;
|
||||||
|
case 'H': case 'h': return SEG_F | SEG_E | SEG_G | SEG_B | SEG_C;
|
||||||
|
case 'I': case 'i': return SEG_B | SEG_C;
|
||||||
|
case 'J': case 'j': return SEG_B | SEG_C | SEG_D;
|
||||||
|
case 'K': case 'k': return SEG_F | SEG_E | SEG_G | SEG_TR | SEG_BR;
|
||||||
|
case 'L': case 'l': return SEG_F | SEG_E | SEG_D;
|
||||||
|
case 'M': case 'm': return SEG_F | SEG_E | SEG_TL | SEG_TR | SEG_B | SEG_C;
|
||||||
|
case 'N': case 'n': return SEG_F | SEG_E | SEG_TL | SEG_BR | SEG_C | SEG_B;
|
||||||
|
case 'O': case 'o': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
|
||||||
|
case 'P': case 'p': return SEG_A | SEG_B | SEG_F | SEG_G | SEG_E;
|
||||||
|
case 'Q': case 'q': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_BR;
|
||||||
|
case 'R': case 'r': return SEG_A | SEG_B | SEG_F | SEG_G | SEG_E | SEG_BR;
|
||||||
|
case 'S': case 's': return SEG_A | SEG_F | SEG_G | SEG_C | SEG_D;
|
||||||
|
case 'T': case 't': return SEG_A | SEG_TM | SEG_BR;
|
||||||
|
case 'U': case 'u': return SEG_F | SEG_E | SEG_D | SEG_C | SEG_B;
|
||||||
|
case 'V': case 'v': return SEG_F | SEG_E | SEG_D | SEG_B | SEG_TR;
|
||||||
|
case 'W': case 'w': return SEG_F | SEG_E | SEG_D | SEG_C | SEG_B | SEG_BR | SEG_TR;
|
||||||
|
case 'X': case 'x': return SEG_TL | SEG_TR | SEG_ML | SEG_MR | SEG_BL | SEG_BR;
|
||||||
|
case 'Y': case 'y': return SEG_F | SEG_B | SEG_G | SEG_C | SEG_D;
|
||||||
|
case 'Z': case 'z': return SEG_A | SEG_TR | SEG_G | SEG_BL | SEG_D;
|
||||||
|
|
||||||
// A
|
// símbolos
|
||||||
case 'A': case 'a':
|
case '-': return SEG_G;
|
||||||
return SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G;
|
case '.': return SEG_DP;
|
||||||
|
case '_': return SEG_D;
|
||||||
|
case ' ': return 0;
|
||||||
|
|
||||||
// B (tipo “8” mais quadrado)
|
default: return 0;
|
||||||
case 'B': case 'b':
|
|
||||||
return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
|
|
||||||
|
|
||||||
// C
|
|
||||||
case 'C': case 'c':
|
|
||||||
return SEG_A | SEG_F | SEG_E | SEG_D;
|
|
||||||
|
|
||||||
// D
|
|
||||||
case 'D': case 'd':
|
|
||||||
return SEG_B | SEG_C | SEG_D | SEG_E | SEG_G;
|
|
||||||
|
|
||||||
// E
|
|
||||||
case 'E': case 'e':
|
|
||||||
return SEG_A | SEG_F | SEG_G | SEG_E | SEG_D;
|
|
||||||
|
|
||||||
// F
|
|
||||||
case 'F': case 'f':
|
|
||||||
return SEG_A | SEG_F | SEG_G | SEG_E;
|
|
||||||
|
|
||||||
// G
|
|
||||||
case 'G': case 'g':
|
|
||||||
return SEG_A | SEG_F | SEG_E | SEG_D | SEG_C | SEG_G;
|
|
||||||
|
|
||||||
// H
|
|
||||||
case 'H': case 'h':
|
|
||||||
return SEG_F | SEG_E | SEG_G | SEG_B | SEG_C;
|
|
||||||
|
|
||||||
// I
|
|
||||||
case 'I': case 'i':
|
|
||||||
return SEG_B | SEG_C;
|
|
||||||
|
|
||||||
// J
|
|
||||||
case 'J': case 'j':
|
|
||||||
return SEG_B | SEG_C | SEG_D;
|
|
||||||
|
|
||||||
// K (usa diagonais internas TL/TR + ML/MR)
|
|
||||||
case 'K': case 'k':
|
|
||||||
return SEG_F | SEG_E | SEG_G | SEG_TR | SEG_BR;
|
|
||||||
|
|
||||||
// L
|
|
||||||
case 'L': case 'l':
|
|
||||||
return SEG_F | SEG_E | SEG_D;
|
|
||||||
|
|
||||||
// M
|
|
||||||
case 'M': case 'm':
|
|
||||||
return SEG_F | SEG_E | SEG_TL | SEG_TR | SEG_B | SEG_C;
|
|
||||||
|
|
||||||
// N
|
|
||||||
case 'N': case 'n':
|
|
||||||
return SEG_F | SEG_E | SEG_TL | SEG_BR | SEG_C | SEG_B;
|
|
||||||
|
|
||||||
// O
|
|
||||||
case 'O': case 'o':
|
|
||||||
return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
|
|
||||||
|
|
||||||
// P
|
|
||||||
case 'P': case 'p':
|
|
||||||
return SEG_A | SEG_B | SEG_F | SEG_G | SEG_E;
|
|
||||||
|
|
||||||
// Q (tipo O + diagonal extra)
|
|
||||||
case 'Q': case 'q':
|
|
||||||
return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_BR;
|
|
||||||
|
|
||||||
// R
|
|
||||||
case 'R': case 'r':
|
|
||||||
return SEG_A | SEG_B | SEG_F | SEG_G | SEG_E | SEG_BR;
|
|
||||||
|
|
||||||
// S
|
|
||||||
case 'S': case 's':
|
|
||||||
return SEG_A | SEG_F | SEG_G | SEG_C | SEG_D;
|
|
||||||
|
|
||||||
// T
|
|
||||||
case 'T': case 't':
|
|
||||||
return SEG_A | SEG_TM | SEG_BR;
|
|
||||||
|
|
||||||
// U
|
|
||||||
case 'U': case 'u':
|
|
||||||
return SEG_F | SEG_E | SEG_D | SEG_C | SEG_B;
|
|
||||||
|
|
||||||
// V
|
|
||||||
case 'V': case 'v':
|
|
||||||
return SEG_F | SEG_E | SEG_D | SEG_B | SEG_TR;
|
|
||||||
|
|
||||||
// W
|
|
||||||
case 'W': case 'w':
|
|
||||||
return SEG_F | SEG_E | SEG_D | SEG_C | SEG_B | SEG_BR | SEG_TR;
|
|
||||||
|
|
||||||
// X
|
|
||||||
case 'X': case 'x':
|
|
||||||
return SEG_TL | SEG_TR | SEG_ML | SEG_MR | SEG_BL | SEG_BR;
|
|
||||||
|
|
||||||
// Y
|
|
||||||
case 'Y': case 'y':
|
|
||||||
return SEG_F | SEG_B | SEG_G | SEG_C | SEG_D;
|
|
||||||
|
|
||||||
// Z
|
|
||||||
case 'Z': case 'z':
|
|
||||||
return SEG_A | SEG_TR | SEG_G | SEG_BL | SEG_D;
|
|
||||||
|
|
||||||
//------------------------------------------------------
|
|
||||||
// SÍMBOLOS ESPECIAIS
|
|
||||||
//------------------------------------------------------
|
|
||||||
|
|
||||||
case '-':
|
|
||||||
return SEG_G;
|
|
||||||
|
|
||||||
case '_':
|
|
||||||
return SEG_D;
|
|
||||||
|
|
||||||
case '=':
|
|
||||||
return SEG_G | SEG_BM;
|
|
||||||
|
|
||||||
case '*':
|
|
||||||
return SEG_TM | SEG_BM | SEG_ML | SEG_MR;
|
|
||||||
|
|
||||||
case '/':
|
|
||||||
return SEG_TR | SEG_BL;
|
|
||||||
|
|
||||||
case '\\':
|
|
||||||
return SEG_TL | SEG_BR;
|
|
||||||
|
|
||||||
case '|':
|
|
||||||
return SEG_B | SEG_C;
|
|
||||||
|
|
||||||
case ':':
|
|
||||||
return SEG_DP | SEG_BR;
|
|
||||||
|
|
||||||
case '.':
|
|
||||||
return SEG_DP;
|
|
||||||
|
|
||||||
case '\'':
|
|
||||||
return SEG_TR;
|
|
||||||
|
|
||||||
case '"':
|
|
||||||
return SEG_TR | SEG_TL;
|
|
||||||
|
|
||||||
case ' ':
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0; // desconhecido → apagado
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// =======================================================
|
||||||
// display_char()
|
// DISPLAY CARACTER / TEXTO
|
||||||
// --------------------------------------------------------
|
// =======================================================
|
||||||
void display_char(int pos, char c)
|
|
||||||
|
void display_char_top(int pos, char c)
|
||||||
{
|
{
|
||||||
uint16_t mask = charset(c);
|
display_raw_top(pos, charset(c));
|
||||||
display_raw(pos, mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------
|
void display_char_bottom(int pos, char c)
|
||||||
// display_text() (4 caracteres)
|
|
||||||
// --------------------------------------------------------
|
|
||||||
void display_text(const char *txt)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; i++)
|
disp_raw(DISP_BOTTOM_ADDR, pos, charset(c));
|
||||||
{
|
}
|
||||||
char c = txt[i];
|
|
||||||
if (c == 0) c = ' ';
|
void display_text_top(const char *txt)
|
||||||
display_char(i, c);
|
{
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
char c = txt[i] ? txt[i] : ' ';
|
||||||
|
display_char_top(i, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------
|
|
||||||
// display_number()
|
void display_text_bottom(const char *txt)
|
||||||
// Mantida para compatibilidade com 7-segment
|
{
|
||||||
// --------------------------------------------------------
|
for (int i = 0; i < 4; i++) {
|
||||||
// Dígitos 0–9 usando os segmentos definidos acima
|
char c = txt[i] ? txt[i] : ' ';
|
||||||
static const uint16_t digit_mask[10] = {
|
display_char_bottom(i, c);
|
||||||
// 0: a b c d e f
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// DISPLAY DE NÚMEROS (igual ao teu)
|
||||||
|
// =======================================================
|
||||||
|
|
||||||
|
static const uint16_t digit_mask[10] =
|
||||||
|
{
|
||||||
[0] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,
|
[0] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,
|
||||||
|
|
||||||
// 1: b c
|
|
||||||
[1] = SEG_B | SEG_C,
|
[1] = SEG_B | SEG_C,
|
||||||
|
|
||||||
// 2: a b g e d
|
|
||||||
[2] = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D,
|
[2] = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D,
|
||||||
|
|
||||||
// 3: a b g c d
|
|
||||||
[3] = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D,
|
[3] = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D,
|
||||||
|
|
||||||
// 4: f g b c
|
|
||||||
[4] = SEG_F | SEG_G | SEG_B | SEG_C,
|
[4] = SEG_F | SEG_G | SEG_B | SEG_C,
|
||||||
|
|
||||||
// 5: a f g c d
|
|
||||||
[5] = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D,
|
[5] = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D,
|
||||||
|
|
||||||
// 6: a f g e d c
|
|
||||||
[6] = SEG_A | SEG_F | SEG_G | SEG_E | SEG_D | SEG_C,
|
[6] = SEG_A | SEG_F | SEG_G | SEG_E | SEG_D | SEG_C,
|
||||||
|
|
||||||
// 7: a b c
|
|
||||||
[7] = SEG_A | SEG_B | SEG_C,
|
[7] = SEG_A | SEG_B | SEG_C,
|
||||||
|
|
||||||
// 8: tudo
|
|
||||||
[8] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,
|
[8] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,
|
||||||
|
|
||||||
// 9: a b c d f g
|
|
||||||
[9] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,
|
[9] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,
|
||||||
};
|
};
|
||||||
|
|
||||||
void display_digit(int pos, uint8_t val)
|
void display_digit_top(int pos, uint8_t val)
|
||||||
{
|
{
|
||||||
if (pos < 0 || pos > 3) return;
|
|
||||||
if (val > 9) val = 0;
|
if (val > 9) val = 0;
|
||||||
|
display_raw_top(pos, digit_mask[val]);
|
||||||
uint16_t mask = digit_mask[val];
|
|
||||||
display_raw(pos, mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_number(int num)
|
|
||||||
|
void display_digit_bottom(int pos, uint8_t val)
|
||||||
|
{
|
||||||
|
if (val > 9) val = 0;
|
||||||
|
disp_raw(DISP_BOTTOM_ADDR, pos, digit_mask[val]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_number_top(int num)
|
||||||
{
|
{
|
||||||
if (num < 0) num = 0;
|
if (num < 0) num = 0;
|
||||||
if (num > 9999) num = 9999;
|
if (num > 9999) num = 9999;
|
||||||
|
|
||||||
display_digit(3, num % 10);
|
display_digit_top(3, num % 10);
|
||||||
display_digit(2, (num / 10) % 10);
|
display_digit_top(2, (num / 10) % 10);
|
||||||
display_digit(1, (num / 100) % 10);
|
display_digit_top(1, (num / 100) % 10);
|
||||||
display_digit(0, (num / 1000) % 10);
|
display_digit_top(0, (num / 1000) % 10);
|
||||||
}
|
}
|
||||||
void display_set_time(int horas, int minutos)
|
|
||||||
|
|
||||||
|
void display_number_bottom(int num)
|
||||||
{
|
{
|
||||||
if (horas < 0) horas = 0;
|
if (num < 0) num = 0;
|
||||||
if (horas > 99) horas = 99;
|
if (num > 9999) num = 9999;
|
||||||
|
|
||||||
|
display_digit_bottom(3, num % 10);
|
||||||
|
display_digit_bottom(2, (num/10) % 10);
|
||||||
|
display_digit_bottom(1, (num/100) % 10);
|
||||||
|
display_digit_bottom(0, (num/1000) % 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// display_set_time() — mantém SEG_DP no sítio certo
|
||||||
|
// =======================================================
|
||||||
|
void display_set_time_top(int horas, int minutos)
|
||||||
|
{
|
||||||
|
if (horas < 0) horas = 0;
|
||||||
|
if (horas > 99) horas = 99;
|
||||||
if (minutos < 0) minutos = 0;
|
if (minutos < 0) minutos = 0;
|
||||||
if (minutos > 59) minutos = 59;
|
if (minutos > 59) minutos = 59;
|
||||||
|
|
||||||
@ -345,15 +322,10 @@ void display_set_time(int horas, int minutos)
|
|||||||
int m1 = minutos / 10;
|
int m1 = minutos / 10;
|
||||||
int m2 = minutos % 10;
|
int m2 = minutos % 10;
|
||||||
|
|
||||||
uint16_t dig1 = digit_mask[h2] | SEG_DP; //dot betwen hours
|
uint16_t mid = digit_mask[h2] | SEG_DP;
|
||||||
|
|
||||||
display_digit(0, h1);
|
display_digit_top(0, h1);
|
||||||
display_raw(1, dig1);
|
display_raw_top(1, mid);
|
||||||
display_digit(2, m1);
|
display_digit_top(2, m1);
|
||||||
display_digit(3, m2);
|
display_digit_top(3, m2);
|
||||||
}
|
|
||||||
|
|
||||||
void display_debug_segment(uint16_t bitmask)
|
|
||||||
{
|
|
||||||
display_raw(0, bitmask); // acende só o dígito 0
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,48 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// ENDEREÇOS I2C (definidos no .c)
|
||||||
|
// =======================================================
|
||||||
|
// TOP = 0x71
|
||||||
|
// BOTTOM = 0x70
|
||||||
|
|
||||||
|
// Inicialização dos dois displays
|
||||||
void display_init(void);
|
void display_init(void);
|
||||||
void display_clear(void);
|
|
||||||
void display_raw(int pos, uint16_t mask);
|
// =======================================================
|
||||||
void display_char(int pos, char c);
|
// RAW ACCESS (usa 16 bits de segmentos)
|
||||||
void display_text(const char *txt);
|
// =======================================================
|
||||||
void display_digit(int pos, uint8_t val);
|
void display_raw_top(int pos, uint16_t mask);
|
||||||
void display_number(int num);
|
void display_raw_bottom(int pos, uint16_t mask);
|
||||||
void display_set_time(int horas, int minutos);
|
|
||||||
void display_debug_segment(uint16_t bitmask);
|
void display_clear_top(void);
|
||||||
|
void display_clear_bottom(void);
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// TEXTO E CARACTERES
|
||||||
|
// =======================================================
|
||||||
|
void display_char_top(int pos, char c);
|
||||||
|
void display_char_bottom(int pos, char c);
|
||||||
|
|
||||||
|
void display_text_top(const char *txt); // 4 chars
|
||||||
|
void display_text_bottom(const char *txt); // 4 chars
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// NÚMEROS (0–9999)
|
||||||
|
// =======================================================
|
||||||
|
void display_digit_top(int pos, uint8_t val);
|
||||||
|
void display_digit_bottom(int pos, uint8_t val);
|
||||||
|
|
||||||
|
void display_number_top(int num);
|
||||||
|
void display_number_bottom(int num);
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// RELÓGIO (HH:MM com DP entre horas)
|
||||||
|
// =======================================================
|
||||||
|
void display_set_time_top(int horas, int minutos);
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// DEBUG
|
||||||
|
// =======================================================
|
||||||
|
void display_debug_segment(uint16_t bitmask);
|
||||||
|
|||||||
@ -92,8 +92,9 @@ void led_clock_animation(void)
|
|||||||
int s = t.tm_sec;
|
int s = t.tm_sec;
|
||||||
|
|
||||||
// Mostrar HHMM no display (14-seg)
|
// Mostrar HHMM no display (14-seg)
|
||||||
display_set_time(h, m);
|
|
||||||
|
display_set_time_top(h, m);
|
||||||
|
|
||||||
// LED dos segundos em azul
|
// LED dos segundos em azul
|
||||||
led_clear(); // APAGA TUDO
|
led_clear(); // APAGA TUDO
|
||||||
|
|
||||||
|
|||||||
45
main/main.c
45
main/main.c
@ -136,6 +136,24 @@ void ht16_test()
|
|||||||
i2c_master_write_to_device(I2C_PORT, 0x70, buf, sizeof(buf), 20 / portTICK_PERIOD_MS);
|
i2c_master_write_to_device(I2C_PORT, 0x70, buf, sizeof(buf), 20 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void i2c_scan()
|
||||||
|
{
|
||||||
|
printf("\n--- A fazer scan ao I2C ---\n");
|
||||||
|
// --- SCAN I2C ---
|
||||||
|
for (uint8_t addr = 1; addr < 127; addr++) {
|
||||||
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||||
|
i2c_master_start(cmd);
|
||||||
|
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
|
||||||
|
i2c_master_stop(cmd);
|
||||||
|
|
||||||
|
esp_err_t r = i2c_master_cmd_begin(I2C_PORT, cmd, 20 / portTICK_PERIOD_MS);
|
||||||
|
i2c_cmd_link_delete(cmd);
|
||||||
|
|
||||||
|
if (r == ESP_OK) {
|
||||||
|
printf("ENCONTRADO I2C: 0x%02X\n", addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============================
|
// ============================
|
||||||
// MAIN
|
// MAIN
|
||||||
@ -166,33 +184,12 @@ void app_main(void) {
|
|||||||
ESP_LOGI("ANIM", "🎨 Animação carregada = %u", animacao);
|
ESP_LOGI("ANIM", "🎨 Animação carregada = %u", animacao);
|
||||||
|
|
||||||
|
|
||||||
//i2c scan
|
|
||||||
|
|
||||||
i2c_init(); // <- o helper entra aqui
|
i2c_init(); // <- o helper entra aqui
|
||||||
display_init(); // <- inicializa o HT16K33
|
display_init(); // <- inicializa o HT16K33
|
||||||
// display_text("INIT"); // ou display_number(0000)
|
i2c_scan();
|
||||||
/*display_number(8);
|
display_text_top("INIT");
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
display_number(4);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
display_number(7);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
display_number(2);
|
|
||||||
|
|
||||||
display_text("HELP");
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
display_text("Err ");
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));*/
|
|
||||||
display_text("C0dE");
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
|
||||||
display_text("0000");
|
|
||||||
/*
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
display_text("UP ");
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
display_text("rSt ");
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -308,14 +308,14 @@ void mqtt_comandos_handle(cJSON *root)
|
|||||||
|
|
||||||
else if (strcmp(c, "MENU_ON") == 0) {
|
else if (strcmp(c, "MENU_ON") == 0) {
|
||||||
ui_set_menu(MENU_MAIN);
|
ui_set_menu(MENU_MAIN);
|
||||||
display_text("MENU");
|
display_text_top("MENU");
|
||||||
ESP_LOGI(TAG, "📟 MENU ON");
|
ESP_LOGI(TAG, "📟 MENU ON");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(c, "MENU_OFF") == 0) {
|
else if (strcmp(c, "MENU_OFF") == 0) {
|
||||||
ui_set_menu(MENU_OFF);
|
ui_set_menu(MENU_OFF);
|
||||||
display_clear();
|
display_clear_top();
|
||||||
ESP_LOGI(TAG, "📟 MENU OFF");
|
ESP_LOGI(TAG, "📟 MENU OFF");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -333,7 +333,7 @@ void mqtt_comandos_handle(cJSON *root)
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(c, "DISP_TEST") == 0) {
|
else if (strcmp(c, "DISP_TEST") == 0) {
|
||||||
display_text("8888");
|
display_text_top("8888");
|
||||||
ESP_LOGI(TAG, "🖥️ TESTE DISPLAY");
|
ESP_LOGI(TAG, "🖥️ TESTE DISPLAY");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -367,7 +367,8 @@ void mqtt_comandos_handle(cJSON *root)
|
|||||||
eeprom_virtual_write_bin("percentagem", &p, 1);
|
eeprom_virtual_write_bin("percentagem", &p, 1);
|
||||||
|
|
||||||
// mostra no display
|
// mostra no display
|
||||||
display_number(p);
|
display_number_bottom(p);
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "🎯 Percentagem definida = %u%%", p);
|
ESP_LOGI(TAG, "🎯 Percentagem definida = %u%%", p);
|
||||||
|
|
||||||
|
|||||||
20
main/ui.c
20
main/ui.c
@ -25,11 +25,11 @@ void ui_menu_next(void)
|
|||||||
static void ui_render_menu(void)
|
static void ui_render_menu(void)
|
||||||
{
|
{
|
||||||
switch (g_menu) {
|
switch (g_menu) {
|
||||||
case MENU_MAIN: display_text("MENU"); break;
|
case MENU_MAIN: display_text_top("MENU"); break;
|
||||||
case MENU_PERC: display_text("PERC"); break;
|
case MENU_PERC: display_text_top("PERC"); break;
|
||||||
case MENU_READ: display_text("READ"); break;
|
case MENU_READ: display_text_top("READ"); break;
|
||||||
case MENU_TEST_LED: display_text("LEDS"); break;
|
case MENU_TEST_LED: display_text_top("LEDS"); break;
|
||||||
case MENU_TEST_DISP: display_text("DISP"); break;
|
case MENU_TEST_DISP: display_text_top("DISP"); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,12 +39,12 @@ void ui_menu_ok(void)
|
|||||||
switch (g_menu) {
|
switch (g_menu) {
|
||||||
case MENU_PERC:
|
case MENU_PERC:
|
||||||
// aqui no futuro: mostra % atual, muda via MQTT, etc
|
// aqui no futuro: mostra % atual, muda via MQTT, etc
|
||||||
display_text("70%");
|
display_text_top("70%");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MENU_READ:
|
case MENU_READ:
|
||||||
// aqui no futuro: mostra entradas/saídas da EEPROM
|
// aqui no futuro: mostra entradas/saídas da EEPROM
|
||||||
display_text("CNT ");
|
display_text_top("CNT ");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MENU_TEST_LED:
|
case MENU_TEST_LED:
|
||||||
@ -58,9 +58,9 @@ void ui_menu_ok(void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MENU_TEST_DISP:
|
case MENU_TEST_DISP:
|
||||||
display_text("8888");
|
display_text_top("8888");
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
display_clear();
|
display_clear_top();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -77,7 +77,7 @@ void ui_task(void *pv)
|
|||||||
struct tm t;
|
struct tm t;
|
||||||
localtime_r(&now, &t);
|
localtime_r(&now, &t);
|
||||||
|
|
||||||
display_set_time(t.tm_hour, t.tm_min);
|
display_set_time_top(t.tm_hour, t.tm_min);
|
||||||
// aqui podes chamar a animação da roda (se quiseres relógio visual)
|
// aqui podes chamar a animação da roda (se quiseres relógio visual)
|
||||||
} else {
|
} else {
|
||||||
ui_render_menu();
|
ui_render_menu();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user