LCD KS0073 am AVRATMega128

Gast #475075
Lesenswert?

Hallo,

habe folgenden Code um das Display (4x20) im 2Zeile 5x8 Modus zu 
initialisieren:

void initLCD(void)
{
  LCD_DDR = 0xEF;   // alle Pins PortC auf  Ausgang schalten
  wait10ms(10);
  int i;
  for (i= 0;i<3;i++)
  {
    LCD_PORT = 3;      // 8Bit
    wait10ms(1);
  }
  LCD_PORT = 2;        // 4Bit
  wait10ms(1);
  LCD_PORT = 10;        // 2-Line Mode 5x8
  wait10ms(1);
  LCD_Enable();
  LCD_PORT = 15;    // Cursor =1, Blink =1, Disp = 1
  _delay_ms(1);
  LCD_Enable();
  LCD_PORT = 1;        // clear Disp
  LCD_Enable();
  LCD_PORT = 6;  //Kursor nach rechts wandernd, kein Display shift
  wait10ms(1);
}

Das Habe ich hier:
http://www.sprut.de/electronic/lcd/index.htm#4x40
her und aus dem Datenblatt des Controllers.

Aber es funktioniert leider nicht richtig. Die Zeichen sehen arg komisch 
aus, es hält sich auch nicht an das Layout (Zeilen) und löschen (D0 =1) 
geht auch nicht!

Hat von euch vielleicht jemand eine Idee was ich falsch mache?

Die HW habe ich bereits gründlich debugged, da liegt der Fehler nicht!

// LCD Display
#define LCD_DDR  DDRC
#define LCD_PORT PORTC
#define LCD_PIN  PINC
#define LCD_D0   PINC0
#define LCD_D1   PINC1
#define LCD_D2   PINC2
#define LCD_D3   PINC3
#define LCD_RS   PINC4
#define LCD_RW   PINC5
#define LCD_ENB   PINC6

Servus Sven!
Gast #475121
Lesenswert?

Ich würde die Warteschleifen kontrollieren und ggf. mal um 50%/100% 
hochsetzen. Und ich würde die elektrischen Verbindungen aller Leitungen 
checken, ob Unterbrechungen oder Vertauschungen vorhanden sind.

Kannst du anhand des Controllerdatenblatts und der Charactertabelle dort 
drin eine Systematik ausmachen zwischen deinen Wunschzeichen und den 
angezeigte Zeichen?
Gast #475152
Lesenswert?

Grüß euch!

Mit den Wartezeiten hab ich schon gespielt, das hatte bislang keinen 
Erfolg.
Die Leitungen hab ich alle kontrolliert, jede einzeln auf Hi geschaltet 
und mit dem Multimeter am LCD-Sockel nachgemessen.

Komisch ist ja, dass nicht mal das löschen des LCD hinhaut, es liegt 
damit wohl an der Initialisierung. Hab dazu auch unterschiedliche 
Lösungen gefunden, und ausprobiert.

Hat von euch auch Jemand auch so ein Display, und kann mal die 
Initialisierungen vergleichen?

Servus Sven!
Gast #475156
Lesenswert?

Hab das nochmal überarbeitet, anhand eines Datenblattes das ich bei 
Electronic Assembly gefunden habe!

Dort wird folgende Initialisierung vorgeschlagen:

void initLCD(void) // Initialisierung des Displays |||4x20 Display ist 
ein 2 Zeilen 5*8 Dislpay!|||
{
  LCD_DDR = 0xFF;   // alle Pins PortC auf  Ausgang schalten
  wait10ms(10);
  LCD_setRS(0);
  LCD_setRW(0);
  LCD_setENB(0);

  LCD_PORT = 2;        // 4Bit
  _delay_ms(5);

  LCD_PORT = 2;        // 4Bit
  _delay_ms(3);
  LCD_PORT = 8;        // 2-Line Mode 5x8
  _delay_ms(5);

  LCD_PORT = 0;        // 2-Line Mode 5x8
  _delay_ms(3);
  //LCD_Enable();
  LCD_PORT = 15;      // Cursor =1, Blink =1, Disp = 1
  _delay_ms(5);

  LCD_PORT = 0;        // Cursor auf Anfang
  _delay_ms(3);
  LCD_PORT = 1;        // Display löschen
  _delay_ms(5);
  //LCD_Enable();

  LCD_PORT = 0;        // clear Disp
  _delay_ms(3);
  LCD_PORT = 6;  //Kursor nach rechts wandernd, kein Display shift
  wait10ms(1);
}

Hat aber auch nichts gebracht!
Gast #475163
Lesenswert?

So ist das dann doch übersichtlicher:

