In this article I'm using a PIC 16F628a to demonstrate one way of using a 4 line LCD.

The hardware

The following schematic is put on a breadboard: Schematic layout

Click here for a bigger view.

BOM - Bill of material

This is what you need.

Partlist

Exported from PIC16F628A-16x4-lcd-demo.sch at 08.11.17 20:56

EAGLE Version 7.2.0 Copyright (c) 1988-2014 CadSoft

Assembly variant: 

Part     Value          Device          Package      Library      Sheet

C1       0.1uF          C-EU025-024X044 C025-024X044 rcl          1
C2       100uF          CPOL-EUE2.5-5   E2,5-5       rcl          1
C3       0.1uF          C-EU025-024X044 C025-024X044 rcl          1
C4       100uF          CPOL-EUE2.5-5   E2,5-5       rcl          1
C5       18pF           C-EU025-024X044 C025-024X044 rcl          1
C6       18pF           C-EU025-024X044 C025-024X044 rcl          1
C7       0.1uF          C-EUC0805K      C0805K       rcl          1
C8       0.1uF          C-EUC0805K      C0805K       rcl          1
D1       1N4004         DIODE-SMB       SMB          diode        1
IC1      78L05Z         78L05Z          TO92         linear       1
IC3      PIC16F628a     DIL18S          SOCKET-18    ic-package   1
JP1      ICSP           PINHD-1X5/90    1X05/90      pinhead      1
JP5      2*16 LCD       PINHD-1X16      1X16         pinhead      1
Q1       16MHz          XTAL/S          QS           special      1
R1       10K            R-EU_R0805      R0805        rcl          1
R2       10K            TRIM_EU-CA6V    CA6V         pot          1
TP1      TPPAD1-13Y     TPPAD1-13Y      P1-13Y       testpad      1
TP2      TPPAD1-13Y     TPPAD1-13Y      P1-13Y       testpad      1
TP3      TPPAD1-13Y     TPPAD1-13Y      P1-13Y       testpad      1
TP4      TPPAD1-13Y     TPPAD1-13Y      P1-13Y       testpad      1
TP5      TPPAD1-13Y     TPPAD1-13Y      P1-13Y       testpad      1
TP6      TPPAD1-13Y     TPPAD1-13Y      P1-13Y       testpad      1
X1       12vDC          W237-102        W237-102     con-wago-500 1

The Breadboard

This is how the breadboard look like: Breadboard layout
Breadboard layout
Breadboard layout

The software

This is the code that's loaded into the PIC.

// INCLUDES
#include <xc.h>

// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

#pragma warning disable 359     // Disable warning 359 - illegal conv between pointer types
#pragma warning disable 373     // Disable warning 373 - signed to unsigned conversion

// DEFINITIONS
#define _XTAL_FREQ 16000000     // refenrence freq for the compiler  
#define Rs PORTAbits.RA0        // Rs is connected to RA0
#define En PORTAbits.RA1        // En is connected to RA1

#define lcd_port TRISB          // lcd port b
#define lcdLine1 0x00           // line one begins here
#define lcdLine2 0x40           // line two begins here
#define lcdLine3 0x90           // line  three begins here
#define lcdLine4 0xd0           // line four begins here

// VARIABLES

// FUNCTION PROTOTYPE
void lcd_cmd(unsigned char cmd);
void lcd_data(unsigned char dat);
void lcd_init(void);
void lcd_line1(void);
void lcd_line2(void);
void lcd_setcursor(unsigned char loc);
int lcd_strobe(void);
void lcd_write(unsigned char dat);
void lcd_writestr(const unsigned char *c);
void show_welcome();

// FUNCTIONS
// function to pulse the En pin high
int lcd_strobe(void)
{
    En = 1;
    __delay_us(1);
    En = 0;
}

// function to write to the lcd port
void lcd_write(unsigned char dat)
{
    lcd_port &= 0x0f;           // get current port and clear upper bits
    lcd_port |= (dat & 0xf0);   // combine upper and lower, leave lower 
    lcd_strobe();

    lcd_port &= 0x0f;
    lcd_port |= ((dat << 4) & (0xf0));  // combine upper and lower
    lcd_strobe();
    __delay_ms(2);                      // little delay for lcd to process
}

// function to set lcd in command mode
void lcd_cmd(unsigned char cmd)
{
    Rs = 0;             // rs low for cmd mode
    lcd_write(cmd);
}

// functionto set lcd in data mode
void lcd_data (unsigned char dat)
{
    Rs = 1;             // rs high for data mode
    lcd_write(dat);
}

// function to initialize the lcd
void lcd_init(void)
{
    lcd_port &= 0x0f;   // clear upper bits
    lcd_port |= 0x30;   // send data to d7-4
    Rs = 0;
    lcd_strobe();
    __delay_ms(10);
    lcd_strobe();;
    __delay_ms(10);
    lcd_strobe();
    __delay_ms(10);

    lcd_port &= 0x0f;   // clear upper bits
    lcd_port |= 0x30;   // send data to d7-4
    lcd_strobe();
    __delay_ms(50);

    lcd_cmd(0x28);  // 4-bit, 2-line, 5x7 font
    lcd_cmd(0x0e);  // display on, cursor on, blink off
    lcd_cmd(0x06);  // auto increment, no shift
    lcd_cmd(0x80);  // address ddram with 0 offset 80h
}

// function to write a strng to the lcd
void lcd_writestr(const unsigned char *c)
{
    while (*c != '\0')
    {
        lcd_data(*c);
        c++;
    }
}

// function to place the cursor on the lcd
void lcd_setcursor(unsigned char loc)
{
    lcd_cmd(loc | 0x80);
}

// function to move cursor to 1st place on line 1
void lcd_line1(void)
{
    lcd_setcursor(lcdLine1);
}

// function to move cursor to 1st place on line 2
void lcd_line2(void)
{
    lcd_setcursor(lcdLine2);
}

// function to move cursor to 1st place on line 3
void lcd_line3(void)
{
    lcd_setcursor(lcdLine3);
}

// function to move cursor to 1st place on line 4
void lcd_line4(void)
{
    lcd_setcursor(lcdLine4);
}

// Function that shows a welcome message
void show_welcome()
{
    lcd_writestr("    16x4 LCD");
    lcd_line2();
    lcd_writestr("   PIC16F628a");
    lcd_line3();
    lcd_writestr("Line 3");
    lcd_line4();
    lcd_writestr("Line 4");
    __delay_ms(2000);    
}

/* THIS IS THE MAIN PROGRAM LOOP */
void main(void) 
{
    CMCON = 0x07;           // Turn comparators off

    TRISA = 0b00000000;     // All output
    TRISB = 0b00000000;     // All output
    PORTA = 0b00000000;     // All low
    PORTB = 0b00000000;     // All low

    lcd_strobe();    
    lcd_init();    

    show_welcome();

while (1)
{
    // Nothing to do.
} // end while

} // end main