I previously posted an LCD display example program for the dsPIC30F4011 microcontroller. This is the same program adapted for the PIC18F4620 microcontroller. I’ll have to update this later with a circuit diagram, but here’s a quick photo of the program running on a breadboard circuit. Hopefully you can work out which pins are which from the code and/or photo, as well as by referring to the more complete documentation for the dsPIC30F4011 example.
//
// lcd.c - LCD display examplefor dsPIC18F4620
// Written by Ted Burke - Last updated 8-10-2013
//
#include <xc.h>
// Select clock oscillator (default frequency Fosc=1MHz -> Tcy = 4us).
// Disable reset pin, watchdog timer, low voltage programming and
// brown-out reset.
#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF,BOREN=OFF
// Select which pins the program will use for the LCD screen
// control signals, RS, RW and E.
// NB I had to change these from the names used in my previous
// dsPIC30F4011 example to avoid a clash with the equivalent
// definitions in the XC8 compiler's peripheral library.
#define PIN_RS LATDbits.LATD7
#define PIN_RW LATDbits.LATD6
#define PIN_E LATDbits.LATD5
// Select a pin to use for the flashing LED
#define PIN_LED LATDbits.LATD4
// Function prototypes for transmitting to LCD
void delay_ms(unsigned int n);
void send_nibble(unsigned char nibble);
void send_command_byte(unsigned char byte);
void send_data_byte(unsigned char byte);
int main()
{
TRISD = 0b00000000; // Set RD0-7 as digital outputs
// Let's just write to the LCD and never read!
// We'll wait 2ms after every command since we can't
// check the busy flag.
PIN_RW = 0;
PIN_RS = 0;
PIN_E = 1;
// Initialisation
delay_ms(16); // must be more than 15ms
send_nibble(0b0011);
delay_ms(5); // must be more than 4.1ms
send_nibble(0b0011);
delay_ms(1); // must be more than 100us
send_nibble(0b0011);
delay_ms(5); // must be more than 4.1ms
send_nibble(0b0010); // select 4-bit mode
// Display settings
send_command_byte(0b00101000); // N=0 : 2 lines (half lines!), F=0 : 5x7 font
send_command_byte(0b00001000); // Display: display off, cursor off, blink off
send_command_byte(0b00000001); // Clear display
send_command_byte(0b00000110); // Set entry mode: ID=1, S=0
send_command_byte(0b00001111); // Display: display on, cursor on, blink on
// Define two 8 character strings
const char line1[] = " Ted's ";
const char line2[] = "PIC18F ";
// Write the two strings to lines 1 and 2
int n;
send_command_byte(0x02); // Go to start of line 1
for (n=0 ; n<8 ; ++n) send_data_byte(line1[n]);
send_command_byte(0xC0); // Go to start of line 2
for (n=0 ; n<8 ; ++n) send_data_byte(line2[n]);
// Now just blink LED indefinitely
while(1)
{
PIN_LED = 1;
delay_ms(500);
PIN_LED = 0;
delay_ms(500);
}
}
// Delay by specified number of milliseconds
void delay_ms(unsigned int n)
{
// At Fosc=1Mhz, Tcy is 4us. That's the time
// taken to perform one machine code instruction.
// Therefore a delay of 250 x Tcy = 1ms.
while(n--) _delay(250);
}
void send_nibble(unsigned char nibble)
{
// Set RD0-3 without affecting RD4-7
LATD = (LATD & 0xF0) + nibble;
delay_ms(1);
// Note: data is latched on falling edge of pin E
PIN_E = 0;
delay_ms(1);
PIN_E = 1;
delay_ms(2); // Enough time even for slowest command
}
// Send a command byte (i.e. with pin RS low)
void send_command_byte(unsigned char byte)
{
PIN_RS = 0;
send_nibble(byte >> 4);
send_nibble(byte & 0xF);
}
// Send a data byte (i.e. with pin RS high)
void send_data_byte(unsigned char byte)
{
PIN_RS = 1;
send_nibble(byte >> 4);
send_nibble(byte & 0xF);
}
I compiled the program using Microchip’s XC8 compiler. This was the command I used:
xc8 --chip=18F4620 lcd.c
I then used the PICkit 2 application to transfer the compiled hex file onto the microcontroller.
