C5 - Parallel Input/Output Ports
Interfacing
Objectives
•Describe I/O ports interfacing to LEDs, Switches, 7-
Segment Display, LCD and keyboard interfacing.
•Write the PIC18 programming in C.
•Apply the I/O system interfacing.
TRIS Register
• Used for setting up the Ports as input or output
(PORTA to PORTE)
• If TRISx = 0 ; PORTx = output
• If TRISx = 1 ; PORTx = input
e.g.
TRISBbits.TRISB7=0; //PB7 as output;
TRISBbits.TRISB0=1; //PB1 as input;
TRISC = 0xFF //PC as intput;
TRISD = 0x00 //PD as output;
I/O Ports
Seven Segment
Objectives
• Describe the functions of the pins of a typical LCD
• Interface a LCD to the PIC18
• Describe the key press
• Interface a Keypad to the PIC18
• Why LCD?
• The ability to display numbers, charaters and graphics
• Incorporation of a refreshing controller into the LCD,
thereby relieving the CPU of the task of refreshing the
LCD
• Ease for programming for characters and graphics
The LCD
LCD
Pin
Pin Descriptions
Symbol I/O
- HD44780 Description
model
1 VSS -- Ground
2 VCC -- +5V Power Supply
3 VEE -- Power Supply to Control Contrast
4 RS I RS=0 to Select Command Register
RS =1 to Select Data Register
5 R/W I R/W=0 for Write
R/W=1 for Read
6 E I/O Enable
7 DB0 I/O The 8-bit Data Bus
8 DB1 I/O The 8-bit Data Bus
9 DB2 I/O The 8-bit Data Bus
10 DB3 I/O The 8-bit Data Bus
11 DB4 I/O The 8-bit Data Bus
12 DB5 I/O The 8-bit Data Bus
13 DB6 I/O The 8-bit Data Bus
14 DB7 I/O The 8-bit Data Bus
• LCD screen consist of two lines of16 characters each
• Every character consists of 5x8 or 5x11 dot matrix
• Its’ three memory blocks:
– DDRAM - Display Data RAM
– CGRAM - Character Generator RAM
– CGROM - Character Generator ROM
Model with backlights
CGROM memory
contains default
character map
Cursor Address for Some LCDs
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
16X2 LCD
LCD Control
• R/W (Read/Write)
– R/W = 0: Write information to the LCD
– R/W = 1: Read information from the LCD
• E
– To latch information presented to its data pins
– When data is supplied to data pins, a HIGH-to-LOW
pulse must be applied to the E pin in order for the LCD
to latch in the data present at the data pins
– This pulse must be a minimum of 450nS wide
• RS (Register Select)
– RS = 0: The instruction command code is selected,
allowing the user to send command such as clear
display, cursor at home
– RS = 1: The data register is selected , allowing the user
to send data to be displayed on the LCD.
• D0-D7
– Are used to send information to the LCD or read the
contents of the LCD’s internal register.
• LCD Command (Page 475)
– 01 – clr display sereen
– 02 - return home
– 38 - 2line and 5 x 7
EX
XTAL 2 MHz, for instruction 2 μs
#define LCD PORTB //define data port
#define RS PORTBbits.RB5
#define E PORTBbits.RB4
void SendLCDdata(char data, char rs)
{
LCD = data >>4; //send left nibble
RS = rs; //control RS
E = 0; //pulse E
E = 1;
Delay10TCYx (2); //delay 40 μs
LCD = data & 0x0F; //send right nibble
RS = rs; //control RS
E = 1; //pulse E
E = 0;
Delay10TCYx (2); //delay 40 μs
}
void intLCD(void)
{
char a;
Delay1TCYx (10); //delay 20 ms
for (a=0;a<3;a++)
{
SendLCDdata(0x20, 0); //send 0x20
Delay1TCYx (3); //wait 6 ms
}
SendLCDdata(0x28, 0);
SendLCDdata(0x01, 0);
Delay1TCYx (1);
SendLCDdata(0x0C, 0);
SendLCDdata(0x06, 0);
}
EX
#define LCD PORTB //define data port
#define RS PORTBbits.RB5
#define E PORTBbits.RB4
#define RW PORTBbits.RB6
#define LCD_TRIS TRISB
void SendLCDdataWbusy(char data, char rs)
{
RW =0; //select write mode
LCD = data >>4; //send left nibble
RS = rs; //control RS
E = 1; //pulse E
E = 0;
Delay10TCYx (2); //delay 40 μs
LCD = data & 0x0F; //send right nibble
RS = rs; //control RS
E = 1; //pulse E
E = 0;
Delay10TCYx (2); //delay 40 μs
RW=1; //select read mode
RS=1; //set R/W
LCD_TRIS = 0x0F; //set RB0-RB3 as input
RS=0; //read busy command
E=1; //read high nibble
E=0;
data=LCD; //read busy bit
while(data&8)==8;
{
E=1; //read low nibble
E=0;
E=1; //pulse E
E=0; //read high nibble
data=LCD; //read LCD
}
LCD_TRIS=0; //prgPORTB as output
)
Ex. Sending commands and data to LCD with time delay
How to send characters (command/data) to the LCD without
checking the busy flag. Send letters ‘M’, ‘D’ and ‘E’ to the
LCD using delay.
Hint.
Delay (5 – 10 ms) between issuing character to the LCD
LDELAY for power-up process
SDELAY for the LCD’s enable input
#include <P18f4580.h>
#define ldata PORTD //LCD Data Pin
#define rs PORTBbits.RB0
#define rw PORTBbits.RB1
#define en PORTBbits.RB2
void main()
{
TRISD = 0x00 //PD as output;
TRISB = 0x00 //PB as output;
en =0; //enable idle low
MSDelay(250); //long delay
lcdcmd(0x38) //init. 2 line 5x7matrix
MSDelay(250);
lcdcmd(0x0E) //Display on, cursor on
MSDelay(15);
lcdcmd(0x01) //clear LCD
MSDelay(15);
lcdcmd(0x06) //shift cursor right
MSDelay(15);
lcdcmd(0x86) //line 1,position 6
MSDelay(15);
lcddata(‘M’) //Display letter ‘M’
MSDelay(15);
lcddata(‘D’) //Display letter ‘M’
MSDelay(15);
lcddata(‘E’) //Display letter ‘M’
}
void lcdcmd(unsigned character value)
{
idata = value; //put the value on the pins
rs = 0;
rw = 0;
en = 1; //strobe the enable pin
MSDelay(1);
en =0;
}
void lcddata(unsigned character value)
{
idata = value; //put the value on the pins
rs = 1;
rw = 0;
en = 1; //strobe the enable pin
MSDelay(1);
en =0;
}
void MSDelay(unsigned int itime)
{
insigned int i, j;
for (i=0; i<itime; i++)
for (j=0;J<135; j++)
}
Ex. Sending command or data to LCD using busy flag
Send letters ‘M’, ‘D’ and ‘E’ to the LCD using busy flag
Use RS = 0 to read the busy flag bit to see if the LCD is
ready to receive information.
To read command register, R/W=1, RS=0 and E=L to H.
When busy flag (D7=1), LCD is busy and not accept new
info.
When D7=0, LCD is ready to accept new info either
command or data.
E (Page 479)
Write – negative edge trigger
Read – positive edge trigger
#include <P18f4580.h>
#define ldata PORTD //LCD Data Pin
#define rs PORTBbits.RB0
#define rw PORTBbits.RB1
#define en PORTBbits.RB2
#define busy PORTDbits.RD7 //busy=PD.7
void main()
{
TRISD = 0x00 //PD as output;
TRISB = 0x00 //PB as output;
en =0; //enable idle low
MSDelay(250); //long delay
lcdcmd(0x38) //init. 2 line 5x7matrix
MSDelay(250);
lcdcmd(0x0E) //Display on, cursor on
lcdready(); //check LCD busy flag
lcdcmd(0x01) //clear LCD
lcdready(); //check LCD busy flag
lcdcmd(0x06) //shift cursor right
lcdready(); //check LCD busy flag
lcdcmd(0x86) //line 1,position 6
lcdready(); //check LCD busy flag
lcddata(‘M’) //Display letter ‘M’
lcdready(); //check LCD busy flag
lcddata(‘D’) //Display letter ‘M’
lcdready(); //check LCD busy flag
lcddata(‘E’) //Display letter ‘M’
}
void lcdcmd(unsigned character value)
{
idata = value; //put the value on the pins
rs = 0;
rw = 0;
en = 1; //strobe the enable pin
MSDelay(1);
en =0;
}
void lcddata(unsigned character value)
{
idata = value; //put the value on the pins
rs = 1;
rw = 0;
en = 1; //strobe the enable pin
MSDelay(1);
en =0;
}
void lcdready()
{
TRISD = 0xFF; //PD as input
rs = 0;
rw = 1;
do //wait for busy flag
{
en=1; //strobe the enable pin
MSDelay(1);
en=0;
}while(busy==1);
TRISD=0;
}
void MSDelay(unsigned int itime)
{
insigned int i, j;
for (i=0; i<itime; i++)
for (j=0;J<135; j++)
}
EX Display data in ROM
#include <P18f4580.h>
#define ldata PORTD //LCD Data Pin
#define rs PORTBbits.RB0
#define rw PORTBbits.RB1
#define en PORTBbits.RB2
#pragma romdata mycom=0x300 //ROM addrs
Far rom const char mycom[ ] = (0x0e,0x01,0x06,0x84);
#pragma romdata mydata=0x320 //ROM addrs
Far rom const char mydata[ ] = “Hello”;
void main()
{
unsigned char z=0;
TRISD = 0x00 //PD as output;
TRISB = 0x00 //PB as output;
en =0; //enable idle low
MSDelay(250); //long delay
lcdcmd(0x38) //init. 2 line 5x7matrix
MSDelay(250);
//send out the command
for(;z<4;z++)
{
lcdcmd(mycom[z]);
MSDelay(15);
}
//send out the data
for(z=0;z<5;z++)
{
lcdcmd(mycom[z]);
MSDelay(15);
While(1) //infinite loop
}
void lcdcmd(unsigned character value)
{
idata=value //put the value on the pin
rs = 0;
rw = 0;
en = 1; //strobe the enable pin
MSDelay(1);
en =0;
}
void lcddata(unsigned character value)
{
idata=value //put the value on the pin
rs = 1;
rw = 0;
en = 1; //strobe the enable pin
MSDelay(1);
en =0;
}
void MSDelay(unsigned int itime)
{
insigned int i, j;
for (i=0; i<itime; i++)
for (j=0;J<135; j++)
}
Interfacing the Keyboard
• Organized in a matrix of rows and coloums
• The CPU accesses both rows and coloums thru’
port; therefore with 8-bit ports, an 8 X 8 matrix of
keys can be connected to a microcontroller
• Key pressed: Row and column make a contact
• Key press detection method:
– Interrupt method
– Scanning method
EX
Row RA0 to RA4
Col RB0 to RB2
Rom near char lookup key [ ] =
{
1,4,7,10
2,5,8,0
3,,6, 9,11
)
#define KEYPORT PORTA
#define DELAY 15
void Switch (char bit)
{
do //wait for release
{
while((KEYPORT&bit)!=bit);
Delay1KTCYx(DELAY);
}
while((KEYPORT&bit)!=bit);
do //wait for press
{
while((KEYPORT&bit)==bit);
Delay1KTCYx(DELAY);
}
while((KEYPORT&bit)==bit);
}
unsigned char key(void)
#define MASK 0x0F //set mask
#define row 4
char a;
char keyCode;
PORTB =keyCode=0; //clr PB and keyCode
Switch(MASK) //debounce and wait for any key
PORTB=0xFE //select a left most col
while((PORTA&MASK)==MASK); //while no key is found
{
PORTB=(PORTB<<1)|1; //gets next col
KeyCode +=ROWS //add row tokeycode
}
For (a=1;a!=0;a<<=1)
{
If(PORTA&a)==0)
break;
keyCode++
}
Return lookupkey(keyCode) //lookup
correct keycode
}
Interrupt Method of Key Press Detection
Column (RB4-RB7)
Row (RB0-RB3)
4 X 4 Matrix Keyboard Connection to Ports
Keyboard Debounce
Noise
Stable
EX:
Read the keypad and sends the result to the serial port
Identify the row and column of the pressed key for the
following:
RB3-RB0 = 1110 (Row)
RB7-RB4 = 1011 (Column)
Try This:
RB3-RB0 = 1101 (Row)
RB7-RB4 = 1011
(Column)
#include <P18f4580.h>
void SerTX(unsigned char x);
void RBIF_ISR(void);
void MSDelay(unsigned int millisecs);
Unsigned char keypad[4] [4] = (‘0’,’1’,’2’,’3’,
‘4’,’5’,’6’,’7’
‘8’,’9’,’A’,’B’
‘C’,’D’,’E’,’F’);
#pragma code HiPrio_int=0x0008 //high-priority interrupt
void my_HiPrio_int (void)
{
_asm
GOTO chk_isr
_endasm
}
#pragma code
#pragma interrupt chk_isr //which ISR
void chk_isr(void)
{
if (INTCON2bits.RBIF==1) //RBIF caused interrupt;
RBIF_ISR( ); //yes goto RBIF_ISR
}
#pragma code
void main()
{
TRISD = 0x00 //PD as output;
INTCON2bits.RBPU=0 //enable PB pullup
TRISB = 0xF0; //PB as input and output;
PORTB = 0xF0; //PB clear PB low
while( PORTB = 0xF0); //wait until key not pressed
TXSTA = 0x20; //low baud rate 8-bit
SPBRG = 15 //9600 baud rate
TXSTAbits.TXEN = 1; //enable tx
RCSTAbits.SPEN = 1; //enable serial port
INTCONbits.RBIE=1; //enable PB int on change
INTCONbits.GIE=1; //enable all int globally
while(1)
}
void RBIF_ISR(void) //which key pressed
{
insigned char temp, COL=0,ROW=4;
MSDelay(15);
temp=PORTB //get column
temp ^=0xF0; //invert high nibble
if(!temp) return; //if false alarmreturn
while(temp<<=1) COL++ //find the column
PORTB=0xFE; //gound row 0
if(PORTB != 0xFE) //did high nibble change
ROW=0; //yes row 0
else{
PORTB=0xFD; //gound row 1
if(PORTB != 0xFE) //did high nibble change
ROW=1; //yes row 1
else
else{
PORTB=0xFB; //gound row 2
if(PORTB != 0xFB) //did high nibble change
ROW=2; //yes row 2
else{
PORTB=0xF7; //gound row 3
if(PORTB != 0xF7) //did high nibble change
ROW=3; //yes row 3
}
}
}
if(ROW<4) //find valid row
serTX(keypad[row][col]) //then send char
while(PORTB!=0xF0) PORTB=0xF0 //wait for release
INTCONbits.RBIF=0; //reset flag
)
void SeTX(unsigned char x) //send char
{
while(PIR1bits.TXIF!=1); //wait until ready
TXREG=x; //send char out serialport
}
void MSDelay(unsigned int millisecs)
{
insigned int i, j;
for (i=0; i<millisecs; i++)
for (j=0;J<135; j++)
}