typedef unsigned char ubyte;
typedef signed char sbyte;
typedef unsigned short word;
typedef unsigned long dword;
//============================================================================
ubyte Read_LCD_Address(void)
{
ubyte
return_value;
ubyte
timeout;
//Poll the LCD's busy line until it is clear.
//Make register select 0
porta&=~PORTA_LCD_RS;
//Make R/W 1=read, update physical port.
PORTA=(porta|=PORTA_LCD_RW);
//Set PORTB to all inputs.
TRISB=(trisb=0xFF);
//Enable the controller's data onto the bus.
PORTA=(porta|=PORTA_LCD_E);
//Test the port's bit, wait for the bit to go low
if(PORTB&PORTB_LCD_DATA_BUSY)
for(timeout=255;(PORTB&PORTB_LCD_DATA_BUSY)&&timeout;timeout--);
//Read the LCD controller's data, mask off the busy bit.
return_value=PORTB&0x7F;
//Get the bus back from the controller
PORTA=(porta&=~PORTA_LCD_E);
//Turn port B back to its default output state.
TRISB=(trisb=0);
return(return_value);
}
//============================================================================
void Write_LCD_Data(ubyte data)
{
ubyte
timeout;
//Poll the LCD's busy line until it is clear.
//Make register select 0
porta&=~PORTA_LCD_RS;
//Make R/W 1=read, update physical port.
PORTA=(porta|=PORTA_LCD_RW);
//Set PORTB to all inputs.
TRISB=(trisb=0xFF);
//Enable the controller's data onto the bus.
PORTA=(porta|=PORTA_LCD_E);
//Test the port's bit, wait for the bit to go low
if(PORTB&PORTB_LCD_DATA_BUSY)
for(timeout=255;(PORTB&PORTB_LCD_DATA_BUSY)&&timeout;timeout--);
//Get the bus back from the controller
PORTA=(porta&=~PORTA_LCD_E);
//Turn port B back to its default output state.
TRISB=(trisb=0);
//Write the data to the port.
PORTB=data;
//Make register select 1
porta|=PORTA_LCD_RS;
//Make R/W 0=write, update physical port.
PORTA=(porta&=~PORTA_LCD_RW);
//Strobe enable
PORTA=(porta|=PORTA_LCD_E);
PORTA=(porta&=~PORTA_LCD_E);
}
//============================================================================
void Write_LCD_Control(ubyte data)
{
ubyte
timeout;
//Poll the LCD's busy line until it is clear.
//Make register select 0
porta&=~PORTA_LCD_RS;
//Make R/W 1=read, update physical port.
PORTA=(porta|=PORTA_LCD_RW);
//Set PORTB to all inputs.
TRISB=(trisb=0xFF);
//Enable the controller's data onto the bus.
PORTA=(porta|=PORTA_LCD_E);
//Test the port's bit, wait for the bit to go low
if(PORTB&PORTB_LCD_DATA_BUSY)
for(timeout=255;(PORTB&PORTB_LCD_DATA_BUSY)&&timeout;timeout--);
if(PORTB&PORTB_LCD_DATA_BUSY)
for(timeout=255;(PORTB&PORTB_LCD_DATA_BUSY)&&timeout;timeout--);
if(PORTB&PORTB_LCD_DATA_BUSY)
for(timeout=255;(PORTB&PORTB_LCD_DATA_BUSY)&&timeout;timeout--);
//Get the bus back from the controller
PORTA=(porta&=~PORTA_LCD_E);
//Turn port B back to its default output state.
TRISB=(trisb=0);
//Write the data to the port.
PORTB=data;
//Make R/W 0=write
PORTA=(porta&=~PORTA_LCD_RW);
//Strobe enable
PORTA=(porta|=PORTA_LCD_E);
PORTA=(porta&=~PORTA_LCD_E);
}
//============================================================================
void Blind_Write_LCD_Control(ubyte data)
{
//Make register select 0, Make R/W 0=write
PORTA=(porta&=~(PORTA_LCD_RS|PORTA_LCD_RW));
//Write the data to the port.
PORTB=data;
//Strobe enable
PORTA=(porta|=PORTA_LCD_E);
PORTA=(porta&=~PORTA_LCD_E);
}
//============================================================================
void LCD_Initialize(void)
{
static const char
default_special_characters[8][8]=
{
{0, 8,12,14,15,14,12, 8}, //right arrow
{0, 1, 3, 7,15, 7, 3, 1}, //left arrow
{0, 4, 4,14,14,31,31, 0}, //up arrow
{0,31,31,14,14, 4, 4, 0}, //down arrow
{0, 0,14,31,31,31,14, 0}, //circle
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
};
ubyte
i;
ubyte
j;
PWM_Initilaize();
//This sequence is from the initialization on page 45 of the HD44780U
//data sheet.
DelayMs(20);
Blind_Write_LCD_Control(0x30);
//Yes, the data sheet says write it twice.
DelayMs(5);
Blind_Write_LCD_Control(0x30);
//Yes, the data sheet says write it three times.
DelayUs(125);
Blind_Write_LCD_Control(0x30);
//Yes, the data sheet says write it four times, but at least this one counts.
//038h is Function set:
//8 bit,
//2 line
//F = (5x8)
DelayUs(125);
Blind_Write_LCD_Control(0x38);
//"Display off"
Write_LCD_Control(0x08);
//"Display clear"
Write_LCD_Control(0x01);
//This delay is needed for the Sitronix ST7066 Display. No reasonable
//explanation, I found it empirically.
DelayMs(2);
//006h is Entry mode set, increment, no shift
Write_LCD_Control(0x06);
//Display on, cursor on, blinking
Write_LCD_Control(0x0F);
//Clear the display again. This seems to fix a power-up problem
//where the display shows "{{{{{" in a couple of places.
Write_LCD_Control(0x01);
//Why is this needed?
DelayMs(2);
//Initialize the first 7 custom characters.
//Address the data area for the custom character 0.
Write_LCD_Control(0x40);
for(j=0;j<=7;j++)
for(i=0;i<=7;i++)
Write_LCD_Data(default_special_characters[j][i]);
}
//============================================================================
void LCD_Position_Cursor(ubyte x, ubyte y)
{
//Valid x is 0-15, valid y is 0-1
if((x<=15)&&(y<=1))
Write_LCD_Control(0x80|(y<<6)|x);
}
//============================================================================
//Could make this aware of display size & wrapping.
void LCD_puts(const char *input_string)
{
while(*input_string)
Write_LCD_Data(*input_string++);
}
//============================================================================
void LCD_Clear(void)
{
//Clears the LCD & positions the cursor at 0,0
Write_LCD_Control(0x01);
}
//============================================================================
//Prints a 3 character string of input at the current location.
void LCD_put_dec(ubyte input)
{
ubyte
digit;
ubyte
no_blank;
digit=input/100;
if(digit)
{
Write_LCD_Data(digit+'0');
no_blank=1;
}
else
{
Write_LCD_Data(' ');
no_blank=0;
}
input%=100;
digit=input/10;
if(digit|no_blank)
Write_LCD_Data(digit+'0');
else
Write_LCD_Data(' ');
Write_LCD_Data(input%10+'0');
}
//============================================================================