Hola, yo lo tengo funcionando a 20MHz con este driver.
El driver es marca de la casa, lo adapte para poder utilizar cualquier pin del pic, asi que tambien servira para la gente que buscaba algo asi.
Codigo:
// coach_lcd.c
//
// Funciones para la gestion del display 2x16 [ByCoach]:
//
// lcd_iniciar() Debe ser llamada antes que las otras funciones.
//
// lcd_putc(c) Visualiza c en la siguiente posición del display.
// Caracteres especiales de control:
// f Borrar display
//
Saltar a la segunda linea
// Retroceder una posición.
//
// lcd_gotoxy(x,y) Selecciona la nueva posicion de escritura en el display.
// (la esquina superior izquierda es 1,1)
//
// lcd_getc(x,y) Devuelve el caracter de la posicion x,y del display.
//Definición de pines:
#define lcd_rs PIN_C0 //
#define lcd_rw PIN_C1 //
#define lcd_en PIN_C2 //
#define lcd_DB4 PIN_C4 //
#define lcd_DB5 PIN_C5 //
#define lcd_DB6 PIN_C6 //
#define lcd_DB7 PIN_C7
void lcd_enviar_nibble( int nibble )
{
output_bit( lcd_DB4, bit_test( nibble, 0 ) ); //Pone en el puerto B[4..7] el valor en nibble[0..3]
output_bit( lcd_DB5, bit_test( nibble, 1 ) );
output_bit( lcd_DB6, bit_test( nibble, 2 ) );
output_bit( lcd_DB7, bit_test( nibble, 3 ) );
delay_us( 1 );
output_high( lcd_en ); //Activa y desactiva enable para que el lcd capture el nibble
delay_us( 2 );
output_low( lcd_en );
}
int lcd_leer_byte( void )
{
int valor = 0;
output_high( lcd_rw ); //Se activa rw indicando que se va a realizar una lectura
delay_us( 1 );
output_high( lcd_en ); //Se activa enable para que el lcd saque la parte alta del byte deseado
delay_us( 1 ); //por los pines de datos
if( input( lcd_DB7 ) ) //Se captura la parte alta del byte deseado
bit_set( valor, 7 );
if( input( lcd_DB6 ) )
bit_set( valor, 6 );
if( input( lcd_DB5 ) )
bit_set( valor, 5 );
if( input( lcd_DB4 ) )
bit_set( valor, 4 );
output_low( lcd_en ); //Se desactiva y se vuelve a activar enable para que el lcd saque la parte
delay_us( 1 ); //baja del byte deseado por los pines de datos
output_high( lcd_en );
delay_us( 1 );
if( input( lcd_DB7 ) ) //Se captura la parte baja del byte deseado
bit_set( valor, 3 );
if( input( lcd_DB6 ) )
bit_set( valor, 2 );
if( input( lcd_DB5 ) )
bit_set( valor, 1 );
if( input( lcd_DB4 ) )
bit_set( valor, 0 );
output_low( lcd_en ); //Se desactiva enable, indicando al lcd el fin de la lectura del byte
return( valor ); //Devuelve el byte capturado
}
void lcd_enviar_byte( int dir, int valor ) //Si recibe en dir un 1 se trata de un dato y si es un 0 es un comando
{
output_low( lcd_rs );
while( bit_test( lcd_leer_byte(), 7 ) ); //Lectura del Flag de Busy (ocupado), si 1 se espera, si 0 se continúa
output_bit( lcd_rs, dir ); //Se asigna a rs el valor de dir para indicar si es dato o comando
delay_us( 1 );
output_low( lcd_rw ); //Se pone a cero rw para indicar que se va a realizar una escritura
delay_us( 1 );
output_low( lcd_en ); //Se pone a cero enable para preparar el valor a enviar
lcd_enviar_nibble( valor >> 4 ); //Se envÃa primero la parte alta del byte
lcd_enviar_nibble( valor & 0x0F ); //a continuación se envÃa la parte baja
}
void lcd_posicionar( int x, int y ) //Se reciben las coordenadas x e y a las que se desea desplazarse
{
int dir;
if ( y != 1 ) //La posición "y" determinará la lÃnea elegida, si es 1 -> LÃnea 1, si no -> LÃnea 2
dir = 0x40; //Dirección de la RAM del LCD para la 2ª lÃnea
else
dir = 0x00; //Dirección de la RAM del LCD para la 1ª lÃnea
dir += x - 1; //Resta uno, ya que la posición 1 serÃa la 0 para el lcd
lcd_enviar_byte( 0, dir | 0x80 ); //Se envÃa el byte, indicando que es un comando y poniendo el bit
} //más significativo a 1, para diferenciar este comando de los demás
void lcd_iniciar( void )
{
int i;
int bytes_inicio[4] = { 0x28, 0x0C, 0x01, 0x06 };
output_low( lcd_rs ); //Pone a cero todos los pines de control
output_low( lcd_rw );
output_low( lcd_en );
delay_ms( 30 );
for ( i = 1 ; i <= 3 ; i++ )
{
lcd_enviar_nibble( 3 );
delay_ms( 5 );
}
lcd_enviar_nibble( 2 );
for( i = 0 ; i <= 3 ; i++ ) //Se configura el lcd con las caracterÃsticas indicadas anteriormente
lcd_enviar_byte( 0 , bytes_inicio );
}
void lcd_putc( char c ) //Se recibe el caracter a enviar
{
switch( c )
{
case "f" : lcd_enviar_byte( 0, 1 ); //Si c = "f", se envÃa un 1, e indica que es un comando
delay_ms( 2 ); //Enviando un 1, se borra la pantalla del lcd
break;
case "
" : lcd_posicionar( 1, 2 ); //Si c = "
", se posiciona en la segunda lÃnea
break;
case "" : lcd_enviar_byte( 0, 0x10 ); //Si c = "", se sitúa una posición a la izquierda
break;
default : lcd_enviar_byte( 1, c ); //Si no es ninguna de las anteriores, envÃa un caracter
break;
}
}
char lcd_getc( int x,int y ) //Se reciben las coordenadas x e y de las que se desea el dato
{
char valor;
lcd_posicionar( x, y ); //Se posiciona en el punto deseado
output_high( lcd_rs ); //Pone a 1 el pin rs, indicando que se trata de un dato
valor = lcd_leer_byte(); //Lee el byte de la posición deseada
output_low( lcd_rs );
return( valor ); //Devuelve el caracter leÃdo
}