Skip to content

Instantly share code, notes, and snippets.

@jgibbard
Last active June 10, 2025 20:49
Show Gist options
  • Save jgibbard/04a664990a2dc06f00ad8ca82f02ca4e to your computer and use it in GitHub Desktop.
Save jgibbard/04a664990a2dc06f00ad8ca82f02ca4e to your computer and use it in GitHub Desktop.
#include "lcd_test.h"
#define FCY 16000000UL
#include <libpic30.h>
#define LCD_RS LATBbits.LATB15
#define LCD_RW LATDbits.LATD5
#define LCD_E LATDbits.LATD4
#define LCD_DATA PORTE
#define LCD_DATA_TRIS TRISE
static void lcd_enable();
static uint8_t is_lcd_busy();
static void lcd_send_cmd(uint8_t cmd);
void lcd_setup() {
// Pin 44, RB15, AN15, LCD_RS
TRISBbits.TRISB15 = 0;
ANSBbits.ANSB15 = 0;
LATBbits.LATB15 = 0;
// Pin 82, RD5, LCD_RW
TRISDbits.TRISD5 = 0;
LATDbits.LATD5 = 0;
// Pin 81, RD4, LCD_E
TRISDbits.TRISD4 = 0;
LATDbits.LATD4 = 0;
// Pin 93, RE0, LCD_D0
TRISEbits.TRISE0 = 0;
LATEbits.LATE0 = 0;
// Pin 94, RE1, LCD_D1
TRISEbits.TRISE1 = 0;
LATEbits.LATE1 = 0;
// Pin 98, RE2, LCD_D2
TRISEbits.TRISE2 = 0;
LATEbits.LATE2 = 0;
// Pin 99, RE3, LCD_D3
TRISEbits.TRISE3 = 0;
LATEbits.LATE3 = 0;
// Pin 100, RE4, LCD_D4
TRISEbits.TRISE4 = 0;
LATEbits.LATE4 = 0;
// Pin 3, RE5, LCD_D5
TRISEbits.TRISE5 = 0;
LATEbits.LATE5 = 0;
// Pin 4, RE6, LCD_D6
TRISEbits.TRISE6 = 0;
LATEbits.LATE6 = 0;
// Pin 5, RE7, LCD_D7
TRISEbits.TRISE7 = 0;
LATEbits.LATE7 = 0;
__delay_ms(100);
// Set display settings
lcd_clear();
// Set cursor to inc, display shift off
// 0b 000001 ID S. ID 1 = inc address (cursor goes right), ID 0 = dec address (cursor goes left). S 1 = shift, 0 = no shift
lcd_send_cmd(0b00000110);
// Set display type to 8 wire connection, dual line mode, 5x8 dots
// 0b 0 0 1 DL N F x x. DL 1 = 8 wires, 0 = 4 wires. N 1 = 2 line display. 0 = 1 line display. F 1 = 5x10 dots, 0 = 5x8 dots
lcd_send_cmd(0b00111000);
// Turn on display, turn off cursor, turn off blink
// 0b00001 D C B. D = Display, C = Cursor, B = Blink. 1= ON 0 = OFF
lcd_send_cmd(0b00001100);
}
static void lcd_enable() {
LCD_E = 1;
__delay_us(1);
//delay_1us();
LCD_E = 0;
}
//Returns 1 if busy, 0 if ready
static uint8_t is_lcd_busy() {
// Set data lines as inputs
LCD_DATA_TRIS = 0b11111111;
// RW==1 : Read data
LCD_RW = 1;
// 0 = command, 1 = data
LCD_RS = 0;
// Pulse the enable line for 1us
LCD_E = 1;
__delay_us(1);
// Read data from LCD
uint16_t lcd_read_val = LCD_DATA;
LCD_E = 0;
// Set data lines as outputs
LCD_DATA_TRIS = 0;
// If MSB = 1 then return 1, else return 0
return ((lcd_read_val & 0b10000000) == 0b10000000);
}
static void lcd_send_cmd(uint8_t cmd) {
// loop until LCD ready
while(is_lcd_busy());
// Set data lines as inputs
LCD_DATA_TRIS = 0;
// Set to write mode
LCD_RW = 0;
// 0 = command, 1 = data
LCD_RS = 0;
// Set data lines to cmd
LCD_DATA = cmd;
// Pulse the enable for 1 us
lcd_enable();
}
void lcd_send_char(uint8_t data) {
// Wait until LCD is not busy
while(is_lcd_busy());
// Set data lines to inputs
LCD_DATA_TRIS = 0;
// Set to write mode
LCD_RW = 0;
// Set to data mode
LCD_RS = 1;
// Set data lines to data
LCD_DATA = data;
// Pulse the enable line for 1us
lcd_enable();
}
void lcd_send_string(const uint8_t *var) {
// While *var != 0 send *var and inc to next char
while(*var) {
lcd_send_char(*var++);
}
}
void lcd_set_cursor(uint8_t row, uint8_t column) {
if (row == 1) {
// Set DRAM address 0b1xxxxxxx = row 1, 0b10000000 = Row 1 column 1, 0b10000001 = row 1, column 2, etc
lcd_send_cmd(0b10000000 + (column-1));
} else if (row==2) {
// Set DRAM address 0b11xxxxxx = row 2
lcd_send_cmd(0b11000000 + (column-1));
}
}
void lcd_home() {
// Sets DRAM to address 0, and returns display from being shifted
lcd_send_cmd(0b00000010);
}
void lcd_clear() {
// Clears all DRAM, sets DRAM address to 0
lcd_send_cmd(0b00000001);
}
void lcd_cursor_shift(uint8_t direction) {
// Sends command to shift cursor
// Bit 2 = 0 = Shift right. // Bit 2 = 1 = Shift left
lcd_send_cmd(0b00010000 | direction);
}
void lcd_screen_shift(uint8_t direction) {
//Sends command to shift display
lcd_send_cmd(0b00011000 | direction);
}
// Custom char generator: https://www.quinapalus.com/hd44780udg.html
void lcd_add_char(uint8_t address,
uint8_t line0, uint8_t line1, uint8_t line2, uint8_t line3,
uint8_t line4, uint8_t line5, uint8_t line6, uint8_t line7) {
// Set address to CGRAM. CHAR0 is at 0x40, CHAR1 is at 0x48,
// CHAR2 is at 0x56, etc. 8 CHARS can be stored
lcd_send_cmd(0x40 + address);
// Send line one of char 0bXXX11111. 3MSBs are ignored
lcd_send_char(line0);
// Send line two of char 0bXXX11111. 3MSBs are ignored
lcd_send_char(line1);
// etc
lcd_send_char(line2);
lcd_send_char(line3);
lcd_send_char(line4);
lcd_send_char(line5);
lcd_send_char(line6);
lcd_send_char(line7);
// Set address back to DRAM, location 1,1
lcd_send_cmd(0b10000000);
}
#ifndef LCD_TEST_H
#define LCD_TEST_H
#include "xc.h"
#define LCD_SHIFT_RIGHT 0b00000100
#define LCD_SHIFT_LEFT 0b00000000
void lcd_setup();
void lcd_send_string(const uint8_t *var);
void lcd_send_char(uint8_t data);
void lcd_set_cursor(uint8_t row, uint8_t column);
void lcd_home();
void lcd_clear();
void lcd_cursor_shift(uint8_t direction);
void lcd_screen_shift(uint8_t direction);
void lcd_add_char(uint8_t address,
uint8_t line0, uint8_t line1, uint8_t line2, uint8_t line3,
uint8_t line4, uint8_t line5, uint8_t line6, uint8_t line7);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment