TODOPIC

Microcontroladores PIC => Todo en microcontroladores PIC => Mensaje iniciado por: et14455 en 05 de Enero de 2005, 04:04:00

Título: Ayuda LCD y 18F452
Publicado por: et14455 en 05 de Enero de 2005, 04:04:00
Hola, soy nuevo en esto de los PICS y la verdad es que me he quedado encallado en el primer paso.

Tengo un PIC 18F452 con un LCD (16x2) basado en el controlador HD44780. Uso un reloj externo de 20 Mhz y la verdad es que no consigo que el LCD me muestre ningún texto. El código que utilizo es el siguiente:
Codigo:

#include <18f452.h>
#include <stdlib.h>
#include <string.h>

#define RW   PIN_A2
#define E   PIN_A1
#define RS   PIN_A3
#define disp_on   0b00001111
#define curs_off 0b00001101
#define blink_off 0b00001110

char text[16];

#Fuses HS,NOPROTECT,NOBROWNOUT,NOWDT,PUT,NODEBUG,NOLVP
#use delay (clock=20000000)

//Coloca els 4 bits de menor per de data al port d (0-3), manté E activat durant 1 us.
void clknibbleout(unsigned char data)
{
   data &= 0x0f;
   output_d(data);
   delay_us(1);
   output_bit(E,1);
   delay_us(1);
   output_bit(E,0);
}


unsigned char LCD_BUSY(void)
{
   unsigned char port_data, port_busypin;
   set_tris_d(0xff); //Configura el port d com entrada
   output_bit(RW,1); //Posa RW a 1
   output_bit(RS,0); //Posa RS a 0
   delay_us(1);
   output_bit(E,1); //Activa E
   delay_us(1);
   port_data = input_d(); //Llegeix el port d
   port_busypin = port_data & (0x08); //and amb el bit d3
   output_bit(E,0); //Desactiva E
   delay_us(1);
   output_bit(E,1); //Activa E
   delay_us(1);
   output_bit(E,0); //Desactiva E
   output_bit(RW,0); //Desactiva RW
   set_tris_d(0x00); //Configura el port d com sortida
   return port_busypin; //Retorna el bit d3
}

void LCD_Command(unsigned char cmd)
{
   set_tris_d(0x00);
   output_bit(RW,0);
   output_bit(RS,0);
   clknibbleout(cmd>>4);
   clknibbleout(cmd);
}

void LCD_WriteChar(char data)
{
   set_tris_d(0x00);
   output_bit(RW,0);
   output_bit(RS,1);
   clknibbleout(data>>4);
   clknibbleout(data);
   set_tris_d(0xff);
}


void LCD_init(void)
{
   SET_TRIS_A(0x04); //Activa R/W com entrada i E i RS com sortida
   SET_TRIS_D(0x00); //Posa el port D com sortida

   output_bit(RW,0); //Posa senyals de control a 0
   output_bit(E,0);
   output_bit(RS,0);

   delay_ms(5);

   clknibbleout(0b00000011); //Treu 0011 per d0-d3
   delay_ms(5);
   clknibbleout(0b00000011); //Treu 0011 per d0-d3
   delay_ms(5);
   clknibbleout(0b00000010); //Treu 0010 per d0-d3
   delay_ms(5);
   clknibbleout(0b00000010); //Treu 0010 per d0-d3
   clknibbleout(0b00001000); //Treu 1000 per d0-d3

   while(LCD_BUSY());         //Mentres
   LCD_Command(0x01);
   delay_ms(20);
   LCD_Command(disp_on & curs_off & blink_off);
}

void LCD_display(unsigned char line, unsigned char position, char *text)
{
   int i =0;
   unsigned char address ;
   address = position - 1;
   if(line == 2)
   address += 0x40;
   address += 0b10000000;
   while(LCD_BUSY());
   LCD_Command(address);
   while(text)

      {
      while(LCD_BUSY());
      delay_us(10);
      LCD_WriteChar(text);
      i++;
      }
}

void clear_screen(void)
{
   strcpy(text, "              ");
   delay_us(50);
   LCD_display(1, 1, text);
   LCD_display(2, 1, text);
}


void main(void)
{

setup_adc_ports(NO_ANALOGS);
set_tris_b(0x00);
OUTPUT_HIGH(PIN_B0);
delay_ms(1000);
LCD_init();
OUTPUT_LOW(PIN_B0);
delay_ms(1000);
clear_screen();
OUTPUT_HIGH(PIN_B0);
delay_ms(1000);
strcpy(text, "Hola Mon");
delay_us(50);
LCD_display(1, 1, text);
delay_ms(500);
strcpy(text, "HOLA MON 2");
delay_us(50);
LCD_display(2, 1, text);
delay_ms(1500);
}