void LCD_Command(char byte_high)  //Pin0-Pin3 sind die Datenleitungen
{
  putch(byte_high);    // Ausgeben auf Uart für Debug!
  char byte_low = byte_high;    //Sichern für unteres Nibble
// Oberes Nibble zuerst ausgeben
  byte_high &= ~0x0f;      //unteres Nibbel 0 setzen
  byte_high = byte_high>>4;    //Wert ins untere Nibble schieben.
  LCD_PORT = byte_high;      //oberes Nibbel Ausgeben
  LCD_Enable();        //Enable Impuls
  putch(byte_high);      // Ausgeben auf Uart für Debug!
// Dann unteres Nibble
  byte_low &= ~0x0f;      //oberes Nibble löschen
  LCD_PORT = byte_low;      //unteres Nibbel Ausgeben
  LCD_Enable();
  putch(byte_low);      // Ausgeben auf Uart für Debug!
  //_delay_us(50);
  _delay_ms(5);
}

void initLCD(void) // Initialisierung des Displays |||4x20 Display ist 
ein 2 Zeilen 5*8 Dislpay!|||
{
  LCD_DDR = 0xFF;       // alle Pins PortC auf  Ausgang schalten
  wait10ms(10);
  LCD_setRS(0);
  LCD_setRW(0);
  LCD_setENB(0);

  LCD_PORT = 2;    // 4Bit
  _delay_ms(5);

  LCD_Command(40);  // 4 Bit 5x8
  LCD_Command(0x0F);  // Cursor =1, Blink =1, Disp = 1
  LCD_Command(0x01);  // Display löschen
  LCD_Command(6);    //Kursor nach rechts wandernd, kein Display shift
  wait10ms(1);
}
Gast #475171
Lesenswert?

Ich benutze folgenden CODE für eine 4x20 LCD von electronic assembly mit 
KS0073 und mega32.

#include <avr/io.h>

//LCD-Steuerleitungen
#define LCD_CONTROL   PORTA
#define LCD_CONTROL_DIR DDRA
#define LCD_RS      1    //PortD.4
#define LCD_RW      2    //PortD.6
#define LCD_EN      3    //PortD.5

//LCD-Datenport: Reihenfolge des High Nibbles (4-7) muss eingehalten 
werden,
//Port kann getauscht werden:
#define LCD_DATEN    PORTA
#define LCD_DATEN_DIR  DDRA
#define LCD_BF      PINA
#define LCD_D4      4     //Porta.4
#define LCD_D5      5     //Porta.5
#define LCD_D6      6     //Porta.6
#define LCD_D7      7     //Porta.7

//********************************************************************** 
***************
//Delay ca. 0.5*x ms bei 16 MHz
//********************************************************************** 
***************
void delay (unsigned int x)
{
  unsigned int a, y;
  for (a=0; a<x; a++)
  {
    for (y=0; y<1333; y++)
    {
      asm("nop");
    }
  }
}
//********************************************************************** 
***************
//LCD code
//********************************************************************** 
***************


void lcd_busy(void)
{
  unsigned char test=0;
  LCD_CONTROL &= ~(1<<LCD_RS);
  LCD_CONTROL |= (1<<LCD_RW);
  LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); 
//Eingang für BUSY FLAG
  while (1)
  {
    LCD_CONTROL|=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    if (!(LCD_BF & (1<<LCD_D7))) test = 1;
    LCD_CONTROL &= ~(1<<LCD_EN);


    LCD_CONTROL |=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    LCD_CONTROL &= ~(1<<LCD_EN);
    if (test) break;
  }

  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); 
//Ausgänge
}

void lcd_befehl(unsigned char befehl)
{

  LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW));
  LCD_DATEN = ((0b11110000 & befehl)|(LCD_DATEN& 0b00001111)); 
//PORTA = HIGH Nibble
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");

  LCD_CONTROL &= ~(1<<LCD_EN);        //High Nibble mit fallender Flanke 
übernehmen

  LCD_DATEN = ((0b11110000 & (befehl<<4))|(LCD_DATEN& 0b00001111)); 
//Low Nibble
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}


void lcd_char(unsigned char daten)
{
  LCD_CONTROL |=(1<<LCD_RS);          //Für Daten
  LCD_CONTROL &= ~(1<<LCD_RW);        //LCD soll lesen
  LCD_DATEN = ((0b11110000 & daten)|(LCD_DATEN& 0b00001111));
  LCD_CONTROL |= (1<<LCD_EN);          //Daten übernehmen
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);

  LCD_DATEN = ((0b11110000 & (daten<<4))|(LCD_DATEN& 0b00001111));
  LCD_CONTROL|= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}

void lcd_string (unsigned char *string)
{
  while (*string)
          lcd_char (*string++);
}


void lcd_init(void)
{
  delay(20);
  LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS)); 
//Ausgänge
  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); 
