Mcapp Lab 10 (Student) LCD (Apr 25)
Mcapp Lab 10 (Student) LCD (Apr 25)
Diploma in CEN
Diploma in ELN
Name: Class:
Objectives:
1. To learn how to interface to the LCD module.
Equipment & Software:
1. Computer / notebook
2. Microchip MPLAB X IDE Version 6.00
3. Microchip XC8 Compiler Version 2.41
4. Target board with PICKit-4
Please go through this reading material before you come for the laboratory
session.
Introduction
Displays are vital components for embedded devices. It enables
the user to know the status of your application program. In this lab,
we shall learn how to use one of the commonly used LCD modules
in the market.
Reference: https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller
1 LCD Module 3
1.1 Pin Layout and Connection 3
1.2 Controlling the LCD Module 4
1.2.1 Enable Line 4
1.2.2 Register Select Line 4
1.2.3 Sending Control Instructions and Display Data 5
1.2.4 Initialising the LCD 7
1.2.5 Display Data RAM Address (DD RAM) 8
2 Exercises 10
2.1 Exercise 1: Display Text on Both Rows 10
3 Lab Extra 15
3.1 Exercise 2: Display Running Clock on LCD 15
3.2 Exercise 3: Display External Interrupt Counts on LCD 20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Ground
Data Pin 0
Data Pin 1
Data Pin 2
Data Pin 3
Data Pin 4
Data Pin 5
Data Pin 6
Data Pin 7
R/W
Backlight +
Contrast
Backlight -
+5V
RS
The LCD can be interfaced to a microcontroller via 4 or 8 data pins. For our purpose, in
order to save the number of I/Os used for interfacing, we shall use 4 data pins only.
PIC16F18877
RE0 E (Enable)
RD4 DB4
RD5 DB5
RD6 DB6 LCD
RD7 DB7 16 characters by 2 lines
4-bit Data Bus
Falling edge
2 triggered
E (Enable)
RS (Register Select)
1
RD<7:4>
Data LCD
Data Lines
The Register Select line is used by the LCD module to determine the type of data being
received on its data lines based on the following rule:
Question:
RE0 and RE1 are used to control the Enable and Register Select lines respectively.
Hence, they should be configured as ___________________.
Tick the correct answer.
Digital Input
Digital Output
2 1
1 0 0 0 0 1 0 0 Data Lines
Lower nibble is Upper nibble is
LCD
sent next sent fist
• Each nibble is sent out with a falling-edge transition on the Enable line.
• The upper nibble is sent out first and followed by the lower nibble.
LCD_E = 1;
__delay_ms(1); Falling Edge
LCD_E = 0;
__delay_ms(1);
}
void lcdWriteCtrlWord(char x)
{
char upper_nibble, lower_nibble;
void lcdWriteDspData(char x)
{
char upper_nibble, lower_nibble;
When the LCD is first powered up, we would need to initialise it through a few control
instructions including turning on the display, setting the cursor blink mode, bringing the
cursor to the home position, and others. The program segment below is the function to
initialise the LCD.
Sequence (a) to (d) is a special sequence, considering that when the LCD is first powered
up, it can either be in 4-bit mode or 8-bit mode. The algorithm in the special sequence
ensures that the LCD is in the correct 4-bit mode after the sequence (a) to (d) is
completed before sending the other control instructions to initialise it.
void initLCD()
{
// Special Sequence a) to d) required for 4-bit interface
__delay_ms(15); // a) 15ms LCD power-up delay
lcdWriteCtrlWord(0b00000011);// b) Function Set (DB4-DB7:8-bit interface)
__delay_ms(5); // c) 5ms delay
lcdWriteCtrlWord(0b00000010);// d) Function Set (DB4-DB7:4-bit interface)
There are a number of instructions that are being sent to the LCD, as you can see. As an
example, you can refer to the Appendix for the following instruction which serves to clear
the LCD display:
void lcdCtrl_ClearDisplay(void) {
lcdWriteCtrlWord(0b00000001);
}
The LCD module contains memory that is used for storing the text data to be displayed.
This memory can be represented by the following “memory map”.
Col 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
Line 1 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
Line 2 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F Hex
The numbers in the map represent the 7-bit DDRAM addresses for the LCD screen
positions (or cursor positions).
• For the first row, the address ranges from 0x00 to 0x0F.
• For the second row, the address ranges from 0x40 to 0x4F.
In the list of control instructions, the Set DDRAM Address instruction is used with the
memory map to set the desired cursor position.
What is the program statement to set the cursor position to line 2, column 8?
• Referring to the memory map, the memory address for line 2, column 8 is 0x47
(0b01000111).
• Taking the lower 7 bits (A6:A0) only, the complete 8-bit control instruction is
0b11000111, or 0xC7. Note that the most significant bit for the Set DD RAM Address
instruction is a 1.
• Hence, the program statement is:
lcdWriteCtrlWord(0b11000111);
We can come up with a function to set the cursor position (lcdCtrl_SetPos()). Allowing it
to take in 2 arguments, row and column, it takes the form below.
Why add
with 0x80?
Procedure
Project
config.h
main.c lcd.c
// Function Declarations:
// - Defined in this file:
void initSysPins(void);
Declare functions
// - Defined in other file(s): that are called in
void initLCD(void); this file
void lcdWriteDspData(char x);
void lcdCtrl_SetPos(char row, char col);
void main(void)
{ Two messages to
char message1[] = "Hello, World!"; be displayed
char message2[] = "I'm learning LCD";
unsigned int i;
initSysPins();
initLCD();
lcdCtrl_SetPos(2, 1);
for(i = 0; message2[i]!=0; i++) {
lcdWriteDspData(message2[i]);
}
PORTA = 0b00001010;
void initSysPins(void)
{
ANSELA = 0b00000000;
ANSELD = 0b00000000; Why does ANSELE and
ANSELE = 0b00000000; TRISE needs to be
TRISA = 0b11110000;
configured?
TRISD = 0b00001111;
TRISE = 0b11111100;
}
main.c
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]
‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘,’ ‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘!’ 0
That is, the program exits from the for-loop when it encounters a null in the
message[12] array element.
5. Download the lcd.c file from the LMS. Add it into the source file branch of this
project.
#include <xc.h>
#include "config.h"
// Function Declarations:
// Defined in this file:
void lcdWriteCtrlWord(char x);
void lcdWriteDspData(char x);
void lcdWriteNibble(char nibble);
void lcdCtrl_SetPos(unsigned char row, unsigned char col);
void lcdCtrl_FunctionSet(void);
void lcdCtrl_OnOffDisplay(char display_state, char cursor_state);
void lcdCtrl_SetEntryMode(void);
void lcdCtrl_ClearDisplay(void); Steps (a) to (d): Special
Sequence
void initLCD()
{
// Special Sequence a) to d) required for 4-bit interface
__delay_ms(15); // a) 15ms LCD power-up delay
lcdWriteCtrlWord(0b00000011); // b) Function Set (DB4-DB7:8-bit interface)
__delay_ms(5); // c) 5ms delay
lcdWriteCtrlWord(0b00000010); // d) Function Set (DB4-DB7:4-bit interface)
LCD_RS = 0;
lcdWriteNibble(upper_nibble); // Write upper nibble
lcdWriteNibble(lower_nibble); // Write lower nibble
}
LCD_RS = 1;
lcdWriteNibble(upper_nibble); // Write upper nibble
lcdWriteNibble(lower_nibble); // Write lower nibble
}
Function to write
void lcdWriteNibble(char nibble)
{ 4 bits (a nibble)
LCD_DATA_D7 = (nibble & 0b00001000) >> 3;
LCD_DATA_D6 = (nibble & 0b00000100) >> 2;
LCD_DATA_D5 = (nibble & 0b00000010) >> 1;
LCD_DATA_D4 = (nibble & 0b00000001);
LCD_E = 1;
__delay_ms(1);
LCD_E = 0;
__delay_ms(1);
}
Function to set
// row values are 1 to 2: cursor position
// col values are 1 to 16:
void lcdCtrl_SetPos(unsigned char row, unsigned char col)
{
unsigned char ramAddr; // Ctrl instruction to be sent
if (row == 1) // If row is 1:
ramAddr = col - 1; // Subtract 1 from the col
else // If row is 2:
ramAddr = 0x40 + col - 1; // Add 0x40 to ramAddr, and
// subtract 1 from the col
if(display_state == 1)
pattern |= 0b00000100; // Display on
if(cursor_state == 1)
pattern |= 0b00000011; // Cursor on and blinking
lcdWriteCtrlWord(pattern);
}
void lcdCtrl_SetEntryMode(void)
{
lcdWriteCtrlWord(0b00000110); // Entry mode - inc addr, no shift
}
void lcdCtrl_ClearDisplay(void)
{
lcdWriteCtrlWord(0b00000001); // Clear display & home position
}
lcd.c (Continued from previous page)
6. Build your project and download the program into the microcontroller. You should
see the messages appear on the LCD.
7. Complete the program design map by listing down the functions that are defined in
each source file.
Project
config.h
main.c lcd.c
_________ _________
_________ _________
_________ _________
In these extra exercises, you will learn how to integrate different parts of a program
together. As with some exercises you have done before using timer interrupts, you will
see a “background” task and a “foreground” task. You will learn how to link events in
the “background” interrupt with updates to the “foreground” display.
Problem Statement:
Using the 1 second timer, show the running time on the LCD in HH:MM:SS format.
Design Plan:
• The plan for the project is drawn in the program design map below.
• The file, dspTask.c manages the refresh of the time on the LCD whenever the 1-
second interrupt happens.
Project
config.h
3. The main.c file has the structure shown below. It calls the function,
dspTask_TimeOnLCD() continuously.
#include <xc.h>
#include "config.h"
// Function declarations:
void main(void)
{
initSysPins(); // Initialise the port pins
______________(); // Initialise Timer0
______________(); // Initialise the LCD
while(1) {
dspTask_TimeOnLCD();
}
}
void initSysPins(void)
{
ANSELA = ____________;
ANSELD = ____________;
ANSELE = ____________;
TRISA = ____________;
TRISD = ____________;
TRISE = ____________;
}
main.c
#include <xc.h>
#include "config.h"
// Function Declarations:
// - Declared in other file(s)
void lcdCtrl_SetPos(char x);
______________________
// Global variable(s):
unsigned char updateTime = 0;
unsigned char hour = 0, min = 0, sec = 0;
if(updateTime == 1) {
lcdCtrl_SetPos(1, 1);
5. In isr.c, the ISR reconfirms if the timer0 interrupt flag was set to 1. If it is, it calls the
dspTask_OnTimer0Interrupt() function. It then reloads the start count.
// Function Declarations
// - Defined in other file(s)
void __________________________(void);
void initSysTimer0(void)
{
____________________; // Disable Global Interrupt
____________________; // Set T0CON0
____________________; // Set T0CON1
____________________; // Set TMR0H
____________________; // Set TMR0L
____________________; // Clear Timer0 interrupt flag
____________________; // Enable Timer0
____________________; // Enable Global Interrupt
}
timer0.c
7. Include the file, lcd.c from previous lab exercises.
8. Build your project. Demonstrate that the running clock is displayed on the LCD.
Ponder:
How do the “background” and “foreground” tasks interact with each another? Why do
you want to design the program like this?
RD4 DB4
RD5 DB5
RD6 DB6 LCD
RD7 DB716 characters by 2 lines
4-bit Data Bus
Problem Statement:
Procedure:
This enables you to conceptualise how your program will turn out to be. Fill in the
blanks to indicate the files used.
config.h
// Function Declarations:
// - Defined in this file:
void _____________(void);
Declare
// - Defined in other file(s): the
void _____________(void); functions
void initLCD(void); that are
void lcdWriteDspData(char x); used in
void lcdCtrl_SetPos(char row, char col); this file
void dspTask_OnLCD(void);
void main(void)
{
char message1[] = "Steps Tracker";
char message2[] = "Today:";
unsigned int i;
lcdCtrl_SetPos(1, 1);
for(i = 0; message1[i]!=0; i++) {
lcdWriteDspData(message1[i]);
}
lcdCtrl_SetPos(2, 1);
for(i = 0; message2[i]!=0; i++) {
lcdWriteDspData(message2[i]);
}
PORTA = 0b00000000;
while(1) {
_______________();
}
}
o It will also keep a global variable to keep track of the number of button presses.
unsigned int extint_pbCount = 0;
o It has another global variable that is set to 1 whenever the external interrupt is
detected. And cleared to 0 whenever number display to LCD is completed.
unsigned int extint_RefreshLCDFlag = 0;
o And another, provided for other files, to get the number of button presses.
unsigned int extint_GetCount(void)
void initSysExtInt(void)
{
Configure
the
external
interrupt
}
extint.c
• In dspTask.c:
o It will have a function that will be called by main() continuously so that there
will be display updates on the LCD whenever the flag,
extint_RefreshLCDFlag goes to 1.
o void dspTask_OnLCD(void)
In the function, a call will be made to the extint_GetCount() to get the
number to be displayed.
// Function Declarations:
// - Defined in other file(s):
void lcdWriteDspData(char x);
void lcdCtrl_SetPos(unsigned char row, unsigned char col);
unsigned int extint_GetCount(void); By declaring with
keyword extern, it
// Extern Global Variable means that this
extern unsigned int extint_RefreshLCDFlag; variable was already
declared in another
void dspTask_OnLCD(void) file and is shared here.
{
unsigned int count;
unsigned char dig0, dig1, dig2, dig3; What's the purpose of
checking this flag?
if(extint_RefreshLCDFlag == 1) {
lcdCtrl_SetPos(2, 8);
lcdWriteDspData(dig3 + _____); // Add 0x30 to translate digit to ASCII
lcdWriteDspData(dig2 + _____);
lcdWriteDspData(dig1 + _____);
lcdWriteDspData(dig0 + _____);
dspTask.c
The "extern" Keyword
In C, the "extern" keyword is used to declare a variable that was first declared in another file
that we could not access. It is declared with this syntax:
// Function Declarations:
// - Defined in other file(s):
void extint_IncrCount(void);
isr.c
8. Complete the program design map by writing down the functions that are "offered" in
each source file. Draw the flow connections.
Project
config.h
9. Build the project and download the built program into the PIC16F18877 flash memory.
Press the push button RB1. Observe the LCD. Demonstrate your program to your
tutor.
Ponder:
(1) Identify which is the “background” and the “foreground” tasks. How do each
interact with the another?
(2) Recall how does the LCD distinguishes between display data and control
instructions.
~ End of Lab ~
Control Execution
D7 D6 D5 D4 D3 D2 D1 D0 Description
Word Time*
F = 1(5 by 10 dots)
F = 0(5 by 7 dots)
D = 1(Display ON)
D = 0(Display OFF)
Display
C = 1(Cursor Display ON)
On/Off 0 0 0 0 1 D C B 37µs
C = 0(Cursor Display OFF)
Control
B = 1(Blink)
B = 0(Don’t Blink)
S = 0(Don’t Shift)
* The execution time for the respective LCD control words are based on the Fosc (LCD built-in oscillator) =
270 kHz and are for your reference only.