TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: juanelete en 16 de Diciembre de 2007, 08:45:09
-
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 :mrgreen:
Saludos a tod@s
-
Estimado Juanelete: Revisa la pagina del Amigo Redpic ahi tiene una libreria "flexible" para los LCDs`
saludos.
Maxluis.
-
Hola maxluis
La conozco, y se que funciona perfectamente.
Pero quiero saber porque no funciona esta con el puerto A y si funciona con cualquier otro puerto.
Gracias por responder. :)
Saludos a tod@s
-
He estado dándole un vistazo y no veo tampoco cuál puede ser el problema. He visto que al reset el 18F876 configura el PORTA como entradas analógicas, pero eso debería estar solucionado con tu setup_adc_ports( NO_ANALOGS ); :shock:
Añádele por si acaso también el SETUP_ADC(ADC_OFF);
-
Hola a tod@s
!!!! SOLUCIONADO !!!!! :-/
He estado revisando el codigo y al final he encontrado el problema, a saber:
!! MI IGNORANCIA !! (90%) y la casualidad (10%) :?
Me explico:
Este driver lo hice hace ya mas de un año, y ha estado funcionado perfectamente, hasta ahora, porque casualmente siempre he utilizado el nibble alto de un puerto para el bus de datos del LCD. Pero en el momento que lo he configurado para utilizar el nibble bajo para el bus, no funciona :( , porque tal y como esta programado siempre saca el dato por el nibble alto del puerto.
Hare la correspondiente modificacion para arregarlo.
Gracias a todos :mrgreen:
Saludos
-
Bien está lo que bien acaba. :mrgreen:
-
Amigo Juanelete,
Podrias pasarme el código a 8 bits para un LCD 4x20?
Yo tengo uno con el controlador PCM2004A y usa el controlador S6A0069. Te lo pido ya que tengo problemas tanto para inicializarlo a 4 lineas y para escribir caracteres. Estoy usando un PIC16F76 con cristal de 8MHz y si lo tuvieras en assembler magnifico ya que no uso el C o en una especie de diagrama a bloques seria suficiente. Ahora que si solo lo tienes en C, pues venga ya me las arreglare para entenderloy pasarlo a assembler.
saludos y gracias de antemano