//Ausgänge
  LCD_CONTROL &= ~(1<<LCD_EN);


  lcd_befehl(0b00100100);    //4Bit Modus mit extension Bit RE=1
  lcd_befehl(0b00001001);    //4 Zeilen
  lcd_befehl(0b00100000);    //extension Bit RE = 0
  lcd_befehl(0b00001110);    //LCD an
  lcd_befehl(0b00000001);    //LCD löschen+Home
  lcd_befehl(0b00000110);
}

int main(void)
{
  lcd_init();
  lcd_string("Hallo Welt!");

  return 0;
}
Gast #475221
Lesenswert?

Hallo,

void initLCD(void)
{
  LCD_DDR = 0xEF;   // alle Pins PortC auf  Ausgang schalten
  wait10ms(10);
  int i;
  for (i= 0;i<3;i++)
  {
    LCD_PORT = 3;      // 8Bit
    wait10ms(1);
  }
  LCD_PORT = 2;        // 4Bit
  wait10ms(1);
  LCD_PORT = 10;        // 2-Line Mode 5x8
  wait10ms(1);
  LCD_Enable();
  LCD_PORT = 15;    // Cursor =1, Blink =1, Disp = 1
  _delay_ms(1);
  LCD_Enable();
  LCD_PORT = 1;        // clear Disp
  LCD_Enable();
  LCD_PORT = 6;  //Kursor nach rechts wandernd, kein Display shift
  wait10ms(1);
}

ich vermisse hier meherere LCD_Enable(); und das setzen von RS und RW.
Im geänderten Code steht zwar dazu was drin aber die E-Pulse fehlen 
immernoch.
Timingdiagramm des KS0073 genauer ansehen. ;)

Das Display nimmt Deine anliegenden Daten erst mit dem H-Puls an Enable 
zur Kenntnis.

In Deiner

Gruß aus Berlin
Michael
Gast #475282
Lesenswert?

In der LCD_Command Funktion setze ich erst die Ausgänge dann das Enable 
Signal für 50 µs.
Vor der Initialisierung warte ich 100ms.Den Code von oben werde ich mal 
mit meinem vergleichen.

Danke Euch!
Gast #475328
Lesenswert?

Ich habe auch mal die Busy Funktion übernommen.
So sieht es jetzt aus:

// -------- LCD Funktionen ----------------------------
void initLCD(void) // Initialisierung des Displays |||4x20 Display ist 
ein 2 Zeilen 5*8 Dislpay!|||
{
  LCD_DDR = 0xFF;       // alle Pins PortC auf  Ausgang schalten
  wait10ms(100);
  LCD_setRS(0);
  LCD_setRW(0);
  LCD_setENB(0);

  LCD_PORT = 2;    // 4Bit
  _delay_ms(5);

  LCD_Command(40);  // 4 Bit
  LCD_Command(15);  // Cursor =1, Blink =1, Disp = 1
  LCD_Command(1);  // Display löschen
  LCD_Command(6);    //Kursor nach rechts wandernd, kein Display shift
  wait10ms(1);
}

void LCD_setRS(uint8_t Val)
{
  if (Val == 0)  LCD_PORT &= ~(1 << LCD_RS);
  if (Val == 1)  LCD_PORT |= (1 << LCD_RS);
}
void LCD_setRW(uint8_t Val)
{
  if (Val == 0) LCD_PORT &= ~(1 << LCD_RW);
  if (Val == 1) LCD_PORT |= (1 << LCD_RW);
}
void LCD_setENB(uint8_t Val)
{
  if (Val == 0)  LCD_PORT &= ~(1 << LCD_ENB);
  if (Val == 1)  LCD_PORT |= (1 << LCD_ENB);
}

void LCD_Enable(void)
{
  LCD_PORT |= (1<<LCD_ENB);        //Enable auf High
  _delay_us(40);             //40ms langer Impuls
  LCD_PORT &= ~(1<<LCD_ENB);       //Enable auf Low
}

void LCD_Clear(void)
{
        LCD_Command(0x01);
  _delay_ms(5);
}

void LCD_Out(char *text)
{
    while (*text)
    {
        LCD_Data(*text++);  //Zeichen ausgeben auf LCD
    }
}

void LCD_Data(char byte_high)
{
  LCD_busy();
  char text[] = "LCD_Data():";
  UART_Text_out(text,0);
  putch(byte_high);      // Ausgeben auf Uart für Debug!

  char byte_low = byte_high;    //Sichern für unteres Nibble
// Oberes Nibble zuerst ausgeben
  byte_high = byte_high>>4;    //Wert ins untere Nibble schieben.
  byte_high |= (1<<LCD_RS);      //RS setzen
  LCD_PORT = byte_high;      //oberes Nibbel des Befehls Ausgeben
  LCD_Enable();        //Enable Impuls
  putch(byte_high);      // Ausgeben auf Uart für Debug!
// Dann unteres Nibble
  byte_low &= 0x0f;      //oberes Nibble löschen
  byte_low |= (1<<LCD_RS);      //RS setzen
  LCD_PORT = byte_low;      //unteres Nibbel Ausgeben
  LCD_Enable();

  putch(byte_low);      // Ausgeben auf Uart für Debug!
  putch('\n');

  //_delay_us(50);
  _delay_ms(5);
  LCD_busy();
}

