#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c.h"
#include "driver/uart.h"
#include "rom/ets_sys.h"
#include "freertos/event_groups.h"
#define UART0 UART_NUM_0
#define STACK_SIZE 1024
TaskHandle_t HandleTask = NULL;
#define BIT_0 ( 1 << 0 )
#define BIT_1 ( 1 << 1 )
void uartputchar(char c) {
uart_write_bytes(UART0, &c, 1);
}
void uartputs(const char *str) {
uart_write_bytes(UART0, str, strlen(str));
}
int uartkbnit(void) {
size_t length = 0;
uart_get_buffered_data_len(UART0, &length);
return (length > 0);
}
char uartgetchar(void) {
char c;
while (!uartkbnit()) {
vTaskDelay(10 / portTICK_PERIOD_MS);
}
uart_read_bytes(UART0, &c, 1, 0);
return c;
}
void uartgets(char *str, int maxlen) {
int i = 0;
char c;
while (i < maxlen - 1) {
c = uartgetchar();
if (c == '\n' || c == '\r') {
break;
}
str[i++] = c;
uartputchar(c);
}
str[i] = '\0';
uartputs("\n");
}
#define LCD_20X04 1
#define I2C_ACK_CHECK_EN 1
#define I2C_ADDRESS_LCD 0x27
#define I2C_SCL_LCD 22
#define I2C_SDA_LCD 21
/* Comandos de la LCD */
#define CLEAR_DISPLAY 0x01
#define RETURN_HOME_UNSHIFT 0x02
#define CURSOR_RIGHT_NO_SHIFT 0x04
#define CURSOR_RIGHT_SHIFT 0x05
#define CURSOR_RIGHT_NO_SHIFT_LEFT 0x06
#define CURSOR_RIGHT_SHIFT_LEFT 0x07
#define DISPLAY_OFF 0x08
#define DISPLAY_ON_CURSOR_OFF 0x0C
#define DISPLAY_ON_CURSOR_ON_STEADY 0x0E
#define DISPLAY_ON_CURSOR_ON_BLINK 0x0F
#define SHIFT_CURSOR_LEFT 0x10
#define SHIFT_CURSOR_RIGHT 0x14
#define SHIFT_DISPLAY_LEFT 0x18
#define SHIFT_DISPLAY_RIGHT 0x1C
#define SET_4BIT_MODE 0x28
#define RETURN_HOME 0x80
/* PCF8574 */
#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
typedef struct {
uint8_t i2c_address;
uint8_t i2c_port;
uint8_t screen_size;
uint8_t screen_backlight;
} lcd_i2c_device_t;
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_write_custom_char(lcd_i2c_device_t * lcd, uint8_t char_address, const uint8_t * pixels);
void i2c_init(void)
{
/* Configure la conexión aquí */
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_SCL_LCD,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_SDA_LCD,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 1000000,
};
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 uart_init(void){
const uart_port_t uart_num = UART_NUM_2;
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_CTS_RTS,
.rx_flow_ctrl_thresh = 122,
};
// Configure UART parameters
ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, 4, 5, 18, 19));
QueueHandle_t uart_queue;
// Install UART driver using an event queue here
const int uart_buffer_size = (1024 * 2);
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_0, uart_buffer_size, uart_buffer_size, 10, &uart_queue, 0));
}
void lcd_init(lcd_i2c_device_t * lcd)
{
lcd_i2c_write_command(lcd, LCD_RS_CMD, RETURN_HOME_UNSHIFT);
lcd_i2c_write_command(lcd, LCD_RS_CMD, SET_4BIT_MODE);
lcd_i2c_write_command(lcd, LCD_RS_CMD, CLEAR_DISPLAY);
lcd_i2c_write_command(lcd, LCD_RS_CMD, DISPLAY_ON_CURSOR_OFF);
lcd_i2c_write_command(lcd, LCD_RS_CMD, CURSOR_RIGHT_NO_SHIFT_LEFT);
vTaskDelay(20 / 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, 1);
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 config = (register_select)? (1 << PCF8574_RS) : 0;
config |= (lcd->screen_backlight)? (1 << PCF8574_BL) : 0;
config |= (config & 0x0F) | (0xF0 & cmd);
config |= (1 << PCF8574_EN);
lcd_i2c_write_byte(lcd, config);
ets_delay_us(10);
config &= ~(1 << PCF8574_EN);
lcd_i2c_write_byte(lcd, config);
ets_delay_us(50);
config = (config & 0x0F) | (cmd << 4);
config |= (1 << PCF8574_EN);
lcd_i2c_write_byte(lcd, config);
ets_delay_us(10);
config &= ~(1 << PCF8574_EN);
lcd_i2c_write_byte(lcd, config);
ets_delay_us(50);
if (cmd == CLEAR_DISPLAY)
{
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
void lcd_set_cursor(lcd_i2c_device_t * lcd, uint8_t column, uint8_t row)
{
switch (row) {
case 0:
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0x80 + column);
break;
case 1:
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0xC0 + column);
break;
case 2:
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0x94 + column);
break;
case 3:
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0xD4 + column);
break;
default:
break;
}
}
void lcd_i2c_write_custom_char(lcd_i2c_device_t * lcd, uint8_t address, const uint8_t * pixels)
{
lcd_i2c_write_command(lcd, LCD_RS_CMD, 0x40 | (address << 3));
for (uint8_t i = 0; i < 8; i++)
{
lcd_i2c_write_command(lcd, LCD_RS_DATA, pixels[i]);
}
lcd_i2c_write_command(lcd, LCD_RS_CMD, RETURN_HOME);
}
void lcd_i2c_print_msg(lcd_i2c_device_t * lcd, char * msg)
{
uint8_t i = 0;
while (msg[i] != '\0')
{
lcd_i2c_write_command(lcd, LCD_RS_DATA, msg[i++]);
}
}
// Task to be created.
void vTaskMatriz( void *pvParameters )
{
lcd_i2c_device_t my_lcd = {
.i2c_port = I2C_NUM_1,
.i2c_address = I2C_ADDRESS_LCD,
.screen_size = LCD_20X04,
.screen_backlight = 1,
};
vTaskDelay(20 / portTICK_PERIOD_MS);
lcd_init(&my_lcd);
while(true){
char ren[10];
char col[10];
char rutas[10];
// Leer renglones y columnas
uartputs("Renglones:\n");
uartgets(ren, sizeof(ren));
int renglones = atoi(ren);
uartputs("Columnas:\n");
uartgets(col, sizeof(col));
int columnas = atoi(col);
// Crear la matriz del campo
int campo[renglones][columnas];
memset(campo, 0, sizeof(campo)); // Inicializar todo a 0 (disponible)
// Leer número de rutas
uartputs("Rutas:\n");
uartgets(rutas, sizeof(rutas));
int num_rutas = atoi(rutas);
// Leer las rutas y marcarlas en la matriz
for (int i = 0; i < num_rutas; i++) {
char ruta_info[30];
uartputs("Ingresa la ruta en formato r c1 c2:\n");
uartgets(ruta_info, sizeof(ruta_info));
int r, c1, c2;
sscanf(ruta_info, "%d %d %d", &r, &c1, &c2); // Leer los valores de la ruta
// Marcar la ruta en la matriz (ajustar índices si son 1-based)
for (int col = c1; col <= c2; col++) {
campo[r][col] = 1; // Marcar como ocupado
}
}
// Calcular celdas disponibles
int celdas_disponibles = 0;
for (int r = 0; r < renglones; r++) {
for (int c = 0; c < columnas; c++) {
if (campo[r][c] == 0) {
celdas_disponibles++;
}
}
}
// Mostrar el resultado en la LCD
char resultado[32];
snprintf(resultado, sizeof(resultado), "Celdas libres: %d", celdas_disponibles);
lcd_set_cursor(&my_lcd, 0, 0); // Mover el cursor al inicio
lcd_i2c_print_msg(&my_lcd, resultado);
// También enviar el resultado por UART
uartputs(resultado);
vTaskDelay(20 / portTICK_PERIOD_MS);
vTaskSuspend(HandleTask);
}
}
#define SMILE 5
#define DROP 2
void app_main() {
i2c_init();
uart_init();
lcd_i2c_device_t my_lcd = {
.i2c_port = I2C_NUM_1,
.i2c_address = I2C_ADDRESS_LCD,
.screen_size = LCD_20X04,
.screen_backlight = 1,
};
vTaskDelay(20 / portTICK_PERIOD_MS);
lcd_init(&my_lcd);
xTaskCreate(vTaskMatriz, "Tarea_Datos", 2*(2*1024), NULL, 1, HandleTask);
}
/*
Reciba por UART:
⦁ El tamaño del campo de siembra, es decir, n y m.
⦁ El número de rutas que hay en el campo.
⦁ El inicio y fin de cada ruta, es decir r, c1 y c2.
*/