#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c.h"
#include "rom/ets_sys.h"
// INICIO DE LA BIBLIOTECA DEL LCD -------------------------------------------
// PINES DEL PCF8475
#define RS 0
#define RW 1
#define EN 2
#define BL 3
// INSTRUCCIONES DEL DISPLAY LCD
#define LIMPIAR_PANTALLA 0x01
#define RETORNAR_INICIO 0x02
#define DISPLAY_ON_CURSOR_OFF 0x0C
#define ESTABLECER_4BIT_MODE 0x28
#define ESTABLECER_POS_CURSOR(fila, col) (0x80 | (fila * 0x40 + col)) // Macro para establecer posición del cursor
typedef struct {
uint8_t direccion; // Dirección del LCD
uint8_t num; // Número del I2C
uint8_t retroiluminacion; // Estado de la luz de fondo
} controlador_lcd_i2c_t;
// Función para escribir un byte en el bus I2C
void i2c_escribir_byte(controlador_lcd_i2c_t *lcd, uint8_t dato) {
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, (lcd->direccion << 1) | I2C_MASTER_WRITE, 1);
i2c_master_write_byte(i2c_cmd, dato, 1);
i2c_master_stop(i2c_cmd);
i2c_master_cmd_begin(lcd->num, i2c_cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(i2c_cmd);
}
// Función para escribir en el LCD (comando o dato)
void lcd_i2c_escribir(controlador_lcd_i2c_t *lcd, char rs_flag, char byte_dato) {
uint8_t byte_buffer = ((1 << RS) * rs_flag) | ((1 << BL) * lcd->retroiluminacion);
byte_buffer |= (byte_buffer & 0x0F) | (0xF0 & byte_dato);
byte_buffer |= (1 << EN);
i2c_escribir_byte(lcd, byte_buffer);
ets_delay_us(10);
byte_buffer &= ~(1 << EN);
i2c_escribir_byte(lcd, byte_buffer);
ets_delay_us(50);
byte_buffer = (byte_buffer & 0x0F) | (byte_dato << 4);
byte_buffer |= (1 << EN);
i2c_escribir_byte(lcd, byte_buffer);
ets_delay_us(10);
byte_buffer &= ~(1 << EN);
i2c_escribir_byte(lcd, byte_buffer);
ets_delay_us(50);
}
// Función para inicializar el LCD
void lcd_i2c_inicializar(controlador_lcd_i2c_t *lcd) {
vTaskDelay(10 / portTICK_PERIOD_MS);
lcd_i2c_escribir(lcd, 0, RETORNAR_INICIO);
lcd_i2c_escribir(lcd, 0, ESTABLECER_4BIT_MODE);
lcd_i2c_escribir(lcd, 0, LIMPIAR_PANTALLA);
lcd_i2c_escribir(lcd, 0, DISPLAY_ON_CURSOR_OFF);
vTaskDelay(10 / portTICK_PERIOD_MS);
}
// Función para imprimir en el LCD
void lcd_i2c_imprimir(controlador_lcd_i2c_t *lcd, const char *str) {
while (*str) {
lcd_i2c_escribir(lcd, 1, *str++);
}
}
// Nueva función para encender la luz de fondo
void lcd_i2c_retroiluminacion_encender(controlador_lcd_i2c_t *lcd) {
lcd->retroiluminacion = 1; // Enciende la luz de fondo
lcd_i2c_escribir(lcd, 0, 0); // Actualiza el estado
}
// Nueva función para apagar la luz de fondo
void lcd_i2c_retroiluminacion_apagar(controlador_lcd_i2c_t *lcd) {
lcd->retroiluminacion = 0; // Apaga la luz de fondo
lcd_i2c_escribir(lcd, 0, 0); // Actualiza el estado
}
// Nueva función para borrar el contenido del LCD
void lcd_i2c_limpiar_pantalla(controlador_lcd_i2c_t *lcd) {
lcd_i2c_escribir(lcd, 0, LIMPIAR_PANTALLA);
}
// Nueva función para establecer la visibilidad del cursor
void lcd_i2c_establecer_visibilidad_cursor(controlador_lcd_i2c_t *lcd, uint8_t visible) {
if (visible) {
lcd_i2c_escribir(lcd, 0, DISPLAY_ON_CURSOR_OFF | 0x02); // Muestra el cursor
} else {
lcd_i2c_escribir(lcd, 0, DISPLAY_ON_CURSOR_OFF); // Oculta el cursor
}
}
// Nueva función para habilitar o deshabilitar el parpadeo del cursor
void lcd_i2c_parpadeo_cursor(controlador_lcd_i2c_t *lcd, uint8_t parpadeo) {
if (parpadeo) {
lcd_i2c_escribir(lcd, 0, DISPLAY_ON_CURSOR_OFF | 0x01); // Habilita el parpadeo
} else {
lcd_i2c_escribir(lcd, 0, DISPLAY_ON_CURSOR_OFF & ~0x01); // Deshabilita el parpadeo
}
}
// Nueva función para desplazar el contenido del display
void lcd_i2c_desplazar_pantalla(controlador_lcd_i2c_t *lcd, uint8_t derecha) {
uint8_t comando = derecha ? 0x1C : 0x18; // 0x1C desplaza a la derecha, 0x18 a la izquierda
lcd_i2c_escribir(lcd, 0, comando);
}
// Nueva función para establecer la posición del cursor
void lcd_i2c_establecer_pos_cursor(controlador_lcd_i2c_t *lcd, uint8_t fila, uint8_t col) {
lcd_i2c_escribir(lcd, 0, ESTABLECER_POS_CURSOR(fila, col));
}
// FIN DE LA BIBLIOTECA DEL LCD ----------------------------------------------
// INICIO DEL CÓDIGO ESPECÍFICO DEL PROYECTO --------------------------------
void i2c_inicializar() {
i2c_config_t configuracion_i2c = {
.mode = I2C_MODE_MASTER,
.sda_io_num = 22, // Pin SDA
.sda_pullup_en = 1,
.scl_io_num = 21, // Pin SCL
.scl_pullup_en = 1,
.master.clk_speed = 100000, // Velocidad del I2C
};
i2c_param_config(I2C_NUM_1, &configuracion_i2c);
i2c_driver_install(I2C_NUM_1, I2C_MODE_MASTER, 0, 0, 0);
}
void app_main() {
i2c_inicializar(); // Inicializa la comunicación I2C
controlador_lcd_i2c_t display = {
.direccion = 0x27, // Asegúrate de que esta sea la dirección correcta para tu LCD
.num = I2C_NUM_1,
.retroiluminacion = 1, // Luz de fondo encendida
};
// Inicializa el display
lcd_i2c_inicializar(&display);
// Ejercicio 0: Mostrar nombre y materia
lcd_i2c_establecer_pos_cursor(&display, 0, 0); // Primera línea
lcd_i2c_imprimir(&display, "RAUL"); // Tu nombre
lcd_i2c_establecer_pos_cursor(&display, 1, 0); // Segunda línea
lcd_i2c_imprimir(&display, "MIC II"); // Nombre de la materia
// Ejercicio 1: Limpieza de pantalla
vTaskDelay(3000 / portTICK_PERIOD_MS); // Espera 3 segundos
lcd_i2c_limpiar_pantalla(&display); // Limpia el LCD
lcd_i2c_imprimir(&display, "PANTALLA LIMPIA"); // Muestra el mensaje
// Ejercicio 2: Control de retroiluminación
for (int i = 0; i < 5; i++) { // Realiza 5 ciclos de encender/apagar
lcd_i2c_retroiluminacion_encender(&display); // Enciende la luz de fondo
vTaskDelay(2000 / portTICK_PERIOD_MS); // Espera 2 segundos
lcd_i2c_retroiluminacion_apagar(&display); // Apaga la luz de fondo
vTaskDelay(2000 / portTICK_PERIOD_MS); // Espera 2 segundos
}
// Ejercicio 3: Movimiento del cursor
lcd_i2c_retroiluminacion_encender(&display);
lcd_i2c_establecer_pos_cursor(&display, 1, 8); // Segunda línea, posición central (columna 8)
lcd_i2c_imprimir(&display, "CENTRO"); // Imprime "Centro"
// Ejercicio 4: Visibilidad y parpadeo del cursor
lcd_i2c_establecer_visibilidad_cursor(&display, 1); // Habilita la visibilidad del cursor
for (int i = 0; i < 6; i++) { // Parpadea 10 veces
lcd_i2c_parpadeo_cursor(&display, 1); // Habilita el parpadeo
vTaskDelay(500 / portTICK_PERIOD_MS); // Espera medio segundo
lcd_i2c_parpadeo_cursor(&display, 0); // Deshabilita el parpadeo
vTaskDelay(500 / portTICK_PERIOD_MS); // Espera medio segundo
}
lcd_i2c_limpiar_pantalla(&display);
// Ejercicio 5: Desplazamiento del contenido
while (1) {
lcd_i2c_imprimir(&display, "HOLA");
for (int i = 0; i < 12; i++) { // Desplaza a la derecha
lcd_i2c_desplazar_pantalla(&display, 1);
vTaskDelay(500 / portTICK_PERIOD_MS); // Espera 500 ms
}
for (int i = 0; i < 12; i++) { // Desplaza a la izquierda
lcd_i2c_desplazar_pantalla(&display, 0);
vTaskDelay(500 / portTICK_PERIOD_MS); // Espera 500 ms
}
for (int i = 0; i < 12; i++) { // Desplaza a la derecha
lcd_i2c_desplazar_pantalla(&display, 1);
vTaskDelay(500 / portTICK_PERIOD_MS); // Espera 500 ms
}
lcd_i2c_limpiar_pantalla(&display);
lcd_i2c_imprimir(&display, "BIENVENIDOS");
while(1){
for (int i = 0; i < 16; i++) { // Desplaza a la derecha
lcd_i2c_desplazar_pantalla(&display, 0);
vTaskDelay(200 / portTICK_PERIOD_MS); // Espera 200 ms
}
}
}
}