void LCD_Command(char byte_high)    //Pin0-Pin3 sind die Datenleitungen
{
  LCD_busy();
  putch(byte_high);    // Ausgeben auf UART für Debug!
  char byte_low = byte_high;    //Sichern für unteres Nibble
// Oberes Nibble zuerst ausgeben
  byte_high = byte_high>>4;  //Wert ins untere Nibble schieben.
  LCD_PORT = byte_high;    //oberes Nibbel des Befehls Ausgeben
  LCD_Enable();      //Enable Impuls
  putch(byte_high);    // Ausgeben auf UART für Debug!
// Dann unteres Nibble
  byte_low &= 0x0f;    //oberes Nibble löschen
  LCD_PORT = byte_low;    //unteres Nibbel Ausgeben
  LCD_Enable();
  putch(byte_low);    // Ausgeben auf Uart für Debug!
  //_delay_us(50);
  _delay_ms(5);
  LCD_busy();
}

void LCD_busy(void)
{
  unsigned char test=0;
  LCD_PORT &= ~(1<<LCD_RS);
  LCD_PORT |= (1<<LCD_RW);
  LCD_DDR &= ~((1<<LCD_D3)|(1<<LCD_D2)|(1<<LCD_D1)|(1<<LCD_D0)); 
//Eingang für BUSY FLAG
  while (1)
  {
    LCD_PORT|=(1<<LCD_ENB);
    asm("nop");
    asm("nop");
    if (!(LCD_BF & (1<<LCD_D3))) test = 1;
    LCD_PORT &= ~(1<<LCD_ENB);

    LCD_PORT |=(1<<LCD_ENB);
    asm("nop");
    asm("nop");
    LCD_PORT &= ~(1<<LCD_ENB);
    if (test) break;
  }
  LCD_DDR = 0xFF; //Ausgänge
}

Geht aber leider immer noch nicht. :(
Gast #475357
Lesenswert?

Hast du mal meinen Code 1:1 übernommen und die entsprechende Pinbelegung 
des LCDs angepasst?
Bei mir geht der CODE mit dem LCD von EA DIP204-4 von Electronic 
Assembly.
Hast du auch den Kontrast richtig eingestellt?
Welches LCD (Typ, Hersteller) hast du genau?
Funktioniert die UART-Ausgabe, oder bleibt er irgendwo bei der 
busy-Abfrage hängen?
Gast #475375
Lesenswert?

Hallo Peter,

deinen Code werde ich jetzt mal probieren. Bisher habe ich nur meinen 
angepasst.

Ich habe das Gleiche Display wie du.
Die UART-Ausgabe geht, er bleibt nur hängen, wenn ich das Display 
abziehe!
Habe eben nochmal die restlichen 4 Datenleitungen (0-3) über einen 1KO 
Widerstand auf Masse gelegt, nicht das da noch irgendwas rumspukt.Der 
Kontrast sollte OK sein, ich sehe ja manchmal Zeichen, wenn auch nicht 
die gewünschten. Wenn er falsch wäre, wäre doch entweder alles Schwarz, 
oder grün, oder nicht? Derzeit sehe ich allerdings garnichts mehr auf 
dem Display..

Sven
Gast #475384
Lesenswert?

Hab es so angepasst:

#include <avr/io.h>

//LCD-Steuerleitungen
#define LCD_CONTROL   PORTC
#define LCD_CONTROL_DIR DDRC
#define LCD_RS      5    //PortD.4
#define LCD_RW      6    //PortD.6
#define LCD_EN      7    //PortD.5

#define LCD_DATEN    PORTC
#define LCD_DATEN_DIR  DDRC
#define LCD_BF      PINC
#define LCD_D4      1     //Porta.4
#define LCD_D5      2     //Porta.5
#define LCD_D6      3     //Porta.6
#define LCD_D7      4     //Porta.7

//********************************************************************** 
***************
//Delay ca. 0.5*x ms bei 16 MHz
//********************************************************************** 
***************
void delay (unsigned int x)
{
  unsigned int a, y;
  for (a=0; a<x; a++)
  {
    for (y=0; y<1333; y++)
    {
      asm("nop");
    }
  }
}
//********************************************************************** 
***************
//LCD code
//********************************************************************** 
***************


void lcd_busy(void)
{
  unsigned char test=0;
  LCD_CONTROL &= ~(1<<LCD_RS);
  LCD_CONTROL |= (1<<LCD_RW);
  LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4));
