#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
// I2C configuration
#define I2C_PORT i2c1
#define I2C_SDA_PIN 26 // GPIO26 for SDA
#define I2C_SCL_PIN 27 // GPIO27 for SCL
#define LCD_I2C_ADDRESS 0x27 // Change to 0x3F if needed
// LCD parameters
#define LCD_ROWS 2
#define LCD_COLS 16
// Commands
#define LCD_CLEAR_DISPLAY 0x01
#define LCD_RETURN_HOME 0x02
#define LCD_ENTRY_MODE_SET 0x04
#define LCD_DISPLAY_CONTROL 0x08
#define LCD_CURSOR_SHIFT 0x10
#define LCD_FUNCTION_SET 0x20
#define LCD_SET_CGRAM_ADDR 0x40
#define LCD_SET_DDRAM_ADDR 0x80
// Flags for display control
#define LCD_DISPLAY_ON 0x04
#define LCD_DISPLAY_OFF 0x00
#define LCD_CURSOR_ON 0x02
#define LCD_CURSOR_OFF 0x00
#define LCD_BLINK_ON 0x01
#define LCD_BLINK_OFF 0x00
// Flags for entry mode
#define LCD_ENTRY_LEFT 0x02
#define LCD_ENTRY_RIGHT 0x00
// Flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// Backlight control
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00
// Enable bit
#define ENABLE_BIT 0x04
// Helper function to send a byte to the LCD
void lcd_write_byte(uint8_t value) {
i2c_write_blocking(I2C_PORT, LCD_I2C_ADDRESS, &value, 1, false);
sleep_us(50);
}
// Send a command to the LCD
void lcd_send_command(uint8_t cmd) {
uint8_t high_nibble = (cmd & 0xF0) | LCD_BACKLIGHT;
uint8_t low_nibble = ((cmd << 4) & 0xF0) | LCD_BACKLIGHT;
lcd_write_byte(high_nibble | ENABLE_BIT);
lcd_write_byte(high_nibble);
lcd_write_byte(low_nibble | ENABLE_BIT);
lcd_write_byte(low_nibble);
sleep_ms(2); // Allow command to process
}
// Send data to the LCD
void lcd_send_data(uint8_t data) {
uint8_t high_nibble = (data & 0xF0) | LCD_BACKLIGHT | 0x01;
uint8_t low_nibble = ((data << 4) & 0xF0) | LCD_BACKLIGHT | 0x01;
lcd_write_byte(high_nibble | ENABLE_BIT);
lcd_write_byte(high_nibble);
lcd_write_byte(low_nibble | ENABLE_BIT);
lcd_write_byte(low_nibble);
sleep_us(50);
}
// Initialize the LCD
void lcd_init() {
sleep_ms(50); // Wait for LCD to power up
// Initialize in 4-bit mode
lcd_send_command(0x03);
lcd_send_command(0x03);
lcd_send_command(0x03);
lcd_send_command(0x02);
// Configure the LCD
lcd_send_command(LCD_FUNCTION_SET | LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS);
lcd_send_command(LCD_DISPLAY_CONTROL | LCD_DISPLAY_ON | LCD_CURSOR_OFF | LCD_BLINK_OFF);
lcd_send_command(LCD_CLEAR_DISPLAY);
lcd_send_command(LCD_ENTRY_MODE_SET | LCD_ENTRY_LEFT);
}
// Set cursor position
void lcd_set_cursor(uint8_t row, uint8_t col) {
uint8_t address = col + (row * 0x40);
lcd_send_command(LCD_SET_DDRAM_ADDR | address);
}
// Print a string to the LCD
void lcd_print(const char *str) {
while (*str) {
lcd_send_data(*str++);
}
}
int main() {
// Initialize stdio
stdio_init_all();
printf("Starting I2C LCD Example...\n");
// Initialize I2C
i2c_init(I2C_PORT, 100 * 1000); // 100kHz I2C frequency
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(I2C_SDA_PIN);
gpio_pull_up(I2C_SCL_PIN);
// Initialize the LCD
lcd_init();
// Display "Embarcatech" on the first row
lcd_set_cursor(0, 0);
lcd_print("Embarcatech 2025");
// Display "2025" on the second row
lcd_set_cursor(1, 0);
lcd_print("Capitulo 6");
// Loop forever
while (true) {
sleep_ms(1000);
}
return 0;
}