/*
lcd_shift.c
print and setting functions for a HD44780 compatible display
Copyright (C) 2011 Marc Heimann <mheimann84@googlemail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <util/delay.h>
#include "lcd_shift.h"
void lcd_enable( void )
{
PORT_OUT_ENABLE |= PIN_ENABLE;
_delay_us( 2 );
PORT_OUT_ENABLE &= ~PIN_ENABLE;
}
// shifts one byte to shift register 74HC164
// no delays are used because the 74HC164 is
// fast enough (74HC164 SIPO.pdf, p. 5)
void shift_byte( uint8_t data_byte )
{
uint8_t i;
for (i = 0; i < 8; i++)
{
if (data_byte & (1<<(7-i))) // from left to right
PORT_OUT_DATA |= PIN_DATA;
else
PORT_OUT_DATA &= ~PIN_DATA;
PORT_OUT_CLOCK |= PIN_CLOCK;
PORT_OUT_CLOCK &= ~PIN_CLOCK;
}
}
// chooses instruction delay (HD44780.pdf, p. 24, 25)
void send_instr( uint8_t data )
{
if (data & RETURN_HOME)
send_instruction( data, 1520 );
else
send_instruction( data, 37 );
}
// sends an instruction via the shift register to the display (RS=0)
void send_instruction( uint8_t data, uint16_t usec_delay )
{
uint8_t data_byte;
// upper 4 bit
data_byte = 0;
if (data & PIN_DB4) data_byte |= SHIFT_OUT_DB0_DB4;
if (data & PIN_DB5) data_byte |= SHIFT_OUT_DB1_DB5;
if (data & PIN_DB6) data_byte |= SHIFT_OUT_DB2_DB6;
if (data & PIN_DB7) data_byte |= SHIFT_OUT_DB3_DB7;
shift_byte( data_byte );
lcd_enable();
_delay_us( usec_delay );
// lower 4 bit
data_byte = 0;
if (data & PIN_DB0) data_byte |= SHIFT_OUT_DB0_DB4;
if (data & PIN_DB1) data_byte |= SHIFT_OUT_DB1_DB5;
if (data & PIN_DB2) data_byte |= SHIFT_OUT_DB2_DB6;
if (data & PIN_DB3) data_byte |= SHIFT_OUT_DB3_DB7;
shift_byte( data_byte );
lcd_enable();
_delay_us( usec_delay );
}
// sends data via the shift register to the display (RS=1)
void send_data( uint8_t data )
{
uint8_t data_byte;
// upper 4 bit
data_byte = SHIFT_OUT_RS;
if (data & PIN_DB4) data_byte |= SHIFT_OUT_DB0_DB4;
if (data & PIN_DB5) data_byte |= SHIFT_OUT_DB1_DB5;
if (data & PIN_DB6) data_byte |= SHIFT_OUT_DB2_DB6;
if (data & PIN_DB7) data_byte |= SHIFT_OUT_DB3_DB7;
shift_byte( data_byte );
lcd_enable();
_delay_us( 50 ); // considering t_ADD (HD44780.pdf, p. 25, figure 10)
// lower 4 bit
data_byte = SHIFT_OUT_RS;
if (data & PIN_DB0) data_byte |= SHIFT_OUT_DB0_DB4;
if (data & PIN_DB1) data_byte |= SHIFT_OUT_DB1_DB5;
if (data & PIN_DB2) data_byte |= SHIFT_OUT_DB2_DB6;
if (data & PIN_DB3) data_byte |= SHIFT_OUT_DB3_DB7;
shift_byte( data_byte );
lcd_enable();
_delay_us( 50 );
}
void init_lcd( void )
{
// processor settings //
// set port output
PORT_DIR_CLOCK |= PIN_CLOCK;
PORT_DIR_DATA |= PIN_DATA;
PORT_DIR_ENABLE |= PIN_ENABLE;
// set output zero
PORT_OUT_CLOCK &= ~PIN_CLOCK;
PORT_OUT_DATA &= ~PIN_DATA;
PORT_OUT_ENABLE &= ~PIN_ENABLE;
// display settings //
// The instructions were taken from HD44780.pdf, p. 42
// step 1, power on
_delay_us( 16000 );
// step 2, set 4 bit operation
shift_byte( SHIFT_OUT_DB1_DB5 );
lcd_enable();
_delay_us( 37 );
// step 3, two instead of one line
send_instruction( SET_4BIT_TWO_LINES, 37 );
// step 4, without cursor
send_instruction( SET_DISPLAY_ON, 37 );
}
// prints content of 'buffer' to DDRAM address 'addr'
void print_lcd( char* buffer, uint8_t addr )
{
uint8_t pos, i;
send_instruction( SET_DDRAM_ADDRESS | addr, 37 );
if (addr >= LINE_2_ADDR) // second line
{
pos = addr - LINE_2_ADDR;
}
else // first line
{
pos = addr;
}
for (i = 0; (buffer[i] != 0) && (pos < CHARACTERS_PER_LINE); i++)
{
send_data( buffer[i] );
pos++;
}
}