//Eingang für BUSY FLAG
  while (1)
  {
    LCD_CONTROL|=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    if (!(LCD_BF & (1<<LCD_D7))) test = 1;
    LCD_CONTROL &= ~(1<<LCD_EN);


    LCD_CONTROL |=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    LCD_CONTROL &= ~(1<<LCD_EN);
    if (test) break;
  }

  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4));
//Ausgänge
}

void lcd_befehl(unsigned char befehl)
{

  LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW));
  LCD_DATEN = ((0xF0 & befehl)|(LCD_DATEN& 0x0F));
//PORTA = HIGH Nibble
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");

  LCD_CONTROL &= ~(1<<LCD_EN);        //High Nibble mit fallender Flanke 
übernehmen

  LCD_DATEN = ((0xF0 & (befehl<<4))|(LCD_DATEN& 0x0F));
//Low Nibble
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}


void lcd_char(unsigned char daten)
{
  LCD_CONTROL |=(1<<LCD_RS);          //Für Daten
  LCD_CONTROL &= ~(1<<LCD_RW);        //LCD soll lesen
  LCD_DATEN = ((0xF0 & daten)|(LCD_DATEN& 0x0F));
  LCD_CONTROL |= (1<<LCD_EN);          //Daten übernehmen
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);

  LCD_DATEN = ((0xF0 & (daten<<4))|(LCD_DATEN& 0x0F));
  LCD_CONTROL|= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}

void lcd_string (unsigned char *string)
{
  while (*string)
          lcd_char (*string++);
}


void lcd_init(void)
{
  delay(20);
  LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS));
//Ausgänge
  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4));
//Ausgänge
  LCD_CONTROL &= ~(1<<LCD_EN);


  lcd_befehl(36);    //4Bit Modus mit extension Bit RE=1
  lcd_befehl(9);    //4 Zeilen
  lcd_befehl(32);    //extension Bit RE = 0
  lcd_befehl(14);    //LCD an
  lcd_befehl(1);    //LCD löschen+Home
  lcd_befehl(6);
}

int main(void)
{
  lcd_init();
  lcd_string("Hallo Welt!");

  return 0;
}

Aber Das Display bleibt leer!

Schade. Was mach ich nur falsch?
Gast #475411
Lesenswert?

Du musst die Reihenfolge einhalten:

FALSCH:
#define LCD_D4      1     //Porta.4
#define LCD_D5      2     //Porta.5
#define LCD_D6      3     //Porta.6
#define LCD_D7      4     //Porta.7

Richtig:
#define LCD_D4      4     //Porta.4
#define LCD_D5      5     //Porta.5
#define LCD_D6      6     //Porta.6
#define LCD_D7      7    //Porta.7

sonst funktioniert die Aufteilung der Nibbels mit meinem Code nicht.

Mit AVR-Studio kannst du auch leicht simulieren, ob die richtigen 
Signale am Port ausgegeben werden.
Gast #475487
Lesenswert?

so müsste es jetzt auch mit deiner Pinbelegung funktionieren

#include <avr/io.h>

//LCD-Steuerleitungen
#define LCD_CONTROL   PORTC
#define LCD_CONTROL_DIR DDRC
#define LCD_RS      5    //PortD.4
#define LCD_RW      6    //PortD.6
#define LCD_EN      7    //PortD.5

//LCD-Datenport: Reihenfolge des High Nibbles (4-7) muss eingehalten 
werden,
//Port kann getauscht werden:
#define LCD_DATEN    PORTC
#define LCD_DATEN_DIR  DDRC
#define LCD_BF      PINC
#define LCD_D4      1     //Porta.4
#define LCD_D5      2     //Porta.5
#define LCD_D6      3      //Porta.6
#define LCD_D7      4     //Porta.7

//********************************************************************** 
***************
//Delay ca. 0.5*x ms bei 16 MHz
//********************************************************************** 
***************
void delay (unsigned int x)
{
  unsigned int a, y;
  for (a=0; a<x; a++)
  {
    for (y=0; y<1333; y++)
    {
      asm("nop");
    }
  }
}
//********************************************************************** 
***************
//LCD code
//********************************************************************** 
***************


void lcd_busy(void)
{
  unsigned char test=0;
  LCD_CONTROL &= ~(1<<LCD_RS);
  LCD_CONTROL |= (1<<LCD_RW);
  LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); 
//Eingang für BUSY FLAG
  while (1)
  {
    LCD_CONTROL|=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    if (!(LCD_BF & (1<<LCD_D7))) test = 1;
    LCD_CONTROL &= ~(1<<LCD_EN);


    LCD_CONTROL |=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    LCD_CONTROL &= ~(1<<LCD_EN);
    if (test) break;
  }

  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); 
//Ausgänge
}

void lcd_befehl(unsigned char befehl)
{

  LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW));
  LCD_DATEN = (0b11110000 & befehl)>>3|(LCD_DATEN& 0b11100001);
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");

  LCD_CONTROL &= ~(1<<LCD_EN);        //High Nibble mit fallender Flanke 
