LCD-Initialisierung

Gast #40637
Lesenswert?

Hallo,
ich hab Probleme mit der Initialisierung meines LCD. Ich benutze den
8535 mit 8MHz.
Ich denke es liegt an den Pausen, die man einlegen muss, weil ich mit
den Verzögerungsschleifen auch noch nicht so recht klarkomme.
Vielleicht könnt ihr euch den Qullcode mal angucken und mir
weiterhelfen. Danke

#include <lcd.h>



#define LCD_BLANK()        {lcd_send_command(1);delay_ms(2);}

#define DISPLAY_ON()     {lcd_send_command(12);}

#define DISPLAY_OFF()     {lcd_send_command(8 v);}

#define nop() asm volatile ("nop")


typedef unsigned char byte;


// Hier befinden sich die Eigenschaften der LCD-Anzeige für die
Initialisierung
byte LCD_INIT_STRING[] = {0x28, 0x0C, 0x01, 0x06};
// 44 = FunktionSet 44 = 0010 1000 = 2C
// 0, 12 = Display an
// 0, 1  = clear Display
// 0, 6 = Entry mode set

//Wartearray für Initialisierung
byte wait[] = {,,};
//5ms, 110us, 110us


int main(void)
{




  //Portbelegung
  //PortA Taster
  outp(0x00, DDRA);

  //PortB LEDs
  outp(0xff, DDRB);
  outp(0x00, PORTB);



  lcd_init();                // Initialisierung der LCD-Anzeige



  lcd_putc(1, "Ein Test");



  for(;;)
  {



      {
        outp(0xf0, PORTB);

      }


  }
}




void lcd_send_nibble( byte n )
{


        outp(n<<4, PORTC);

  sbi(PORTC, 2);  //Enable = 1
           nop();
        cbi(PORTC, 2);  //Enable =0

}

void lcd_send_byte( byte address, byte n )
{
  if(address)
     sbi(PORTC,0);  //RS = 1 ->Daten schreiben
   else
     cbi(PORTC,0);  //RS = 0 ->Kommando senden

      cbi(PORTC, 1);  //RW = 0
   //   sbi(PORTC, 2);  //E = 1

  wait_busy();
      lcd_send_nibble(n >> 4);
  wait_busy();
      lcd_send_nibble(n & 0x0f);

}

byte lcd_init()
{
    byte i;

    outp(0xff, DDRC);

   //RS, RW auf 0,E auf 0
    cbi(PORTC, 0);               // siehe 4-Bit Initialisierung
(LCD-Datenblatt)
   // cbi(PORTC, 1);
    cbi(PORTC, 2);


  //Länger als 15ms warten
  long_delay();  // 16 ms Pause

    for(i=0;i<3;i++)
    {
       lcd_send_nibble(3);
       if(i==0 || i == 1)
           long_delay(wait[i]);

       else
          delay(wait[i]);

    }


  lcd_send_nibble(2);
  delay();

    for(i=0; i <= 3; i++)
    {
       lcd_send_command(LCD_INIT_STRING[i]);

    }


}



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

   if (y==1)  address=0;  //
   else if (y==2) address=0x40;
   else address=0;

   address += x-1;

   lcd_send_command(0x80|address); //mmmmmh, ob das stimmt?
}



void lcd_putc( byte Zeile, char f)
{
//  lcd_gotoxy(1, Zeile);
  lcd_send_data(f);
}


void lcd_send_command(byte cmd)
{
  lcd_send_byte(0, cmd);
}

void lcd_send_data(byte data)
{
  lcd_send_byte(1, data);
}


void wait_busy()
{
      register byte data;

  cbi(PORTC,0);  //RS = 0
      sbi(PORTC, 1);  //  RW = 1
   //   sbi(PORTC, 2);  //E = 1 (HIGH)
      outp(0x0f, DDRC);  //BIT 7-4 als Input

  do
  {
    sbi(PORTC, 2);  //Enable = 1
    nop();
         data = inp(PINC);
          cbi(PORTC, 2);  //Enable = 0

  }while(data & 0x80);

  //Standards Wiederherstellen
  outp(0xff, DDRC); //Port C wieder Ausgang
  cbi(PORTC,1);  //RW wieder 0

}





void delay(unsigned char n)            //Wie kann ich hier die
                                       //verstrichene Zeit errechnen?
{
  while(n--);
}

