360 lines
9.4 KiB
C
360 lines
9.4 KiB
C
#include "driver/i2c.h"
|
||
#include "esp_log.h"
|
||
#include "display.h"
|
||
|
||
#define DISP_ADDR 0x70
|
||
#define I2C_PORT I2C_NUM_0
|
||
|
||
const char *TAG = "DISPLAY";
|
||
|
||
// Mapa de bits real do teu módulo
|
||
#define SEG_A (1 << 0) // topo
|
||
#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_ML (1 << 6) // meio-esquerda
|
||
#define SEG_MR (1 << 7) // meio-direita
|
||
|
||
// parte alfanumérica (topo)
|
||
#define SEG_TL (1 << 8) // top-left extra
|
||
#define SEG_TM (1 << 9) // top-middle (horizontal)
|
||
#define SEG_TR (1 << 10) // top-right extra
|
||
|
||
// parte alfanumérica (baixo)
|
||
#define SEG_BL (1 << 11) // bottom-left extra
|
||
#define SEG_BM (1 << 12) // bottom-middle (horizontal)
|
||
#define SEG_BR (1 << 13) // bottom-right extra
|
||
|
||
#define SEG_DP (1 << 14) // ponto decimal
|
||
|
||
// "segmento do meio" clássico (g) = as duas barrinhas
|
||
#define SEG_G (SEG_ML | SEG_MR)
|
||
|
||
|
||
|
||
|
||
// ------------------------------
|
||
// DISPLAY INIT
|
||
// ------------------------------
|
||
void display_init(void)
|
||
{
|
||
uint8_t cmd1 = 0x21; // oscillator ON
|
||
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();
|
||
}
|
||
|
||
// ------------------------------
|
||
// 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;
|
||
|
||
uint8_t buf[3];
|
||
buf[0] = pos * 2;
|
||
buf[1] = mask & 0xFF;
|
||
buf[2] = (mask >> 8) & 0xFF;
|
||
|
||
i2c_master_write_to_device(I2C_PORT, DISP_ADDR, buf, 3, 20 / portTICK_PERIOD_MS);
|
||
}
|
||
|
||
// --------------------------------------------------------
|
||
// Tabela alfanumérica 14 segmentos
|
||
// (corrigido: H com os 2 segmentos horizontais g1/g2)
|
||
// --------------------------------------------------------
|
||
static uint16_t charset(char c)
|
||
{
|
||
switch (c)
|
||
{
|
||
//------------------------------------------------------
|
||
// NÚMEROS (PERFEITOS)
|
||
//------------------------------------------------------
|
||
case '0': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
|
||
case '1': return SEG_B | SEG_C;
|
||
case '2': return SEG_A | SEG_B | SEG_G | SEG_E | SEG_D;
|
||
case '3': return SEG_A | SEG_B | SEG_G | SEG_C | SEG_D;
|
||
case '4': return SEG_F | SEG_G | SEG_B | SEG_C;
|
||
case '5': return SEG_A | SEG_F | SEG_G | SEG_C | SEG_D;
|
||
case '6': return SEG_A | SEG_F | SEG_G | SEG_E | SEG_D | SEG_C;
|
||
case '7': return SEG_A | SEG_B | SEG_C;
|
||
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;
|
||
|
||
//------------------------------------------------------
|
||
// LETRAS A-Z (todas as possíveis)
|
||
//------------------------------------------------------
|
||
|
||
// A
|
||
case 'A': case 'a':
|
||
return SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G;
|
||
|
||
// B (tipo “8” mais quadrado)
|
||
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()
|
||
// --------------------------------------------------------
|
||
void display_char(int pos, char c)
|
||
{
|
||
uint16_t mask = charset(c);
|
||
display_raw(pos, mask);
|
||
}
|
||
|
||
// --------------------------------------------------------
|
||
// display_text() (4 caracteres)
|
||
// --------------------------------------------------------
|
||
void display_text(const char *txt)
|
||
{
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
char c = txt[i];
|
||
if (c == 0) c = ' ';
|
||
display_char(i, c);
|
||
}
|
||
}
|
||
|
||
// --------------------------------------------------------
|
||
// display_number()
|
||
// Mantida para compatibilidade com 7-segment
|
||
// --------------------------------------------------------
|
||
// Dígitos 0–9 usando os segmentos definidos acima
|
||
static const uint16_t digit_mask[10] = {
|
||
// 0: a b c d e f
|
||
[0] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,
|
||
|
||
// 1: b c
|
||
[1] = SEG_B | SEG_C,
|
||
|
||
// 2: a b g e 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,
|
||
|
||
// 4: f g b 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,
|
||
|
||
// 6: a f g e d 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,
|
||
|
||
// 8: tudo
|
||
[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,
|
||
};
|
||
|
||
void display_digit(int pos, uint8_t val)
|
||
{
|
||
if (pos < 0 || pos > 3) return;
|
||
if (val > 9) val = 0;
|
||
|
||
uint16_t mask = digit_mask[val];
|
||
display_raw(pos, mask);
|
||
}
|
||
|
||
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);
|
||
}
|
||
void display_set_time(int horas, int minutos)
|
||
{
|
||
if (horas < 0) horas = 0;
|
||
if (horas > 99) horas = 99;
|
||
if (minutos < 0) minutos = 0;
|
||
if (minutos > 59) minutos = 59;
|
||
|
||
int h1 = horas / 10;
|
||
int h2 = horas % 10;
|
||
int m1 = minutos / 10;
|
||
int m2 = minutos % 10;
|
||
|
||
uint16_t dig1 = digit_mask[h2] | SEG_DP; //dot betwen hours
|
||
|
||
display_digit(0, h1);
|
||
display_raw(1, dig1);
|
||
display_digit(2, m1);
|
||
display_digit(3, m2);
|
||
}
|
||
|
||
void display_debug_segment(uint16_t bitmask)
|
||
{
|
||
display_raw(0, bitmask); // acende só o dígito 0
|
||
}
|