/*
* LIBRERÍA DE ACENTOS PARA LCD I2C
*
* Esta librería permite mostrar caracteres con acentos españoles en pantallas LCD I2C
* Uso: Incluir este código en tu proyecto y llamar a mostrarTextoConAcentos()
*
* Ejemplo de uso:
* mostrarTextoConAcentos(lcd, "Educación", 0, 0);
* mostrarTextoConAcentos(lcd, "¿Está bien?", 0, 1);
*/
// ===== CONFIGURACIÓN DE CARACTERES ESPECIALES =====
const int MAX_CARACTERES_ESPECIALES = 9;
const int TOTAL_SLOTS_LCD = 8;
const int SLOT_RESERVADO = 0; // Slot reservado para otros usos
// Estructura para definir caracteres especiales
struct CaracterEspecial {
byte primerByte; // Primer byte del carácter UTF-8
byte segundoByte; // Segundo byte del carácter UTF-8
byte disenio[8]; // Diseño del carácter en matriz 5x8
};
// Definición de caracteres especiales con acentos y símbolos
const CaracterEspecial CARACTERES_ESPECIALES[MAX_CARACTERES_ESPECIALES] = {
{0xC3, 0xA1, {B00001, B00010, B01110, B00001, B01110, B10001, B01110, B00000}}, // á
{0xC3, 0xA9, {B00001, B00010, B01110, B10001, B11111, B10000, B01110, B00000}}, // é
{0xC3, 0xAD, {B00010, B00100, B00000, B01100, B00100, B00100, B01110, B00000}}, // í
{0xC3, 0xB3, {B00001, B00010, B01110, B10001, B10001, B10001, B01110, B00000}}, // ó
{0xC3, 0xBA, {B00010, B00100, B10001, B10001, B10001, B10011, B01101, B00000}}, // ú
{0xC3, 0xB1, {B01110, B00000, B10110, B11001, B10001, B10001, B10001, B00000}}, // ñ
{0xC2, 0xB0, {B01100, B10010, B01100, B00000, B00000, B00000, B00000, B00000}}, // °
{0xC2, 0xA1, {B00100, B00000, B00000, B00100, B00100, B00100, B00100, B00000}}, // ¡
{0xC2, 0xBF, {B00100, B00000, B00100, B01000, B10000, B10001, B01110, B00000}} // ¿
};
// Variables estáticas para mantener el estado entre llamadas
static byte slotsUsados[MAX_CARACTERES_ESPECIALES];
static bool slotOcupado[TOTAL_SLOTS_LCD];
static bool sistemaInicializado = false;
// ===== PROTOTIPOS DE FUNCIONES PRIVADAS =====
void inicializarSistemaAcentos();
int buscarCaracterEspecial(byte byte1, byte byte2);
bool asignarSlotACaracter(int indiceCaracter, int fila, LiquidCrystal_I2C& lcd);
int obtenerRangoSlots(int fila, bool esInicio);
void asignarSlotsCaracteres(String texto, int fila, LiquidCrystal_I2C& lcd);
void mostrarTextoEnPantalla(String texto, int columnaInicial, int fila, LiquidCrystal_I2C& lcd);
void mostrarTextoConAcentos(LiquidCrystal_I2C& lcd, String texto, int columna, int fila, bool limpiarFila = true);
// ===== FUNCIÓN PRINCIPAL PÚBLICA =====
/**
* Muestra texto con acentos españoles en una pantalla LCD I2C
*
* @param lcd Referencia al objeto LiquidCrystal_I2C
* @param texto String con el texto a mostrar (puede contener acentos)
* @param columna Posición inicial en la columna (0-15)
* @param fila Fila donde mostrar el texto (0 o 1)
* @param limpiarFila Si true, limpia la fila antes de escribir (default: true)
*/
void mostrarTextoConAcentos(LiquidCrystal_I2C& lcd, String texto, int columna, int fila, bool limpiarFila = true) {
// Inicializar sistema si es la primera vez
if (!sistemaInicializado) {
inicializarSistemaAcentos();
}
// Limpiar fila si se solicita
if (limpiarFila) {
lcd.setCursor(0, fila);
lcd.print(" "); // 16 espacios
}
// Procesar y mostrar texto
asignarSlotsCaracteres(texto, fila, lcd);
mostrarTextoEnPantalla(texto, columna, fila, lcd);
}
/**
* Reinicia el sistema de slots para caracteres especiales
* Útil cuando se necesita liberar slots para otros caracteres personalizados
*/
void reiniciarSlotsAcentos() {
inicializarSistemaAcentos();
}
// ===== FUNCIONES PRIVADAS =====
void inicializarSistemaAcentos() {
// Inicializar mapeo de slots
for (int i = 0; i < MAX_CARACTERES_ESPECIALES; i++) {
slotsUsados[i] = 255; // Valor que indica "no asignado"
}
// Limpiar estado de slots
for (int i = 0; i < TOTAL_SLOTS_LCD; i++) {
slotOcupado[i] = false;
}
// Marcar slot reservado como ocupado
slotOcupado[SLOT_RESERVADO] = true;
sistemaInicializado = true;
}
void asignarSlotsCaracteres(String texto, int fila, LiquidCrystal_I2C& lcd) {
for (size_t i = 0; i < texto.length(); i++) {
byte primerByte = texto.charAt(i);
byte segundoByte = texto.charAt(i + 1);
int indiceCaracter = buscarCaracterEspecial(primerByte, segundoByte);
if (indiceCaracter >= 0 && slotsUsados[indiceCaracter] == 255) {
if (asignarSlotACaracter(indiceCaracter, fila, lcd)) {
// Crear el carácter personalizado en el LCD
lcd.createChar(slotsUsados[indiceCaracter], CARACTERES_ESPECIALES[indiceCaracter].disenio);
}
}
}
}
void mostrarTextoEnPantalla(String texto, int columnaInicial, int fila, LiquidCrystal_I2C& lcd) {
int columnaActual = columnaInicial;
for (size_t i = 0; i < texto.length() && columnaActual < 16; i++) {
byte primerByte = texto.charAt(i);
byte segundoByte = texto.charAt(i + 1);
int indiceCaracter = buscarCaracterEspecial(primerByte, segundoByte);
lcd.setCursor(columnaActual, fila);
if (indiceCaracter >= 0 && slotsUsados[indiceCaracter] != 255) {
// Mostrar carácter especial
lcd.write(slotsUsados[indiceCaracter]);
i++; // Saltar el segundo byte del carácter UTF-8
} else {
// Mostrar carácter normal
lcd.print((char)primerByte);
}
columnaActual++;
}
}
int buscarCaracterEspecial(byte byte1, byte byte2) {
for (int i = 0; i < MAX_CARACTERES_ESPECIALES; i++) {
if (CARACTERES_ESPECIALES[i].primerByte == byte1 &&
CARACTERES_ESPECIALES[i].segundoByte == byte2) {
return i;
}
}
return -1; // No encontrado
}
bool asignarSlotACaracter(int indiceCaracter, int fila, LiquidCrystal_I2C& lcd) {
int slotInicio = obtenerRangoSlots(fila, true);
int slotFin = obtenerRangoSlots(fila, false);
// Buscar slot libre en el rango permitido para esta fila
for (int slot = slotInicio; slot <= slotFin; slot++) {
if (!slotOcupado[slot]) {
slotsUsados[indiceCaracter] = slot;
slotOcupado[slot] = true;
return true;
}
}
return false; // No hay slots disponibles
}
int obtenerRangoSlots(int fila, bool esInicio) {
if (fila == 0) {
return esInicio ? 1 : 4; // Fila 0: slots 1-4
} else {
return esInicio ? 5 : 7; // Fila 1: slots 5-7
}
}
/*
* EJEMPLO DE USO:
*
* #include <Wire.h>
* #include <LiquidCrystal_I2C.h>
*
* LiquidCrystal_I2C lcd(0x27, 16, 2);
*
* void setup() {
* lcd.init();
* lcd.backlight();
*
* mostrarTextoConAcentos(lcd, "Educación", 0, 0);
* mostrarTextoConAcentos(lcd, "¿Está bien?", 0, 1);
* }
*
* void loop() {
* // Tu código aquí
* }
*/