#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
// I2C definitions
#define I2C_MASTER_SCL_IO 22 // GPIO number for I2C master clock
#define I2C_MASTER_SDA_IO 21 // GPIO number for I2C master data
#define I2C_MASTER_NUM I2C_NUM_0 // I2C port number for master dev
#define I2C_MASTER_TX_BUF_DISABLE 0 // I2C master doesn't need buffer
#define I2C_MASTER_RX_BUF_DISABLE 0 // I2C master doesn't need buffer
#define I2C_MASTER_FREQ_HZ 100000 // I2C master clock frequency
// LCD Address
#define LCD_ADDR 0x27 // I2C address of the LCD
// LCD Commands
#define LCD_CLEAR_DISPLAY 0x01 // Clear display command
#define LCD_RETURN_HOME 0x02 // Return home command
#define LCD_ENTRY_MODE_SET 0x04 // Entry mode set command
#define LCD_DISPLAY_CONTROL 0x08 // Display control command
#define LCD_CURSOR_SHIFT 0x10 // Cursor or display shift command
#define LCD_FUNCTION_SET 0x20 // Function set command
#define LCD_SET_CGRAM_ADDR 0x40 // Set CGRAM address command
#define LCD_SET_DDRAM_ADDR 0x80 // Set DDRAM address command
// Function prototypes
esp_err_t i2c_lcd_write_byte(uint8_t data, uint8_t cmd);
void i2c_lcd_init();
void i2c_lcd_clear();
void i2c_lcd_puts(const char *str);
void app_main(void)
{
// Initialize I2C master
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = I2C_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = I2C_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
i2c_param_config(I2C_MASTER_NUM, &conf);
i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
// Initialize LCD
i2c_lcd_init();
// Display some text
i2c_lcd_puts("Hello, ESP32!");
}
esp_err_t i2c_lcd_write_byte(uint8_t data, uint8_t cmd)
{
i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();
i2c_master_start(cmd_handle);
i2c_master_write_byte(cmd_handle, LCD_ADDR << 1 | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd_handle, data, true);
i2c_master_stop(cmd_handle);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd_handle, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd_handle);
return ret;
}
void i2c_lcd_init()
{
// Initialize LCD
vTaskDelay(50 / portTICK_PERIOD_MS);
i2c_lcd_write_byte(0x30, 0);
vTaskDelay(5 / portTICK_PERIOD_MS);
i2c_lcd_write_byte(0x30, 0);
vTaskDelay(1 / portTICK_PERIOD_MS);
i2c_lcd_write_byte(0x30, 0);
vTaskDelay(1 / portTICK_PERIOD_MS);
// Set 4-bit mode
i2c_lcd_write_byte(0x20, 0);
vTaskDelay(1 / portTICK_PERIOD_MS);
// Initialize LCD in 4-bit mode
i2c_lcd_write_byte(0x28, 0); // Function set: 4-bit mode, 2 lines, 5x8 font
i2c_lcd_write_byte(0x08, 0); // Display off
i2c_lcd_clear(); // Clear display
i2c_lcd_write_byte(0x06, 0); // Entry mode set: Increment cursor, no shift
//i2c_lcd_write_byte(0x0C, 0); // Display on, cursor off, blink off
}
void i2c_lcd_clear()
{
i2c_lcd_write_byte(LCD_CLEAR_DISPLAY, 0);
vTaskDelay(2 / portTICK_PERIOD_MS);
}
void i2c_lcd_puts(const char *str)
{
while (*str)
{
i2c_lcd_write_byte(*str, 1);
str++;
}
}