übernehmen

  LCD_DATEN = ((0b11110000 & (befehl<<4))>>3)|(LCD_DATEN& 0b11100001); 
//Low Nibble
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}


void lcd_char(unsigned char daten)
{
  LCD_CONTROL |=(1<<LCD_RS);          //Für Daten
  LCD_CONTROL &= ~(1<<LCD_RW);        //LCD soll lesen
  LCD_DATEN = (0b11110000 & daten)>>3|(LCD_DATEN& 0b11100001);
  LCD_CONTROL |= (1<<LCD_EN);          //Daten übernehmen
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);

  LCD_DATEN = ((0b11110000 & (daten<<4))>>3)|(LCD_DATEN& 0b11100001);
  LCD_CONTROL|= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}

void lcd_string (unsigned char *string)
{
  while (*string)
          lcd_char (*string++);
}


void lcd_init(void)
{

  LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS)); 
//Ausgänge
  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); 
//Ausgänge
  LCD_CONTROL &= ~(1<<LCD_EN);
  delay(20);


  lcd_befehl(0b00100100);    //4Bit Modus mit extension Bit RE=1
  lcd_befehl(0b00001001);    //4 Zeilen
  lcd_befehl(0b00100000);    //extension Bit RE = 0
  lcd_befehl(0b00001110);    //LCD an
  lcd_befehl(0b00000001);    //LCD löschen+Home
  lcd_befehl(0b00000110);
}

int main(void)
{
  lcd_init();
  lcd_string("Hallo Welt!");

  return 0;
}
Gast #475756
Lesenswert?

Nochmal zur HW,muss ich Reset noch irgendwie anschließen?
Die Kontrastspannung kann ich (ohne LCD) zwischen 0 un d1,4V einstellen, 
wenn ich das LCD anschließe liegen an dem PIN -0.13V an.D4-D7 hab ich 
direkt an die PINS des µC angeschlossen, D0-D3 über 1KOhm auf GND. Passt 
das soweit?
Gast #475769
Lesenswert?

Sag mir mal genau deine komplette Pinbelegung.
Ich ändere dann das Programm ab.
Das obige modifizierte Programm Funktioniert nur mit dieser Reihenfolge:

#define LCD_DATEN    PORTC
#define LCD_DATEN_DIR  DDRC
#define LCD_BF      PINC
#define LCD_D4      1     //Porta.4
#define LCD_D5      2     //Porta.5
#define LCD_D6      3      //Porta.6
#define LCD_D7      4    //Porta.7

kein Wunder das es bei dir nicht geht.
Sonst müsste alles OK sein!
Gast #475843
Lesenswert?

So sieht meine Pinbelegung aus:

#define LCD_DDR  DDRC
#define LCD_PORT PORTC
#define LCD_PIN  PINC

#define LCD_D0   PINC0
#define LCD_D1   PINC1
#define LCD_D2   PINC2
#define LCD_D3   PINC3
#define LCD_RS   PINC4
#define LCD_RW   PINC5
#define LCD_ENB  PINC6
Gast #475873
Lesenswert?

Ich denke du hast anstatt D0-D3 D4-D7 gemeint.
So sollt es jetzt eigentlich Funktionieren.
Du kannst auch noch ein paar nops mehr einfügen.
Ich hatte auch schon mal das Problem als ich das LCD an langen Leitungen 
hatte, waren die Pegelwechsel zu schnell.

#include <avr/io.h>

//LCD-Steuerleitungen
#define LCD_CONTROL   PORTC
#define LCD_CONTROL_DIR DDRC
#define LCD_RS      4    //PortD.4
#define LCD_RW      5    //PortD.6
#define LCD_EN      6    //PortD.5

//LCD-Datenport: Reihenfolge des High Nibbles (4-7) muss eingehalten 
werden,
//Port kann getauscht werden:
#define LCD_DATEN    PORTC
#define LCD_DATEN_DIR  DDRC
#define LCD_BF      PINC
#define LCD_D4      0     //Porta.4
#define LCD_D5      1     //Porta.5
#define LCD_D6      2      //Porta.6
#define LCD_D7      3     //Porta.7

//********************************************************************** 
***************
//Delay ca. 0.5*x ms bei 16 MHz
//********************************************************************** 
***************
void delay (unsigned int x)
{
  unsigned int a, y;
  for (a=0; a<x; a++)
  {
    for (y=0; y<1333; y++)
    {
      asm("nop");
    }
  }
}
//********************************************************************** 
***************
//LCD code
//********************************************************************** 
***************


void lcd_busy(void)
{
  unsigned char test=0;
  LCD_CONTROL &= ~(1<<LCD_RS);
  LCD_CONTROL |= (1<<LCD_RW);
  LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); 
