I have a HD44780 driven 5V 16x2 LCD that I thought at first I would need logic level shifters, but then I learned I could use a simple voltage divider, and perhaps not even that if the HD44780 is set read-only anyway. That is, CMOS 3.3 V high logic from Pico works fine to drive TTL 5 V high, but the other direction needs a voltage divider, or logic level shifter. I wired up a RGB backlit 16x2 LCD by using the Pico VBUS to power it. I assume it is fine to steal a little VBUS for the 5V connections? I put voltage dividers on each of the lines RS, EN, D4-D7. Like I said, probably not needed, but nice to know they are there just in case. I used 2.3k ohm resistors from LCD pins, and 3.3k ohm resistors to ground to make a ~3V divider on each GP pin.
Here is a setup I did in a hurry, so messy with resistor leads and such not trimmed:
![Image]()
General wiring of this type of display hookup guide: https://learn.adafruit.com/character-lc ... racter-lcd
Mine is RGB, but I am ony using Red at the moment.
I saw this done with Micro Python, but here is a Pico SDK example main.c, reset/power cycle after flashing.CMakeLists.txt for referenceSo, yay, my old 5V 16x2 LCD with the HD44780 chip works with the Pico!
Here is a setup I did in a hurry, so messy with resistor leads and such not trimmed:

General wiring of this type of display hookup guide: https://learn.adafruit.com/character-lc ... racter-lcd
Mine is RGB, but I am ony using Red at the moment.
I saw this done with Micro Python, but here is a Pico SDK example main.c, reset/power cycle after flashing.
Code:
// HD44780 driver for 16x2 character display#include "pico/stdlib.h"// GPIO mapping#define LCD_RS 10 // Register Select#define LCD_EN 11 // Enable#define LCD_D4 18 // Data pin 4#define LCD_D5 19 // Data pin 5#define LCD_D6 20 // Data pin 6#define LCD_D7 21 // Data pin 7void lcd_gpio_init(void);void lcd_pulse_enable(void);void lcd_send_nibble(uint8_t nibble);void lcd_send_byte(uint8_t rs, uint8_t data);void lcd_init(void);void lcd_set_cursor(uint8_t row, uint8_t col);void lcd_print(const char *str);int main(void) { lcd_init(); lcd_set_cursor(0, 0); // Row 0, Col 0 lcd_print("Hello, World!"); while (1) { tight_loop_contents(); }}void lcd_gpio_init(void) { gpio_init(LCD_RS); gpio_set_dir(LCD_RS, GPIO_OUT); gpio_init(LCD_EN); gpio_set_dir(LCD_EN, GPIO_OUT); gpio_init(LCD_D4); gpio_set_dir(LCD_D4, GPIO_OUT); gpio_init(LCD_D5); gpio_set_dir(LCD_D5, GPIO_OUT); gpio_init(LCD_D6); gpio_set_dir(LCD_D6, GPIO_OUT); gpio_init(LCD_D7); gpio_set_dir(LCD_D7, GPIO_OUT);}void lcd_pulse_enable(void) { gpio_put(LCD_EN, 1); sleep_us(1); // Enable pulse width > 450ns gpio_put(LCD_EN, 0); sleep_us(50); // Commands need > 37µs to settle}void lcd_send_nibble(uint8_t nibble) { gpio_put(LCD_D4, (nibble >> 0) & 1); gpio_put(LCD_D5, (nibble >> 1) & 1); gpio_put(LCD_D6, (nibble >> 2) & 1); gpio_put(LCD_D7, (nibble >> 3) & 1); lcd_pulse_enable();}void lcd_send_byte(uint8_t rs, uint8_t data) { gpio_put(LCD_RS, rs); // RS=0 for command, 1 for data lcd_send_nibble(data >> 4); // Send higher nibble lcd_send_nibble(data & 0xF); // Send lower nibble sleep_us(50); // Wait for the command to execute}void lcd_init(void) { lcd_gpio_init(); sleep_ms(15); // Wait for LCD to power up // Initialization sequence lcd_send_nibble(0x3); // Function set in 8-bit mode sleep_ms(5); lcd_send_nibble(0x3); sleep_us(150); lcd_send_nibble(0x3); sleep_us(50); lcd_send_nibble(0x2); // Switch to 4-bit mode // Function set: 4-bit mode, 2 lines, 5x8 font lcd_send_byte(0, 0x28); // Display ON/OFF control: Display ON, Cursor OFF, Blink OFF lcd_send_byte(0, 0x0C); // Clear display lcd_send_byte(0, 0x01); sleep_ms(2); // Entry mode set: Increment cursor, No shift lcd_send_byte(0, 0x06);}void lcd_set_cursor(uint8_t row, uint8_t col) { uint8_t address = (row == 0 ? 0x00 : 0x40) + col; lcd_send_byte(0, 0x80 | address); // Set DDRAM address}void lcd_print(const char *str) { while (*str) { lcd_send_byte(1, *str++); }}
Code:
# Minimum required CMake versioncmake_minimum_required(VERSION 3.13)# Pull in SDK (must be before project)include(pico_sdk_import.cmake)project(lcd C CXX ASM)set(CMAKE_C_STANDARD 11)set(CMAKE_CXX_STANDARD 17)if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0") message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")endif()# Initialize the SDKpico_sdk_init()add_compile_options( -Wall # Enable most warning messages -Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int -Wno-unused-function # we have some for the docs that aren't called )if (CMAKE_C_COMPILER_ID STREQUAL "GNU") add_compile_options(-Wno-maybe-uninitialized)endif()# name target executableadd_executable(lcd main.c)# pull in common dependencies and additional i2c hardware supporttarget_link_libraries(lcd pico_stdlib)# enable usb output, disable uart outputpico_enable_stdio_usb(lcd 1)pico_enable_stdio_uart(lcd 0)# create map/bin/hex file etc.pico_add_extra_outputs(lcd)
Statistics: Posted by breaker — Sun Jan 05, 2025 6:00 am