Cuando lo ejecuto se enciende el LED de B0, se apaga y se vuelve encender, después se quedan todos los puntos de la primera fila encenddidos y ahí se queda.

Uso el compilador CCS 3.212 con el MPLAB 6.60.

Muchas gracias por su ayuda.
Título: RE: Ayuda LCD y 18F452
Publicado por: fer_zone en 09 de Enero de 2005, 19:51:00
Puedo ver muchas contradicciones en el programa, como setear R/W como entrada y despues usarlo como salida (es verdad que el compilador debería pasar la configuración a salida, pero yo le sacaría todas las instrucciónes TRIS y dejaria que el compilador se encargue solo).
La descripción que haces es tipica de un LCD que recibe alimentación pero no recibe ningun comando del micro, por eso tambien tenes que verificar la parte electronica de conexión LCD-Micro.

Ya que usas el CCS, por qué no usas el driver que ya trae lcd.c, incluso trae un programa de ejemplo, solo tendrias que cambiarle los puerto que estas usando.
Título: RE: Ayuda LCD y 18F452
Publicado por: eumoll en 10 de Enero de 2005, 04:00:00
Yo tengo el mismo problema, no consigo hacer funcionar el LCD con un 18F452. Uso el CCS con las librerías del propio CCS, aunque he cambiado los puertos de salida al puerto D, en lugar del B.

Os agradecería un comentario al respecto, puesto que no sé por donde puede fallar el asunto.

El código también conecta con un teclado, aunque esta opción la tengo comentada, puesto que primero quiero hacer funcionar el LCD solo.

A continuación os pongo el código que uso:

[code]
#include <18F452.h>
#Fuses HS,NOPROTECT,NOBROWNOUT,NOWDT,PUT,NODEBUG,NOLVP
#use  delay( clock=20000000 )
#include <math.h>
#include "Lcd.c"

// Keypad Layout
// 1 2 3 A
// 4 5 6 B
// 7 8 9 C
// * 0 # D

struct keypad_pin_map
{
    int  key: 4;
    int  row: 4;
} PortC;

#Byte PortC = 0xF82
#Byte PortD = 0xF83

#use fast_io( C )
#use fast_io( D )

struct Keypad_pin_map const WR = {0,0};
struct Keypad_pin_map const RD = {15,0};

//"1"=17, "2"=18, "3"=20, "A"=24
//"4"=33, "5"=34, "6"=36, "B"=40
//"7"=65, "8"=66, "9"=68, "C"=72
//"*"=129 "0"=130 "#"=132 "D"=136
byte ReadKeyPad()
{
  byte i,k,l,Res;
  Res = 0;
  for (i=0; i<4; i++)
     {
       Set_Tris_C( WR );
       PortC.Key = 0;
       PortC.Row = exp(i*log(2));
       delay_us(50);
       Set_Tris_C( RD );
       k = PortC.Key;
       l = exp((4+i)*log(2));
       if( k!= 0) { Res = k|l; }
     }
  return Res;
}

void main()
{
  byte c;
  lcd_init();
  lcd_putc("f  HOLA
" );
  lcd_putc(   "  MUNDO  " );
  delay_ms(1000);
/*
  while(1)
  {
     c = ReadKeyPad();
     if (c != 0) printf(lcd_putc, "f%u", c );

  }
*/
}
[code]

Además el código de "lcd.c" modificado para que funcione sobre el puerto D és el siguiente:

[code]
// As defined in the following structure the pin connection is as follows:
//     D0  enable
//     D1  rs
//     D2  rw
//     D4  D4
//     D5  D5
//     D6  D6
//     D7  D7
//
//   LCD pins D0-D3 are not used and PIC B3 is not used.

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 = 8                        // This puts the entire structure
                                     // on to port B (at address 6)

#define lcd_type 2           // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40    // LCD RAM address for the second line


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 lcd_read_byte() {
byte low,high;

set_tris_d(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_d(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_d(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);
}


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

if(y!=1)
address=lcd_line_two;
else
address=0;
address+=x-1;

lcd_send_byte(0,0x80|address);
}

void lcd_putc( char c) {
switch (c) {
case "f" : lcd_send_byte(0,1);
delay_ms(2);
break;
case "
" : lcd_gotoxy(1,2); break;
case "" : 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);
}
[code]