//Eingang für BUSY FLAG
  while (1)
  {
    LCD_CONTROL|=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    if (!(LCD_BF & (1<<LCD_D7))) test = 1;
    LCD_CONTROL &= ~(1<<LCD_EN);


    LCD_CONTROL |=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    LCD_CONTROL &= ~(1<<LCD_EN);
    if (test) break;
  }

  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); 
//Ausgänge
}

void lcd_befehl(unsigned char befehl)
{

  LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW));
  LCD_DATEN = (0b11110000 & befehl)>>4|(LCD_DATEN& 0b11110000);
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");

  LCD_CONTROL &= ~(1<<LCD_EN);        //High Nibble mit fallender Flanke 
übernehmen

  LCD_DATEN = ((0b11110000 & (befehl<<4))>>4)|(LCD_DATEN& 0b11110000); 
//Low Nibble
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}


void lcd_char(unsigned char daten)
{
  LCD_CONTROL |=(1<<LCD_RS);          //Für Daten
  LCD_CONTROL &= ~(1<<LCD_RW);        //LCD soll lesen
  LCD_DATEN = (0b11110000 & daten)>>4|(LCD_DATEN& 0b11110000);
  LCD_CONTROL |= (1<<LCD_EN);          //Daten übernehmen
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);

  LCD_DATEN = ((0b11110000 & (daten<<4))>>4)|(LCD_DATEN& 0b11110000);
  LCD_CONTROL|= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}

void lcd_string (unsigned char *string)
{
  while (*string)
          lcd_char (*string++);
}


void lcd_init(void)
{

  LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS)); 
//Ausgänge
  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); 
//Ausgänge
  LCD_CONTROL &= ~(1<<LCD_EN);
  delay(20);


  lcd_befehl(0b00100100);    //4Bit Modus mit extension Bit RE=1
  lcd_befehl(0b00001001);    //4 Zeilen
  lcd_befehl(0b00100000);    //extension Bit RE = 0
  lcd_befehl(0b00001110);    //LCD an
  lcd_befehl(0b00000001);    //LCD löschen+Home
  lcd_befehl(0b00000110);
}

int main(void)
{
  lcd_init();
  lcd_char(0b10100011);
  lcd_string("Hallo Welt!");

  return 0;
}
Gast #475925
Lesenswert?

Ich musste es noch so abändern, weil mein Compiler keine Zahlen im 
Binärformat mag..

#include <avr/io.h>

//LCD-Steuerleitungen
#define LCD_CONTROL   PORTC
#define LCD_CONTROL_DIR DDRC
#define LCD_RS      4    //PortD.4
#define LCD_RW      5    //PortD.6
#define LCD_EN      6    //PortD.5

//LCD-Datenport: Reihenfolge des High Nibbles (4-7) muss eingehalten

//Port kann getauscht werden:
#define LCD_DATEN    PORTC
#define LCD_DATEN_DIR  DDRC
#define LCD_BF      PINC
#define LCD_D4      0     //Porta.4
#define LCD_D5      1     //Porta.5
#define LCD_D6      2      //Porta.6
#define LCD_D7      3     //Porta.7

//********************************************************************** 
***************
//Delay ca. 0.5*x ms bei 16 MHz
//********************************************************************** 
***************
void delay (unsigned int x)
{
  unsigned int a, y;
  for (a=0; a<x; a++)
  {
    for (y=0; y<1333; y++)
    {
      asm("nop");
    }
  }
}
//********************************************************************** 
***************
//LCD code
//********************************************************************** 
***************


void lcd_busy(void)
{
  unsigned char test=0;
  LCD_CONTROL &= ~(1<<LCD_RS);
  LCD_CONTROL |= (1<<LCD_RW);
  LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4));
//Eingang für BUSY FLAG
  while (1)
  {
    LCD_CONTROL|=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    if (!(LCD_BF & (1<<LCD_D7))) test = 1;
    LCD_CONTROL &= ~(1<<LCD_EN);


    LCD_CONTROL |=(1<<LCD_EN);
    asm("nop");
    asm("nop");
    LCD_CONTROL &= ~(1<<LCD_EN);
    if (test) break;
  }

  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4));
//Ausgänge
}

void lcd_befehl(unsigned char befehl)
{

  LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW));
  LCD_DATEN = (0xF0 & befehl)>>4|(LCD_DATEN& 0xF0);
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");

  LCD_CONTROL &= ~(1<<LCD_EN);        //High Nibble mit fallender Flanke

  LCD_DATEN = ((0xF0 & (befehl<<4))>>4)|(LCD_DATEN& 0xF0);
//Low Nibble
  LCD_CONTROL |= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}


void lcd_char(unsigned char daten)
{
  LCD_CONTROL |=(1<<LCD_RS);          //Für Daten
  LCD_CONTROL &= ~(1<<LCD_RW);        //LCD soll lesen
  LCD_DATEN = (0xF0 & daten)>>4|(LCD_DATEN& 0xF0);
  LCD_CONTROL |= (1<<LCD_EN);          //Daten übernehmen
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);

  LCD_DATEN = ((0xF0 & (daten<<4))>>4)|(LCD_DATEN& 0xF0);
  LCD_CONTROL|= (1<<LCD_EN);
  asm("nop");
  LCD_CONTROL &= ~(1<<LCD_EN);
  lcd_busy();

}

void lcd_string (unsigned char *string)
{
  while (*string)
          lcd_char (*string++);
}


void lcd_init(void)
{

  LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS));
//Ausgänge
  LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4));
//Ausgänge
  LCD_CONTROL &= ~(1<<LCD_EN);
  delay(20);

/*
  lcd_befehl(0b00100100);    //4Bit Modus mit extension Bit RE=1
  lcd_befehl(0b00001001);    //4 Zeilen
  lcd_befehl(0b00100000);    //extension Bit RE = 0
  lcd_befehl(0b00001110);    //LCD an
  lcd_befehl(0b00000001);    //LCD löschen+Home
  lcd_befehl(0b00000110);*/

  lcd_befehl(36);    //4Bit Modus mit extension Bit RE=1
  lcd_befehl(9);    //4 Zeilen
  lcd_befehl(32);    //extension Bit RE = 0
  lcd_befehl(14);    //LCD an
  lcd_befehl(1);    //LCD löschen+Home
  lcd_befehl(6);
}

int main(void)
{
  lcd_init();
 // lcd_char(0b10100011);
  lcd_char(0xA3);
  lcd_string("Hallo Welt!");

  return 0;
}

Es geht! Der Text erscheint tatsächlich! Hab schon nicht mehr daran 
geglaubt.!

Vielen Dank Peter, ohne deine Hilfe hätte ich das aufgegeben, so lang 
ich mich nun damit rumgeärgert habe.

Mal sehen, wo der Fehler in meinem Code ist.

Servus, Sven!
Gast #477572
Lesenswert?

Das hier war der Fehler in meinem Programm:

void LCD_Enable(void)
{
  LCD_PORT |= (1<<LCD_ENB);      //Enable auf High
  delay_us(60);           //60ms langer Impuls
  LCD_PORT &= ~(1<<LCD_ENB);     //Enable auf Low
}


Und so geht es:
void LCD_Enable(void)
{
  LCD_PORT |= (1<<LCD_ENB);      //Enable auf High
  asm("nop");
  LCD_PORT &= ~(1<<LCD_ENB);     //Enable auf Low
}

So ganz verstanden hab ich es aber noch nicht.
#477965
Lesenswert?

Hallo,

Ich habe eine ganz ähnliches Problem.

Bei meinem Display werden nach dem initalisieren ein Text in alle 4 
Zeilen geschrieben.
Dieser erscheint auch. Aber nur Kurz und mit wenig Kontrast.
ca. 2 Sec. später löscht er sich wieder und nur Zeile 1 und Zeile 3 
bleiben sichtbar(mit vollem Kontrast).

Dann bewegt sich der Cursor?? Im Anschluss wird der Text gelöscht und 
der Cursor erscheint blinkend. 1 sec später erscheint wieder Zeile 1 und 
3.
Mir kommt das ganze vor als ob ich in einer Schleife hängen würde. Aber 
weit und breit hab ich keine Schleife reinprogrammiert.

Hat jemand von euch eine ähnliche Erfahrung? An was könnte das nich 
liegen?Zu wenig Strom am Display? Display Treiber Schrott?

Es handelt sich um den KS0066 als Display Treiber Chip(Reichelt LCD 204B 
LED)
(4bit Modus, Hintergrundbeleuchtung nicht angeschlossen)


Gruß Uli
Gast #479973
Lesenswert?

Hab auch so ein ähnliches problem...
das display schaltet sich für ca. 2-3 sekunden an und geht dann wieder 
aus! Hab keine ahnung woran das liegen könnte....

das display ist ein lcd1602A und liegt an portc.

quellcode befindet sich im anhang...
Angehängte Dateien:
Gast #480153
Lesenswert?

@ Uli

Eigene Diskussion aufmachen und Projektfiles mit Sourcecode, Makefile 
etc. bereitstellen. Link zum Datenblatt des LCD ist auch hilfreich. 
Schaltplan kann auch helfen. Dann hoffen, dass die Problembeschreibung 
so gut ist, dass jemand auf das Problem anspringt.

@ Matze

Meinst du dieses LC-Display LCD-1602A von Crystalfontz?
http://www.datasheet4u.com/html/L/C/D/LCD-1602A_CA.pdf.html

>  PORTC = 0b00100000;      //4 Bit Mode setzen

Bist du sicher, dass da nicht 3x was zum LCD geschickt werden muss, 
bevor du so in den 4-Bit Modus wechseln kannst (vgl. Seite 17 im PDF 
oben)?

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