Hola a tod@s
Quiero usar las lineas RA0-RA3 de un 16f876 para conectar el bus de datos de un LCD, y no hay forma de que funcione.
Conozco perfectamente el funcionamiento del driver de inicializacion del LCD, de hecho tengo varios drivers modificados y adaptados a mis necesidades, funcionando perfectamente tanto con 4, como con 8 bits. El driver que quiero utilizar funciona perfectamente siempre y cuando no intente utilizar el puerto A como bus de datos.
Hay algun problema para utilizar RA0-RA3 como bus de datos?, hay que tener algo en cuenta?, aparte de declarar los pines como digitales y ponerlos como salidas.
Aqui teneis el driver para 4 bit
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Libreria LCD_4B20x4.lib.C
//
// Bus 4 bits datos, lineas 4x20, Datos en PORT_A (RA0-RA3) y Control en PORT_C (RC0,RC1),
// sin utilizar R/W (Bussy Flag) y con retardos, en total 6 lineas
//
// Funciones:
//
// lcd_init() Must be called before any other function.
//
// lcd_putc(c) Will display c on the next position of the LCD.
// The following have special meaning:
// \f Clear display
// \n Go to start of second line
// \b Move back one position
//
// lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
//
// (NO) lcd_getc(x,y) Returns character at position x,y on LCD
//
// PINES PIC PINES LCD
// 1 Masa
// 2 VDD 5V
// 3 Contraste
// 2-5 RA0-RA3 11-14 D4-D7
// 11 RC0 4 RS
// 5 R/W Masa=0
// 12 RC1 6 E
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Configurar puertos segun el PIC utilizado
#define PORT_A 0x05
#define PORT_B 0x06
#define PORT_C 0x07
#define PORT_D 0x08
#define PORT_E 0x09
#define LCD_TRIS_WRITE 0b00000000
#define LCD_TRIS_READ 0b11111111
#define LCD_RS_COMANDO 0 //RS
#define LCD_RS_CARACTER 1 //RS
struct lcd_bus_dat // Declaro la structura que va a contener los bits de datos del LCD
{
int nibble_bajo : 4; // Nible bajo (Solo se usa en bus datos 8 bits, junto con el nible alto)
int nibble_alto : 4; // Nible alto, Bus de datos del LCD de 4 bits
} lcd;
#byte lcd = PORT_A // Aqui hay que elegir el puerto para el bus de datos (PORT_B, PORT_C,...)
// Ahora vamos a elegir donde conectaremos los pines de control del LCD.
#bit lcd_rs = PORT_C.0 //11
#bit lcd_enable = PORT_C.1 //12
#define set_tris_lcd(x) set_tris_A(x)
#define FUN_SET 32 // Funcion SET. Solo se puede utilizar en la inicializacion
#define LCD_FUENTE 0 // 0=5x7, 4=5x10
#define LCD_LINEAS 8 // 0=1 Linea, 2=2 Lineas, 8=2 Lineas ó mas.
#define LCD_BUS 0 // 0=4 Bits (D4-D7), 16=8 Bits (D0-D7)
#define DISPLAY_CTRL 8 // Funcion Display control
#define LCD_BLINK 0 // Parpadeo cursor 'ƒ'. 0=Off, 1=On
#define LCD_CURSOR 0 // Visualizacion cursor '_'. 0=Off, 2=On
#define LCD_DISPLAY 4 // Display encendido o apagado. 0=Off, 4=On ** ojo, mientras este Off no veras nada **
#define CLEAR_DISPLAY 1 // Funcion Borrar pantalla
#define ENTRY_MODE 4 // Funcion Modo entrada
#define DESPLAZ_TXT 0 // 0=Off, 1=On Desplazamiento del texto al escribir un nuevo caracter
#define INC_DEC_CURSOR 2 // 0=Decremento, 2=Incremento Incr/Decr autoamtico de la pos. del cursor
#define RETURN_HOME 2 // Funcion Poner el cursor en 0,0
#define CURSOR_DISPLAY 16 // Funcion para controlar los desplazamientos del cursor y la pantalla
#define LCD_RL 0 // 0=Izquierda, 4=Derecha
#define LCD_SC 0 // 0=Solo cursor, 8=Cursor y DDRAM
#define LCD_GOTO_XY 128 // Funcion para situar el cursor en la pos. deseada
int8 lcd_linea=1; //Numero de linea donde estamos (necesario para el comando \n)
// Envia el nibble al LCD
void lcd_send_nibble(int8 dato) // Formato n -> 0000 DDDD DDDD = nibble a enviar
{
lcd.nibble_alto = dato; //Como cargo un byte en una variable de 4 bits se pierde la parte alta del byte
delay_cycles(1);
lcd_enable = 1;
delay_us(2);
lcd_enable = 0;
}
// Esta funcion descompone el dato en dos nibbles y los mete en sendos bytes para enviarlos a LCD
void lcd_send_byte( int8 modo, int8 dato ) // RS=0 ó 1 RW=0 ESCRIBIR
{
lcd_rs = modo; // 0 = Modo comando, 1 = Modo caracter
delay_cycles(1);
lcd_enable = 0;
lcd_send_nibble(dato >> 4); // Elimino la parte baja y envio la parte alta con este formato: 0000 AAAA
lcd_send_nibble(dato & 0xf); // Pongo a cero la parte alta y solo envio la parte baja 0000 BBBB
if(modo==LCD_RS_CARACTER)
delay_us(40); //Retardo necesario modo caracter (No se comprueba Bussy Flag)
else
delay_ms(2); //Retardo necesario modo comando
}
// Antes de nada hay que inicializar el LCD segun una secuencia determinada por el fabricante
void lcd_init() // 4 Bit
{
int8 i;
set_tris_lcd(LCD_TRIS_WRITE); //Pines puerto datos como salida
set_tris_c(0b00000000); //Pines puerto control como salida
lcd_enable = 0;
lcd_rs = LCD_RS_COMANDO; //Modo comando
delay_ms(15);
for(i=0;i<3;i++) //3 veces
{
lcd_send_nibble(0b0011); //0011 Segun Datasheet
delay_ms(5);
}
lcd_send_nibble(0b0010); //0010 Segun Datasheet
lcd_send_byte(LCD_RS_COMANDO,FUN_SET | (LCD_FUENTE + LCD_LINEAS + LCD_BUS));
lcd_send_byte(LCD_RS_COMANDO,DISPLAY_CTRL | (LCD_DISPLAY + LCD_CURSOR + LCD_BLINK));
lcd_send_byte(LCD_RS_COMANDO,CLEAR_DISPLAY);
lcd_send_byte(LCD_RS_COMANDO,ENTRY_MODE | (DESPLAZ_TXT + INC_DEC_CURSOR));
lcd_send_byte(LCD_RS_COMANDO,RETURN_HOME);
}
void lcd_gotoxy( byte x, byte y)
{
int8 pos;
switch(y)
{
case 1 : pos=0x80; break;
case 2 : pos=0xc0; break;
case 3 : pos=0x94; break;
case 4 : pos=0xd4; break;
}
lcd_send_byte(LCD_RS_COMANDO,LCD_GOTO_XY | pos+x-1); //Las direcciones de la DDRAM empiezan por 1xxxxxxx
// 1DDDDDDD Comando Desplazamiento cursor
// 0x80 = 10000000 Osea que para poner el valor del desplazamiento en el comando, hay que hacer OR con 0x80
// Ejemplo: Col=8 y Lin=2 => address=0x40 + 0x08 - 0x01 = 0x47 = 01000111 Este seria el desplazamiento
// Ahora hay que poner (hacer OR) en el byte comando el valor del desplazamiento: 10000000 OR 01000111 = 11000111
}
void lcd_putc( char c)
{
switch (c)
{
case '\f': lcd_send_byte(LCD_RS_COMANDO,CLEAR_DISPLAY);
lcd_linea=1; //El cursor esta en la primera linea
break;
case '\n': lcd_gotoxy(1,++lcd_linea); // Desplaza cursor siguiente linea
break;
// 00010000 Comando desplazar cursor, sin alterar ddram, Izquierda
case '\b': lcd_send_byte(LCD_RS_COMANDO,CURSOR_DISPLAY | (LCD_RL + LCD_SC));
break;
default : lcd_send_byte(LCD_RS_CARACTER,c); // Envio byte en modo caracter
break;
}
}
Y el programa de prueba
////////////////////////////////////////////////////////////////////////////////
// pruLCD4B20x4v4.c
//
// PIC: 16F876
// Programa de prueba para probar la libreria LCD_4B20x4v4.lib.c
//
////////////////////////////////////////////////////////////////////////////////
#INCLUDE <16F876.H>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#include <LCD_4B20x4v4.lib.C>
void main()
{
char c;
setup_adc_ports( NO_ANALOGS ); //Todos los puertos digitales
set_tris_A(0b00000000); //Puerto A como salidas
delay_ms(100);
lcd_init();
lcd_putc("\fPreparado...\n");
while(1);
}
Decime si se os ocurre algo.
Gracias anticipadas
Saludos a tod@s