Autor Tema: Problemas con LCD 4x20 y PIC18F4520  (Leído 8091 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Problemas con LCD 4x20 y PIC18F4520
« en: 27 de Agosto de 2012, 17:00:05 »
Saludos.

Quiero hacer un teclado ADC, para empesar me guie en el artículo que se muestra en la página de redpic (segun recuerdo), lo que hace su programa es entregar al puerto serial caracteres que indican el valor de cada tecla segun la lectura del ADC. El problema esta en que yo quiero que me entregue valores numericos, no caracteres, hice un código y nisiquiera me funciona el LCD, ya revise el código, pero no logro hacer que funcione, necesito hacer el teclado para introducir valores y luego sirvan como base para operaciones matemáticas de control.

En el primer código no hice estas declaraciones:
Código: [Seleccionar]
#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_RS PIN_B2
#define LCD_E PIN_B3
ya que en la libreria indica las conexiones que se tiene que hacer en el puerto D y parte del E, asi no funciono para nada, luego le puse esas declaraciones y lo conecte al puerto B, pero igual, nada de nada.
Aquí el código en CCS.
Código: [Seleccionar]
#include <18F4520.h>
#device adc=10
#use delay(clock=4000000)
#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT

#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_RS PIN_B2
#define LCD_E PIN_B3

#include <flex_lcd204.c>

void main()
{
   int Tecla,TeclaAntigua;
   int Teclap;
   lcd_init();
   setup_adc_ports(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   Tecla = 0;
   TeclaAntigua = 0;
   while (true)
   {
      set_adc_channel(0);
      delay_us (20);
      Tecla = read_adc();
      if ((Tecla) && (Tecla!=TeclaAntigua))
      {
         if (Tecla<440)
            Teclap = 13;
         if (Tecla<462)
            Teclap = 12;
         if (Teclap<488)
            Teclap = 11;
         if (Tecla<496)
            Teclap = 10;
         if (Tecla<523)
            Teclap = 15;
         if (Tecla<554)
            Teclap = 9;
         if (Tecla<592)
            Teclap = 6;
         if (Tecla<603)
            Teclap = 3;
         if (Tecla<617)
            Teclap = 0;
         if (Tecla<661)
            Teclap = 8;
         if (Tecla<716)
            Teclap = 5;
         if (Tecla<733)
            Teclap = 2;
         if (Tecla<770)
            Teclap = 14;
         if (Tecla<839)
            Teclap = 7;
         if (Tecla<931)
            Teclap = 4;
         if (Tecla<959)
            Teclap = 1;
         printf(lcd_putc,"\f   TECLA  PULSADA \n     %2u",Teclap);
      }
      TeclaAntigua = Tecla;
   }
   
}

aquí la libreria del LCD: flex_lcd204.c
Código: [Seleccionar]

// Flex_LCD420.c

// These pins are for my Microchip PicDem2-Plus board,
// which I used to test this driver.
// An external 20x4 LCD is connected to these pins.
// Change these pins to match your own board's connections.

#ifndef LCD_DB4
#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_D5
#define LCD_DB6   PIN_D6
#define LCD_DB7   PIN_D7

#define LCD_RS    PIN_E0
#define LCD_RW    PIN_E1
#define LCD_E     PIN_E2
#endif

/*
// To prove that the driver can be used with random
// pins, I also tested it with these pins:
#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_B1
#define LCD_DB6   PIN_C5
#define LCD_DB7   PIN_B5

#define LCD_RS    PIN_E2
#define LCD_RW    PIN_B2
#define LCD_E     PIN_D6
*/

// If you want only a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.  Doing so will save one PIC
// pin, but at the cost of losing the ability to read from
// the LCD.  It also makes the write time a little longer
// because a static delay must be used, instead of polling
// the LCD's busy bit.  Normally a 6-pin interface is only
// used if you are running out of PIC pins, and you need
// to use as few as possible for the LCD.
//#define USE_RW_PIN   1     


// These are the line addresses for most 4x20 LCDs.
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x40
#define LCD_LINE_3_ADDRESS 0x14
#define LCD_LINE_4_ADDRESS 0x54

// These are the line addresses for LCD's which use
// the Hitachi HD66712U controller chip.
/*
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x20
#define LCD_LINE_3_ADDRESS 0x40
#define LCD_LINE_4_ADDRESS 0x60
*/


//========================================

#define lcd_type 2   // 0=5x7, 1=5x10, 2=2 lines(or more)

int8 lcd_line;

int8 const LCD_INIT_STRING[4] =
{
 0x20 | (lcd_type << 2),  // Set mode: 4-bit, 2+ lines, 5x8 dots
 0xc,                     // Display on
 1,                       // Clear display
 6                        // Increment cursor
 };
                             

//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note:  !! converts an integer expression
// to a boolean (1 or 0).
 output_bit(LCD_DB4, !!(nibble & 1));
 output_bit(LCD_DB5, !!(nibble & 2));
 output_bit(LCD_DB6, !!(nibble & 4));   
 output_bit(LCD_DB7, !!(nibble & 8));   

 delay_cycles(1);
 output_high(LCD_E);
 delay_us(2);
 output_low(LCD_E);
}

//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine.  For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.     

#ifdef USE_RW_PIN
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;
   
output_high(LCD_E);
delay_us(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
 
output_low(LCD_E);
delay_us(1);
   
return(retval);   
}   
#endif

//---------------------------------------
// Read a byte from the LCD and return it.

#ifdef USE_RW_PIN
int8 lcd_read_byte(void)
{
int8 low;
int8 high;

output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif

//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);

#ifdef USE_RW_PIN
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif

if(address)
   output_high(LCD_RS);
else
   output_low(LCD_RS);
     
 delay_cycles(1);

#ifdef USE_RW_PIN
output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
//----------------------------

void lcd_init(void)
{
int8 i;

lcd_line = 1;

output_low(LCD_RS);

#ifdef USE_RW_PIN
output_low(LCD_RW);
#endif

output_low(LCD_E);

// Some LCDs require 15 ms minimum delay after
// power-up.  Others require 30 ms.  I'm going
// to set it to 35 ms, so it should work with
// all of them.
delay_ms(35);         

for(i=0 ;i < 3; i++)
   {
    lcd_send_nibble(0x03);
    delay_ms(5);
   }

lcd_send_nibble(0x02);

for(i=0; i < sizeof(LCD_INIT_STRING); i++)
   {
    lcd_send_byte(0, LCD_INIT_STRING[i]);
   
    // If the R/W signal is not used, then
    // the busy bit can't be polled.  One of
    // the init commands takes longer than
    // the hard-coded delay of 50 us, so in
    // that case, lets just do a 5 ms delay
    // after all four of them.
    #ifndef USE_RW_PIN
    delay_ms(5);
    #endif
   }

}

//----------------------------

void lcd_gotoxy(int8 x, int8 y)
{
int8 address;


switch(y)
  {
   case 1:
     address = LCD_LINE_1_ADDRESS;
     break;

   case 2:
     address = LCD_LINE_2_ADDRESS;
     break;

   case 3:
     address = LCD_LINE_3_ADDRESS;
     break;

   case 4:
     address = LCD_LINE_4_ADDRESS;
     break;

   default:
     address = LCD_LINE_1_ADDRESS;
     break;
     
  }

address += x-1;
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
 switch(c)
   {
    case '\f':
      lcd_send_byte(0,1);
      lcd_line = 1;
      delay_ms(2);
      break;
   
    case '\n':
       lcd_gotoxy(1, ++lcd_line);
       break;
   
    case '\b':
       lcd_send_byte(0,0x10);
       break;
   
    default:
       lcd_send_byte(1,c);
       break;
   }
}

//------------------------------
#ifdef USE_RW_PIN
char lcd_getc(int8 x, int8 y)
{
char value;

lcd_gotoxy(x,y);

// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));

output_high(LCD_RS);
value = lcd_read_byte();
output_low(LCD_RS);

return(value);
}
#endif

Aparte, al hacer la compilacion del código el CCS me dice que hay muchos warnings, con eso de los valores que se utiliza para comparar, me dice que todas las condiciones se cumplen, ya que un número siempre terminara siendo menor que los demas si éste es menor que el primero.

Envío el esquemático hecho en proteus 7.7
Desde yá, muchas gracias por la ayuda.

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #1 en: 27 de Agosto de 2012, 20:08:15 »
  Para solucionar el tema de los "if" debes anidar los mismos. O hacer una comparación con un límite inferior y uno superior.

  Cuando configuras los puertos del ADC los colocas todos como analógicos eso implica que algunos pines del puerto B también serán entradas analógicas. Tal vez entre en conflicto con el hecho de que quieres utilizar el puerto B para el LCD.

  Prueba de configurar sólo como analógico el pin que usas para el ADC.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #2 en: 27 de Agosto de 2012, 23:08:24 »
Saludos.

Muchas gracias por tu tiempo AngelGris.

Sobre tu consejo del anidado de "if's" lo voy a hacer y haber que pasa.

En cuanto a la configuracion de puertos ADC, intente poner la siguiente configuracion: AN0_AN1_AN3, pero ésta me da error con la libreria del LCD, no se por qué pasa eso, tambien intente con AN0,
Código: [Seleccionar]
setup_adc_ports (AN0_AN1_AN3);
y tambien con
setup_adc_ports (AN0);
Todas esas configuraciones las saque del libro: Compilador CCS y proteus para PIC's, ninguna de las dos parece ser aceptada, o no se, y lo más raro es que da error con la libreria del LCD al poner esas configuraciones del ADC.

Muchas gracias.


Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #3 en: 30 de Agosto de 2012, 20:37:45 »
Hola.

En verdad, no puedo hacer funcionar el LCD 4x20 en un pic18f4520 ni 4550, ahora que ando intentando con el 4550, le puse otra libreria, pero se salta las líneas 2 y 4, simplemente no las escribe, solamente escribe en las líneas 1 y 3, la libreria que utilizo es la siguiente: la saque del foro, pero no recuerdo de que parte:

LIBRERIA LCD
Código: [Seleccionar]
////////////////////////////////////////////////////////////////////////////
////                             LCD4por20.C                               ////
////            Driver for common 4x20 LCD modules                      ////
////                                                                    ////
////  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)     ////
////                                                                    ////
////  lcd_getc(x,y)   Returns character at position x,y on LCD          ////
////                                                                    ////
////////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,1997 Custom Computer Services            ////
//// This source code may only be used by licensed users of the CCS C   ////
//// compiler.  This source code may only be distributed to other       ////
//// licensed users of the CCS C compiler.  No other use, reproduction  ////
//// or distribution is permitted without written permission.           ////
//// Derivative programs created using this software in object code     ////
//// form are not restricted in any way.                                ////
////////////////////////////////////////////////////////////////////////////

// As defined in the following structure the pin connection is as follows:
//     B0  enable
//     B1  rs
//     B2  rw
//     B4  D4
//     B5  D5
//     B6  D6
//     B7  D7
//
//   LCD pins D0-D3 are not used and PIC B3 is not used.
#define use_portb_lcd TRUE


struct lcd_pin_map {                 // This structure is overlayed
           BOOLEAN enable;           // on to an I/O port to gain
           BOOLEAN rs;               // access to the LCD pins.
           BOOLEAN rw;               // The bits are allocated from
           BOOLEAN unused;           // low order up.  ENABLE will
           int     data : 4;         // be pin B0.
        } lcd;


#if defined use_portb_lcd
   //#locate lcd = getenv("sfr:PORTB")    // This puts the entire structure over the port
   #ifdef __pch__
    #locate lcd = 0xf81
   #else
    #locate lcd = 6
   #endif
   #define set_tris_lcd(x) set_tris_b(x)
#else
   //#locate lcd = getenv("sfr:PORTD")    // This puts the entire structure over the port
   #ifdef __pch__
    #locate lcd = 0xf83
   #else
    #locate lcd = 8
   #endif
   #define set_tris_lcd(x) set_tris_d(x)
#endif

#ifndef lcd_type
#define lcd_type 2           // 0=5x7, 1=5x10, 2=2 lines
#endif

#define lcd_line_two 0x40    // LCD RAM address for the second line

/*struct lcd_pin_map {                 // This structure is overlayed
           BOOLEAN enable;           // on to an I/O port to gain
           BOOLEAN rs;               // access to the LCD pins.
           BOOLEAN rw;               // The bits are allocated from
           BOOLEAN unused;           // low order up.  ENABLE will
           int     data : 4;         // be pin B0.
        } lcd;

#byte lcd = 6                        // This puts the entire structure
                                     // on to port B (at address 6)

#define lcd_type 2           // 0=5x7, 1=5x10, 2=2 lines*/


BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
                             // These bytes need to be sent to the LCD
                             // to start it up.


                             // The following are used for setting
                             // the I/O port direction register.

struct lcd_pin_map const LCD_WRITE = {0,0,0,0,0}; // For write mode all pins are out
struct lcd_pin_map const LCD_READ = {0,0,0,0,15}; // For read mode data pins are in


BYTE lcdline;

BYTE lcd_read_byte() {
      BYTE low,high;

      set_tris_b(LCD_READ);
      lcd.rw = 1;
      delay_cycles(1);
      lcd.enable = 1;
      delay_cycles(1);
      high = lcd.data;
      lcd.enable = 0;
      delay_cycles(1);
      lcd.enable = 1;
      delay_us(1);
      low = lcd.data;
      lcd.enable = 0;
      set_tris_b(LCD_WRITE);
      return( (high<<4) | low);
}


void lcd_send_nibble( BYTE n ) {
      lcd.data = n;
      delay_cycles(1);
      lcd.enable = 1;
      delay_us(2);
      lcd.enable = 0;
}


void lcd_send_byte( BYTE address, BYTE n ) {

      lcd.rs = 0;
      while ( bit_test(lcd_read_byte(),7) ) ;
      lcd.rs = address;
      delay_cycles(1);
      lcd.rw = 0;
      delay_cycles(1);
      lcd.enable = 0;
      lcd_send_nibble(n >> 4);
      lcd_send_nibble(n & 0xf);
}


void lcd_init() {
    BYTE i;

    set_tris_b(LCD_WRITE);
    lcd.rs = 0;
    lcd.rw = 0;
    lcd.enable = 0;
    delay_ms(15);
    for(i=1;i<=3;++i) {
       lcd_send_nibble(3);
       delay_ms(5);
    }
    lcd_send_nibble(2);
    for(i=0;i<=3;++i)
       lcd_send_byte(0, LCD_INIT_STRING[i]);
}


void lcd_gotoxy( BYTE x, BYTE y) {
   BYTE address;

   switch(y) {
     case 1 : address=0x80;break; //0x80
     case 2 : address=0xc0;break; //0xc0
     case 3 : address=0x94;break; //0x94
     case 4 : address=0xd4;break; //0xd4
   }
   address+=x-1;
   lcd_send_byte(0,address);
}

void lcd_putc( char c) {
   switch (c) {
     case '\f'   : lcd_send_byte(0,1);
                   lcdline=1;
                   delay_ms(2);
                                           break;
     case '\n'   : lcd_gotoxy(1,++lcdline);        break;
     case '\b'   : lcd_send_byte(0,0x10);  break;
     default     : lcd_send_byte(1,c);     break;
   }
}

char lcd_getc( BYTE x, BYTE y) {
   char value;

    lcd_gotoxy(x,y);
    lcd.rs=1;
    value = lcd_read_byte();
    lcd.rs=0;
    return(value);
}

tambien lei por ahí, que se tiene que cambiar la linea :
Código: [Seleccionar]
#byte lcd = 6
CAMBIARLA POR:
#byte lcd = 3969

creo que ello tiene que ver algo con direcciones de puerto segun lei, o algo asi, eso para que hagarre con los pic18f

por si, aqui tambien pongo el código de ejemplo que utilizo:
Código: [Seleccionar]
#include <18f4550.h>
#fuses hs,nowdt,noprotect,nolvp
#use delay (clock = 20000000)
#use standard_io(B)
#define use_portB_lcd TRUE
//#include <LCD4por20.c>
#include <flex_lcd204.c>

void main ()
{
   lcd_init();
   while(true)
   {
      //printf(lcd_putc,"\f  \n  linea\n    linea\n    linea");
     
      lcd_putc("\f");
      delay_ms(100);
      lcd_gotoxy(1,1);
      lcd_putc("hola");
      delay_ms(100);
      lcd_gotoxy(1,2);
      lcd_putc("2da linea");
      delay_ms(100);
      lcd_gotoxy(1,3);
      lcd_putc("3ra linea");
      delay_ms(100);
      lcd_gotoxy(1,4);
      lcd_putc("4ta linea");
      delay_ms(300);
      /*
      delay_ms(100);
      printf(lcd_putc,"\f  linea 1");
      delay_ms(100);
      printf(lcd_putc,"\n  linea 2");
      delay_ms(100);
      printf(lcd_putc,"\n  linea 3");
      delay_ms(100);
      printf(lcd_putc,"\n  linea 4");
      delay_ms(3000);*/
   }
}

como podran ver en el código, intente de varias ,maneras, eso de querer escribir en las lineas 2 y 4.

Muchas gracias.

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #4 en: 30 de Agosto de 2012, 20:41:39 »
que descuido, porsiacaso, esa libreria :

#include <LCD4por20.c>

es la que escribe en las 2 líneas mensionadas. La libreria:

flex_lcd204.c

no escribe nada de nada, esa solo funciona con el pic 16f877a

Hice la prueva con las 2 librerias, y el código que esta de ejemplo, pues olvide sacarle el comentario de la libreria, na mas ponen el comentario a la libreria flex y a la otra lo avilitan.

gracias y mil perdones

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #5 en: 30 de Agosto de 2012, 22:35:08 »
encontre esta página que trata sobre las direcciones de memoria (supongo) del chip HD44780, que supuestamente es el que posee el lcd RT204-1 de 4x20

http://web.alfredstate.edu/weimandn/lcd/lcd_addressing/lcd_addressing_index.html

pues, cambie esas direcciones en la libreria, pero aun nada de nada.

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #6 en: 31 de Agosto de 2012, 16:54:01 »
Hola.

ya no se qué más hacer, encontre esta libreria que posteo pink_brenda, es donde hay que cambiar la dirección del puerto B, para que sea a la del 4550, esa libreria esta en este link:

http://www.todopic.com.ar/foros/index.php?topic=26259.0

modifique las direcciones de las filas segun los casos vistos en estas páginas:

http://web.alfredstate.edu/weimandn/lcd/lcd_addressing/lcd_addressing_index.html

http://www.circuitvalley.com/2012/02/lcd-custom-character-hd44780-16x2.html

en ambas páginas muestran diferentes direcciones de columna.

No se me ocurre nada más,  :( :(, ya no se que hacer para que funsione.

Muchas gracias.

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #7 en: 02 de Septiembre de 2012, 11:11:03 »
Ya pude solucionar el problema, escribe en las 4 líneas como debe ser.

aqui pongo el programa de ejemplo y la libreria correspondiente, para quien tambien tenga este problema.

Código: [Seleccionar]
#include <18f4550.h>
#fuses hs,nowdt,noprotect,nolvp
#use delay (clock = 20000000)
#use standard_io(B)
#include <lcd20Cx4F.c>

void main ()
{
   lcd_init();
   while(true)
   {
      delay_ms(100);
      printf(lcd_putc,"\f  HOLA \n  AHORA\n    JALA\n    ESTA WEA");

   }
}

La libreria
Código: [Seleccionar]
// Flex_LCD420.c

// These pins are for my Microchip PicDem2-Plus board,
// which I used to test this driver.
// An external 20x4 LCD is connected to these pins.
// Change these pins to match your own board's connections.

#define LCD_DB4   PIN_B4
#define LCD_DB5   PIN_B5
#define LCD_DB6   PIN_B6
#define LCD_DB7   PIN_B7

#define LCD_RS    PIN_B0
#define LCD_RW    PIN_B1
#define LCD_E     PIN_B2

/*
// To prove that the driver can be used with random
// pins, I also tested it with these pins:
#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_B1
#define LCD_DB6   PIN_C5
#define LCD_DB7   PIN_B5

#define LCD_RS    PIN_E2
#define LCD_RW    PIN_B2
#define LCD_E     PIN_D6
*/

// If you want only a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.  Doing so will save one PIC
// pin, but at the cost of losing the ability to read from
// the LCD.  It also makes the write time a little longer
// because a static delay must be used, instead of polling
// the LCD's busy bit.  Normally a 6-pin interface is only
// used if you are running out of PIC pins, and you need
// to use as few as possible for the LCD.
#define USE_RW_PIN   1     


// These are the line addresses for most 4x20 LCDs.
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x40
#define LCD_LINE_3_ADDRESS 0x14
#define LCD_LINE_4_ADDRESS 0x54

// These are the line addresses for LCD's which use
// the Hitachi HD66712U controller chip.
/*
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x20
#define LCD_LINE_3_ADDRESS 0x40
#define LCD_LINE_4_ADDRESS 0x60
*/


//========================================

#define lcd_type 2   // 0=5x7, 1=5x10, 2=2 lines(or more)

int8 lcd_line;

int8 const LCD_INIT_STRING[4] =
{
 0x20 | (lcd_type << 2),  // Set mode: 4-bit, 2+ lines, 5x8 dots
 0xc,                     // Display on
 1,                       // Clear display
 6                        // Increment cursor
 };
                             

//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note:  !! converts an integer expression
// to a boolean (1 or 0).
 output_bit(LCD_DB4, !!(nibble & 1));
 output_bit(LCD_DB5, !!(nibble & 2)); 
 output_bit(LCD_DB6, !!(nibble & 4));   
 output_bit(LCD_DB7, !!(nibble & 8));   

 delay_cycles(1);
 output_high(LCD_E);
 delay_us(2);
 output_low(LCD_E);
}

//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine.  For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.     

#ifdef USE_RW_PIN
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;
   
output_high(LCD_E);
delay_us(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
 
output_low(LCD_E);
delay_us(1);
   
return(retval);   
}   
#endif

//---------------------------------------
// Read a byte from the LCD and return it.

#ifdef USE_RW_PIN
int8 lcd_read_byte(void)
{
int8 low;
int8 high;

output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif

//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);

#ifdef USE_RW_PIN
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60); 
#endif

if(address)
   output_high(LCD_RS);
else
   output_low(LCD_RS);
     
 delay_cycles(1);

#ifdef USE_RW_PIN
output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
//----------------------------

void lcd_init(void)
{
   int8 i;

   lcd_line = 1;

   output_low(LCD_RS);

   #ifdef USE_RW_PIN
      output_low(LCD_RW);
   #endif

   output_low(LCD_E);

   // Some LCDs require 15 ms minimum delay after
   // power-up.  Others require 30 ms.  I'm going
   // to set it to 35 ms, so it should work with
   // all of them.
   delay_ms(35);         

   for(i=0 ;i < 3; i++)
   {
      lcd_send_nibble(0x03);
      delay_ms(5);
   }

   lcd_send_nibble(0x02);

   for(i=0; i < sizeof(LCD_INIT_STRING); i++)
   {
      lcd_send_byte(0, LCD_INIT_STRING[i]);
   
      // If the R/W signal is not used, then
      // the busy bit can't be polled.  One of
      // the init commands takes longer than
      // the hard-coded delay of 50 us, so in
      // that case, lets just do a 5 ms delay
      // after all four of them.
      #ifndef USE_RW_PIN
         delay_ms(5);
      #endif
   }

}

//----------------------------

void lcd_gotoxy(int8 x, int8 y)
{
int8 address;


switch(y)
  {
   case 1:
     address = LCD_LINE_1_ADDRESS;
     break;

   case 2:
     address = LCD_LINE_2_ADDRESS;
     break;

   case 3:
     address = LCD_LINE_3_ADDRESS;
     break;

   case 4:
     address = LCD_LINE_4_ADDRESS;
     break;

   default:
     address = LCD_LINE_1_ADDRESS;
     break;
     
  }

address += x-1;
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
 switch(c)
   {
    case '\f':
      lcd_send_byte(0,1);
      lcd_line = 1;
      delay_ms(2);
      break;
   
    case '\n':
       lcd_gotoxy(1, ++lcd_line);
       break;
   
    case '\b':
       lcd_send_byte(0,0x10);
       break;
   
    default:
       lcd_send_byte(1,c);
       break;
   }
}

//------------------------------
#ifdef USE_RW_PIN
char lcd_getc(int8 x, int8 y)
{
char value;

lcd_gotoxy(x,y);

// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7)); 

output_high(LCD_RS);
value = lcd_read_byte();
output_low(LCD_RS);

return(value);
}
#endif

Muchas gracias y suerte.

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #8 en: 02 de Septiembre de 2012, 11:13:27 »
me olvidava, la libreria la copie del usuario PicTrance del foro de neoteo, tambien agradecer a _Suky_, del mismo foro.

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #9 en: 03 de Septiembre de 2012, 10:57:19 »
Ahora que ya esta lo del LCD en el 4550, pues ahora me puse a hacer el teclado analógico, pero......, mi duda es cómo hago los if's anidados, hice un código de ello, pero me da error, me dice: "A numeric expression must appear here" en la línea que corresponde al else if.

Aparte, creo que solucione eso de la configuracion de pines analógicos, ahora ya no esta declarados todos los ADC, sino que na mas los ADC's del puerto A, aqui pongo el código para que le hechen una revisada, para ver si esta correcto la declaracion de puertos, jajaja, y eso de los if's tambien.

Código: [Seleccionar]
#include <18F4550.h>
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT
#device adc=10
#use delay(clock=20000000)
#use standard_io (B)

#include <lcd20Cx4F.c>

void main()
{
   int Tecla,TeclaAntigua;
   int Teclap;
   
   setup_port_A(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   lcd_init();
   Tecla = 0;
   TeclaAntigua = 0;
   while (true)
   {
      set_adc_channel(0);
      delay_us (50);
      Tecla = read_adc();

      if ((Tecla) && (Tecla!=TeclaAntigua))
      {         
         // aqui empieza if anidados
         if (Tecla < 440)
            {
               Teclap = 13;
               else if (Tecla < 462)
               {
                  Teclap = 12;
                  else if (Tecla < 488)
                  {
                     Teclap = 11;
                     else if (Tecla < 496)
                     {
                        Teclap = 10;
                        else if (Tecla < 523)
                        {
                           Teclap = 15;
                           else if (Tecla < 554)
                           {
                              Teclap = 9;
                              else if (Tecla < 592)
                              {
                                 Teclap = 6;
                                 else if (Tecla < 603)
                                 {
                                    Teclap = 3;
                                    else if (Tecla < 617)
                                    {
                                       Teclap = 0;
                                       else if (Tecla < 661)
                                       {
                                          Teclap = 5;
                                          else if (Tecla < 733)
                                          {
                                             Teclap = 2;
                                             else if (Tecla < 770)
                                             {
                                                Teclap = 14;
                                                else if (Tecla < 839)
                                                {
                                                   Teclap = 7;
                                                   else if (Tecla < 931)
                                                   {
                                                      Teclap = 4;
                                                      else if (Tecla < 951)
                                                      {
                                                         Teclap = 1;
                                                      }
                                                   }
                                                }
                                             }
                                          }
                                       }
                                    }
                                 }
                              }
                           }
                        }
                     }
                  }
               }
            }
         // aqui termina if anidados
 
      }
      printf(lcd_putc,"\f   TECLA  PULSADA \n     %2u",Teclap);
      delay_ms (300);
      TeclaAntigua = Tecla;
   }
   
}

Desde ya, muchas gracias.

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #10 en: 03 de Septiembre de 2012, 12:11:34 »
  El if anidado podría ser algo así

Código: C
  1. if (tecla < 440) teclap = 13;
  2. else
  3.   if (tecla < 462) teclap = 12;
  4.   else
  5.     if (tecla < 488) teclap = 11;

 y sigue así hasta la última evaluación...


 también se puede recurrir a esta otra forma

Código: C
  1. if ((tecla < 462) && (tecla > 440)) teclap = 12;

  Aunque a la vista me resulta más elegante la segundo forma, seguramente llevará más tiempo de ejecución -y no sé si no generará más código- ya que siempre se evalúan todas las posibilidades. En cambio, en la primer forma, cuando se cumple una de las condiciones, el resto no se evalúa.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #11 en: 04 de Septiembre de 2012, 13:13:37 »
Hola.

Hice de las dos formas, en la primera sigue saliendo el warning que la sentencia siempre es verdadera, en la segunda opcion de código me sale:
warning: Variable of this data type is never greater than this constant.
algo como que una variable nunca es mayor que una constante.

pues eso ya me dejo............ :?

En la simulasion me muestra directamente en la pantalla :
TECLA PULSADA ES
   13

y no cambia para nada.

En el código cambie esta línea:
Código: [Seleccionar]
if ((tecla != 0) && (tecla!=teclaantigua))antes estava como:
Código: [Seleccionar]
if ((tecla) && (tecla!=teclaantigua))sin que la variable tecla se compare con nada al inicio del if

con eso esperaba solucionar el problema del warning: valor siempre sera verdadero

bueno, aqui, otraves, el código:

Código: [Seleccionar]
#include <18F4550.h>
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT
#device adc=10
#use delay(clock=20000000)
#use standard_io (B)

#include <lcd20Cx4F.c>

void main()
{
   int tecla,teclaantigua;
   int teclap;
   
   //setup_adc_ports(ALL_ANALOG);
   setup_port_A(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   lcd_init();
   tecla = 0;
   teclaantigua = 0;
   teclap = 0;
   while (true)
   {
      set_adc_channel(0);
      delay_us (50);
      tecla = read_adc();
      //printf(lcd_putc,"\f   TECLA  PULSADA \n     %2u",Tecla);
      if ((tecla != 0) && (tecla!=teclaantigua))
      {         
         // aqui empieza if anidados
         if ((tecla < 440) && (tecla > 0)) teclap = 13;
         if ((tecla < 462) && (tecla > 440)) teclap = 12;
         if ((tecla < 488) && (tecla > 462)) teclap = 11;
         if ((tecla < 496) && (tecla > 488)) teclap = 10;
         if ((tecla < 523) && (tecla > 496)) teclap = 15;
         if ((tecla < 554) && (tecla > 523)) teclap = 9;
         if ((tecla < 592) && (tecla > 554)) teclap = 6;
         if ((tecla < 603) && (tecla > 592)) teclap = 3;
         if ((tecla < 617) && (tecla > 603)) teclap = 0;
         if ((tecla < 661) && (tecla > 617)) teclap = 8;
         if ((tecla < 716) && (tecla > 661)) teclap = 5;
         if ((tecla < 733) && (tecla > 716)) teclap = 2;
         if ((tecla < 770) && (tecla > 733)) teclap = 14;
         if ((tecla < 839) && (tecla > 770)) teclap = 7;
         if ((tecla < 931) && (tecla > 839)) teclap = 4;
         if ((tecla < 959) && (tecla > 931)) teclap = 1;
         /*
         if (Tecla < 440) Teclap = 13;
         else
            if (Tecla < 462) Teclap = 12;
            else
              if (Tecla < 488) Teclap = 11;
              else
                if (Tecla < 496) Teclap = 10;
                else
                  If (Tecla < 523) Teclap = 15;
                  else
                    if (Tecla < 554) Teclap = 9;
                    else
                      if (Tecla < 592) Teclap = 6;
                      else
                        if (Tecla < 603) Teclap = 3;
                        else
                          if (Tecla < 617) Teclap = 0;
                          else
                            if (Tecla < 661) Teclap = 8;
                            else
                              if (Tecla < 716) Teclap = 5;
                              else
                                if (Tecla < 733) Teclap = 2;
                                else
                                  if (Tecla < 770) Teclap = 14;
                                  else
                                    if (Tecla < 839) Teclap = 7;
                                    else
                                      if (Tecla < 931) Teclap = 4;
                                      else
                                        if (Tecla < 959) Teclap = 1;
                                                  */
         // aqui termina if anidados
   
      }
      printf(lcd_putc,"\f   TECLA  PULSADA \n     %2u",teclap);
      delay_ms (300);
      teclaantigua = tecla;
   }
   
}

deje como comentario los if anidados

Muchas gracias.

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #12 en: 04 de Septiembre de 2012, 13:47:44 »
  Fijate en la ayuda de CCS porque creo que las variables INT en dicho compilador son de 8 bits. Si es así, el máximo valor que puede almacenar es 255 y  por lo tanto siempre tendrá un valor menor a 440.

  Busca que tipo corresponde a una variable de 16 bits... ¿será int16?
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #13 en: 05 de Septiembre de 2012, 17:50:16 »
Uyyy... cómo no se me ocurrio revisar esa parte, muchas gracias, lo reviso y haber cómo anda.

Saludos.

Desconectado Lord_Duran

  • PIC12
  • **
  • Mensajes: 76
Re: Problemas con LCD 4x20 y PIC18F4520
« Respuesta #14 en: 06 de Septiembre de 2012, 08:45:24 »
Hola..

Ahora ya me muestra los números correspondientes a cada tecla.
Con el código anterior, na mas que las variables eran de tipo long o int16, ya que AngelGris tiene razón, como estaba el código, la variable nunca va a ser mayor a 255, que pasada la mia,  :D :D

el arreclo que hice fue este:
Código: [Seleccionar]
long tecla,teclaantigua;
int teclap;

Bueno, haber, otra duda.

El código sugerido, para solucionar eso de los if's:
Código: [Seleccionar]
if ((tecla < 462) && (tecla > 440)) teclap = 12;

esta mejor que solo preguntar si la variable es menor y procediendo con else if, pero....., el problema es que tarda en responder, osea, cada tecla tengo que mantenerla pulsada porlomenos 1 segundo, y si suelto en un tiempo menor, pues no la lee, intente hacer tambien metiendole else if, suponiendo que (sin else) si una condicion se cumple, seguira evaluando las demás hasta terminar con todas las sentencias de condición (if), y que por esa razón es que tarda en reconocer una tecla, pues al código le hice lo siguiente, na mas le aumente "else":

Código: [Seleccionar]
if ((tecla < 440) && (tecla > 0)) teclap = 13;
         else
         if ((tecla < 462) && (tecla > 440)) teclap = 12;
         else
         if ((tecla < 488) && (tecla > 462)) teclap = 11;
         else
         if ((tecla < 496) && (tecla > 488)) teclap = 10;
         else
         if ((tecla < 523) && (tecla > 496)) teclap = 15;
         else
         if ((tecla < 554) && (tecla > 523)) teclap = 9;
         else
         if ((tecla < 592) && (tecla > 554)) teclap = 6;
         else
         if ((tecla < 603) && (tecla > 592)) teclap = 3;
         else
         if ((tecla < 617) && (tecla > 603)) teclap = 0;
         else
         if ((tecla < 661) && (tecla > 617)) teclap = 8;
         else
         if ((tecla < 716) && (tecla > 661)) teclap = 5;
         else
         if ((tecla < 733) && (tecla > 716)) teclap = 2;
         else
         if ((tecla < 770) && (tecla > 733)) teclap = 14;
         else
         if ((tecla < 839) && (tecla > 770)) teclap = 7;
         else
         if ((tecla < 931) && (tecla > 839)) teclap = 4;
         else
         if ((tecla < 959) && (tecla > 931)) teclap = 1;

pero el tiempo de retardo para cada tecla sigue siendo el mismo, es cómo si siguiese evaluando todas las condiciones sin importar que se cumpla la anterior.

Se me ocurrio la idea de hacerlo con la sentencia "case", pero el problema esta en que cómo haria para saber exáctamente que número es el que va a evaluar cada caso.

Nota: En la simulasion, cambiar la resistencia divisora de voltaje de 10k por 1k, me equivoque esa parte... :5] :D :D.

Muchas gracias.