#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/i2c.h"
#include "rom/ets_sys.h"
#include "esp_system.h"
// Definiciones UART
#define UART_NUM UART_NUM_0
#define BUF_SIZE (1024)
// Definiciones LCD
#define LCD_20X04 1
#define I2C_ACK_CHECK_EN 1
#define I2C_ADDRESS_LCD 0x27
#define I2C_SCL_LCD 21
#define I2C_SDA_LCD 22
// Comandos LCD
#define CLEAR_DISPLAY 0x01
#define RETURN_HOME_UNSHIFT 0x02
#define CURSOR_RIGHT_NO_SHIFT_LEFT 0x06
#define DISPLAY_ON_CURSOR_OFF 0x0C
#define SET_4BIT_MODE 0x28
#define RETURN_HOME 0x80
#define PCF8574_RS 0
#define PCF8574_RW 1
#define PCF8574_EN 2
#define PCF8574_BL 3
#define LCD_RS_CMD 0
#define LCD_RS_DATA 1
// Estructura para el dispositivo LCD
typedef struct {
uint8_t i2c_address;
uint8_t i2c_port;
uint8_t screen_size;
uint8_t screen_backlight;
} lcd_i2c_device_t;
// Declaraciones de funciones UART
void uart_init(void);
void uart_put_char(char c);
void uart_puts(const char *str);
int uart_kbhit(void);
char uart_get_char(void);
void uart_gets(char *str, int maxlen);
// Declaraciones de funciones de procesamiento
void eliminar_espacios(char* input);
void llenar_matriz(char* cadena, int rows, int cols, char matriz[rows][cols]);
// Declaraciones de funciones LCD
void i2c_init(void);
void lcd_init(lcd_i2c_device_t * lcd);
void lcd_i2c_write_byte(lcd_i2c_device_t * lcd, uint8_t data);
void lcd_i2c_write_command(lcd_i2c_device_t * lcd, uint8_t register_select, uint8_t cmd);
void lcd_set_cursor(lcd_i2c_device_t * lcd, uint8_t column, uint8_t row);
void lcd_i2c_print_char(lcd_i2c_device_t * lcd, char c);
void lcd_i2c_print_msg(lcd_i2c_device_t * lcd, char * msg);
// Implementación de funciones UART
void uart_init(void)
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
ESP_ERROR_CHECK(uart_driver_install(UART_NUM, BUF_SIZE, 0, 0, NULL, 0));
}
void uart_put_char(char c)
{
uart_write_bytes(UART_NUM, &c, 1);
}
void uart_puts(const char *str)
{
uart_write_bytes(UART_NUM, str, strlen(str));
}
int uart_kbhit(void)
{
size_t length = 0;
uart_get_buffered_data_len(UART_NUM, &length);
return (length > 0);
}
char uart_get_char(void)
{
char c;
while (!uart_kbhit())
{
vTaskDelay(10 / portTICK_PERIOD_MS);
}
uart_read_bytes(UART_NUM, &c, 1, 0);
return c;
}
void uart_gets(char *str, int maxlen)
{
int i = 0;
char c;
while (i < maxlen - 1)
{
c = uart_get_char();
if (c == '\n' || c == '\r')
{
break;
}
str[i++] = c;
uart_put_char(c); // Eco para el usuario
}
str[i] = '\0';
uart_puts("\n"); // Nueva línea después de la entrada
}
// Implementación de funciones de procesamiento
void eliminar_espacios(char* input)
{
int longitud = strlen(input);
int c = 0;
char aux[longitud + 1];
for (int i = 0; i < longitud; i++)
{
if (input[i] != ' ')
{
aux[c] = input[i];
c++;
}
}
aux[c] = '\0';
strcpy(input, aux); // Actualiza el contenido original
}
void llenar_matriz(char* cadena, int rows, int cols, char matriz[rows][cols])
{
int len = strlen(cadena);
int index = 0;
// Llenar la matriz
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (index < len)
{
matriz[i][j] = cadena[index++];
}
else
{
matriz[i][j] = ' '; // Rellenar espacios vacíos
}
}
}
}
// Implementación de funciones LCD
void i2c_init(void)
{
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_SDA_LCD,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_SCL_LCD,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 400000,
};
esp_err_t error = i2c_param_config(I2C_NUM_1, &i2c_config);
if (error != ESP_OK) {
while(1);
}
i2c_driver_install(I2C_NUM_1, I2C_MODE_MASTER, 0, 0, 0);
}
void lcd_init(lcd_i2c_device_t * lcd)
{
vTaskDelay(50 / portTICK_PERIOD_MS); // Esperar a que el LCD esté listo
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0x03);
vTaskDelay(5 / portTICK_PERIOD_MS);
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0x03);
ets_delay_us(150);
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0x03);
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0x02);
lcd_i2c_write_command(lcd, LCD_RS_CMD, SET_4BIT_MODE);
lcd_i2c_write_command(lcd, LCD_RS_CMD, DISPLAY_ON_CURSOR_OFF);
lcd_i2c_write_command(lcd, LCD_RS_CMD, CLEAR_DISPLAY);
lcd_i2c_write_command(lcd, LCD_RS_CMD, CURSOR_RIGHT_NO_SHIFT_LEFT);
vTaskDelay(5 / portTICK_PERIOD_MS);
}
void lcd_i2c_write_byte(lcd_i2c_device_t * lcd, uint8_t data)
{
i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();
i2c_master_start(cmd_handle);
i2c_master_write_byte(cmd_handle, (lcd->i2c_address << 1) | I2C_MASTER_WRITE, I2C_ACK_CHECK_EN);
i2c_master_write_byte(cmd_handle, data | (lcd->screen_backlight ? (1 << PCF8574_BL) : 0), I2C_ACK_CHECK_EN);
i2c_master_stop(cmd_handle);
i2c_master_cmd_begin(lcd->i2c_port, cmd_handle, 100 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd_handle);
}
void lcd_i2c_write_command(lcd_i2c_device_t * lcd, uint8_t register_select, uint8_t cmd)
{
uint8_t upper_nibble = cmd & 0xF0;
uint8_t lower_nibble = (cmd << 4) & 0xF0;
uint8_t rs = (register_select == LCD_RS_DATA) ? (1 << PCF8574_RS) : 0;
// Enviar bits altos
lcd_i2c_write_byte(lcd, upper_nibble | rs | (1 << PCF8574_EN));
ets_delay_us(1);
lcd_i2c_write_byte(lcd, upper_nibble | rs);
ets_delay_us(50);
// Enviar bits bajos
lcd_i2c_write_byte(lcd, lower_nibble | rs | (1 << PCF8574_EN));
ets_delay_us(1);
lcd_i2c_write_byte(lcd, lower_nibble | rs);
ets_delay_us(50);
}
void lcd_set_cursor(lcd_i2c_device_t * lcd, uint8_t column, uint8_t row)
{
uint8_t row_offsets[] = {0x00, 0x40, 0x14, 0x54};
if (row > 3) {
row = 3;
}
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0x80 | (column + row_offsets[row]));
}
void lcd_i2c_print_char(lcd_i2c_device_t * lcd, char c)
{
lcd_i2c_write_command(lcd, LCD_RS_DATA, c);
}
void lcd_i2c_print_msg(lcd_i2c_device_t * lcd, char * msg)
{
while (*msg) {
lcd_i2c_print_char(lcd, *msg++);
}
}
// Función principal
void app_main()
{
// Inicializar UART
uart_init();
// Inicializar LCD
i2c_init();
lcd_i2c_device_t my_lcd = {
.i2c_port = I2C_NUM_1,
.i2c_address = I2C_ADDRESS_LCD,
.screen_size = LCD_20X04,
.screen_backlight = 1,
};
lcd_init(&my_lcd);
// Leer entrada desde UART
char input[100];
uart_puts("Escribir la cadena: ");
uart_gets(input, sizeof(input));
// Eliminar espacios de la cadena ingresada
eliminar_espacios(input);
// Calcular longitud de la cadena
int longitud = strlen(input);
// Calcular filas y columnas para la matriz cuadrada
int cols = ceil(sqrt(longitud));
int rows = ceil((double)longitud / cols);
// Crear y llenar la matriz
char matriz[rows][cols];
llenar_matriz(input, rows, cols, matriz);
// Mostrar la matriz en el LCD
lcd_i2c_write_command(&my_lcd, LCD_RS_CMD, CLEAR_DISPLAY);
for (int i = 0; i < rows && i < 4; i++) // El LCD de 20x4 tiene 4 filas
{
lcd_set_cursor(&my_lcd, 0, i);
for (int j = 0; j < cols && j < 20; j++) // Cada fila tiene 20 caracteres
{
lcd_i2c_print_char(&my_lcd, matriz[i][j]);
}
}
}