void long_delay(unsigned char loop)
{
  unsigned char warten, i;
  for(i=loop; i>0; i--)
  {
    warten = 1000;
    while(warten--);
  }
}






/* 16-bit count, 4 cycles/loop */
/*void delay_loop_2(unsigned int __count)
{
  asm volatile (
    "1: sbiw %0,1" "\n\t"
    "brne 1b"
    : "=w" (__count)
    : "0" (__count)
  );
}


//  1 Mikrosekunde,      stimmt die Berchnung
// 1us sollten doch 8 Cycles sein, oder? bei 8MHz
void delay_us(unsigned int count)
{
  delay_loop_2( 2 * count);
}


//  1 Millisekunde
void delay_ms(unsigned int count)
{
  delay_us(1000 * count);
}


*/
Gast #40639
Lesenswert?

Ich hab das undefiniert gelassen, so wie jede andere delay-schleife
auch, weil ich nicht weiß welchen Wert ich da benutzten soll.
Am Ende von dem Quelltext sind zwei unterschiedliche Arten von
Delayloops, die aber beide nicht richtig funktionieren, wobei
zzumindest die, die ich auskommentiert habe, richtig funktionieren
sollte.

mfg
  Daniel
Gast #40640
Lesenswert?

Deine eigenen delay-Funktion gehen nicht, weil der Compiler die
Zählschleifen wegoptimierten kann.
Aus:
  warten=1000;
  while(warten--);
wird dann:
  warten -=1000;

Ich verwende z.Zt diese Warteschleifen:

void
lcd_delay_5ms() {
  uint16_t i;
  /* t = i * loop / UC_CLOCK
     i = t / loop * UC_CLOCK
     the fastest way the compiler can do that loop takes 5 clocks:
     2 clocks for decrementing, 1 for nop, 2 clocks to branch.
     take care that i does not exceed max(uint16_t) */
  for (i=UC_CLOCK*0.005/5; i; i--)
    asm volatile("nop\n\t"::);   /* required to prevent compiler
optimisation */
}

inline void
lcd_delay_50us() {
  uint8_t i;
  /* t = i * loop / UC_CLOCK
     i = t / loop * UC_CLOCK
     the fastest way the compiler can do that loop takes 4 clocks:
     1 clocks for decrementing, 1 for nop, 2 clocks to branch.
     take care that i does not exceed max(uint8_t) */
  for (i=UC_CLOCK*50e-6/4; i; i--)
    asm volatile("nop\n\t"::);   /* required to prevent compiler
optimisation */
}

meine Init-Routine sieht so aus:
void lcd_init() {
  uint8_t i;

  LCD_DATA_PORT &= ~LCD_DATA_MASK; /* clear the data pins */
  LCD_DATA_DDR |= LCD_DATA_MASK;   /* define the data pins as output */
  LCD_ENABLE_PORT &= ~_BV(LCD_ENABLE_PIN);  /* clear enable pin */
  LCD_ENABLE_DDR |= _BV(LCD_ENABLE_PIN);  /* and define as output */
  LCD_RS_PORT &= ~_BV(LCD_RS_PIN);  /* clear RS pin */
  LCD_RS_DDR |= _BV(LCD_RS_PIN);  /* and define as output */

  for (i=50; i; i--)    /* 250ms power up wait */
    lcd_delay_5ms();

  LCD_DATA_PORT |= 0x03;   /* put the LCD into 8-bit mode, send 3-times
*/
  lcd_enable();
  lcd_delay_5ms();         /* 1 */
  lcd_enable();
  lcd_delay_5ms();         /* 2 */
  lcd_enable();
  lcd_delay_5ms();         /* 3 */

  LCD_DATA_PORT &= ~LCD_DATA_MASK;   /* delete the data port pins */
  LCD_DATA_PORT |= 0x02;   /* put lcd into 4-bit mode */
  lcd_enable();
  lcd_delay_5ms();

  /* function set (bit 7-5 */
  /* 4-bit mode (bit4), 2-lines (bit3), 7*5 dots (bit2), xx bit1-0 */
  lcd_command(0x28);

  /* entry mode set (bit7-2)
     cursor move direction increase (bit1=1), display is not shifted
(bit0=0) */
  lcd_command(0x06);

  /* display mode set (bit7-3)
     display on (bit2=1), cursor on (bit1=1), blinking off (bit0=0) */
  lcd_command(0x0E);
}


mfg
werner

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren