#define clrRS
#define setRS
#define clrE
#define setE
lcdcntrl &= ~RS
lcdcntrl |= RS
lcdcntrl &= ~E
lcdcntrl |= E
#define lcdcls
lcd_send_byte(0,0x01)
#define line1
#define line2
lcd_gotoxy(1,1)
lcd_gotoxy(2,1)
#define backliteON
#define backliteOFF
LATC1 = 1
LATC1 = 0
char LCD_INIT_STRING[5] = {0x28,0x08,0x01,0x06,
0x0E};
The LCD definitions and macros are pretty much self-explanatory. The hex bytes that associate with E and RS
represent bit locations within PORTB. The PORTB bit
positions are used by the set and clear macros.
All of the four-bit LCD driver functions are based on the
lcd_send_nibble function:
void lcd_send_nibble( char n )
{
databus &= 0xF0;
databus |= n >> 4;
_delay(5);
setE;
_delay(5);
clrE;
}
The lcd_send_nibble function clears out the low nibble
of PORTB while preserving the bit states of PORTB’s high
nibble. Other LCD functions that use lcd_send_nibble
always send the byte to the LCD’s most significant byte first.
Thus, the nibble to send to the LCD (n) is always shifted to
the lower nibble position of PORTB.
The HI-TECH C compiler includes the _delay function in
a library that resides within the htc.h include file. The
_delay function counts instruction cycles to produce a delay.
With a clock of 20 MHz, that puts each instruction cycle at
200 nS. Thus, _delay( 5) will produce a delay of 1,000 nS.
The minimum E cycle time for the Newhaven NHD-0208BZ-
FL-YBW LCD is listed as 500 nS with a minimum E pulse
width of 230 nS. So, an argument of 5 in the _delay
function is very conservative.
The lcd_init function is the first LCD function to call the
lcd_send_nibble function:
void lcd_init(void)
{
char j8;
clrRS;
clrE;
clrRW;
_delay(80000);
lcd_send_nibble(0x30);
_delay(30000);
lcd_send_nibble(0x30);
_delay(5000);
lcd_send_nibble(0x30);
_delay(10000);
lcd_send_nibble(0x20);
for(j8=0;j8<5;++j8)
{
_delay(10000);
lcd_send_byte(0,LCD_INIT_STRING[j8]);
}
}
The sequence of nibbles, bytes, and time delays
contained within the lcd_init function place the LCD in four-bit mode. Note the 0 in the argument of the lcd_send_byte
function. An LCD command is sent with the LCD RS pin
held logically low. A zero in this position of the
lcd_send_byte function causes the LCD’s RS pin to be
driven logically low. Conversely, a one in the lcd_send_byte
argument forces the LCD’s RS pin logically high and the
function’s payload is designated as a character. Here’s the
source code for the second function to call the
lcd_send_nibble function:
void lcd_send_byte( char address, char n )
{
clrE;
switch (address)
{
case 0:
clrRS;
break;
case 1:
setRS;
break;
default:
setRS;
break;
}
_delay(5000);
lcd_send_nibble (n);
lcd_send_nibble (n << 4);
_delay(5000);
}
The LCD in our design is configured physically as two
lines with eight characters per line. Arranging the LCD
characters as eight-byte arrays makes for an easy way to
display LCD messages:
char lcdmsg_servo[] = “ SERVO “;
With each message packaged as eight bytes, displaying
SERVO on the upper line of the LCD is simple:
char msg8;
line1;
for(msg8=0;msg8<8;++msg8)
lcd_send_byte(1,lcdmsg_servo[msg8]);
Mixing in the Optical Encoder
Suppose we wanted to alternately display SERVO1 and
SERVO2 by rotating the optical encoder’s shaft. First, we
would define our eight-byte messages. Our six-byte SERVOx
SERVO 07.2010 47