#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
// Pin Definitions
#define RS 12 // Register Select pin
#define E 13 // Enable pin
#define D4 14 // Data pin 4
#define D5 17 // Data pin 5
#define D6 18 // Data pin 6
#define D7 19 // Data pin 7
// LCD Commands
#define LCD_CLEAR 0x01
#define LCD_HOME 0x02
#define LCD_ENTRY_MODE 0x06
#define LCD_DISPLAY_ON 0x0C
#define LCD_FUNCTION_SET 0x28
#define LCD_SET_CURSOR 0x80
void lcd_send_command(uint8_t command) {
gpio_set_level(RS, 0); // Command mode
gpio_set_level(E, 1);
gpio_set_level(D4, (command >> 4) & 0x01);
gpio_set_level(D5, (command >> 5) & 0x01);
gpio_set_level(D6, (command >> 6) & 0x01);
gpio_set_level(D7, (command >> 7) & 0x01);
gpio_set_level(E, 0);
vTaskDelay(1 / portTICK_PERIOD_MS);
gpio_set_level(E, 1);
gpio_set_level(D4, command & 0x01);
gpio_set_level(D5, (command >> 1) & 0x01);
gpio_set_level(D6, (command >> 2) & 0x01);
gpio_set_level(D7, (command >> 3) & 0x01);
gpio_set_level(E, 0);
vTaskDelay(1 / portTICK_PERIOD_MS);
}
void lcd_send_data(uint8_t data) {
gpio_set_level(RS, 1); // Data mode
gpio_set_level(E, 1);
gpio_set_level(D4, (data >> 4) & 0x01);
gpio_set_level(D5, (data >> 5) & 0x01);
gpio_set_level(D6, (data >> 6) & 0x01);
gpio_set_level(D7, (data >> 7) & 0x01);
gpio_set_level(E, 0);
vTaskDelay(1 / portTICK_PERIOD_MS);
gpio_set_level(E, 1);
gpio_set_level(D4, data & 0x01);
gpio_set_level(D5, (data >> 1) & 0x01);
gpio_set_level(D6, (data >> 2) & 0x01);
gpio_set_level(D7, (data >> 3) & 0x01);
gpio_set_level(E, 0);
vTaskDelay(1 / portTICK_PERIOD_MS);
}
void lcd_init() {
gpio_set_direction(RS, GPIO_MODE_OUTPUT);
gpio_set_direction(E, GPIO_MODE_OUTPUT);
gpio_set_direction(D4, GPIO_MODE_OUTPUT);
gpio_set_direction(D5, GPIO_MODE_OUTPUT);
gpio_set_direction(D6, GPIO_MODE_OUTPUT);
gpio_set_direction(D7, GPIO_MODE_OUTPUT);
vTaskDelay(20 / portTICK_PERIOD_MS); // Wait for LCD to power up
lcd_send_command(0x33); // Initialization sequence
vTaskDelay(5 / portTICK_PERIOD_MS); // Wait before next command
lcd_send_command(0x32); // Set to 4-bit mode
vTaskDelay(5 / portTICK_PERIOD_MS); // Wait before next command
lcd_send_command(LCD_FUNCTION_SET); // 4-bit mode, 2-line, 5x8 dots
vTaskDelay(5 / portTICK_PERIOD_MS); // Wait before next command
lcd_send_command(LCD_DISPLAY_ON); // Display ON
vTaskDelay(5 / portTICK_PERIOD_MS); // Wait before next command
lcd_send_command(LCD_CLEAR); // Clear display
vTaskDelay(5 / portTICK_PERIOD_MS); // Wait before next command
lcd_send_command(LCD_ENTRY_MODE); // Entry mode
}
void lcd_print(const char* str) {
for (int i = 0; i < strlen(str); i++) {
lcd_send_data(str[i]); // Use lcd_send_data for printing characters
}
}
void app_main() {
lcd_init(); // Initialize the LCD
printf("LCD Initialized\n"); // Debug info
lcd_send_command(LCD_CLEAR); // Clear the display to avoid garbage values
lcd_print("Hello, Wokwi!"); // Print a message on the first line
vTaskDelay(1000 / portTICK_PERIOD_MS); // Wait for a moment
lcd_send_command(LCD_SET_CURSOR | 0x40); // Move to the beginning of the second line
lcd_print("ESP32 + LCD"); // Print on second line
printf("Message printed to LCD\n"); // Debug info
}