Forum: Compiler & IDEs LCD KS0073 am AVRATMega128


von Sven (Gast)


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!

von Sven (Gast)


Lesenswert?

noch zur Info:

void LCD_Enable(void)
{
  LCD_PORT |= (1<<LCD_ENB);
  _delay_us(50);
  LCD_PORT &= ~(1<<LCD_ENB);
}

von Stefan (Gast)


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?

von Sven (Gast)


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!

von Sven (Gast)


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!

von Sven (Gast)


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);
}

von Sven (Gast)


Lesenswert?

war noch ein Bug drin muss so sein, sorry:
byte_low &= 0x0f;      //oberes Nibble löschen

von Peter (Gast)


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;
}

von vorbeigeschlendert (Gast)


Lesenswert?

@Sven
wie viel Zeit läßt du dem Display nach dem PowerUp? AFAIK sollte man dem 
schon ein bisschen Bedenkzeit lassen ehe man es mit Daten bombadiert...

von Michael U. (Gast)


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

von Sven (Gast)


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!

von Sven (Gast)


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. :(

von Peter (Gast)


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?

von Sven (Gast)


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

von Sven (Gast)


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?

von Peter (Gast)


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.

von Sven (Gast)


Lesenswert?

Ach stimmt natürlich. Aber dann müsste ich es ja umlöten.
AVRStudio hab ich leider nicht.
Denkst du denn ich habe einen Fehler in meinem Code (oben)?

von Peter (Gast)


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;
}

von Sven (Gast)


Lesenswert?

Danke für die Hilfe!

Leider bleibt das Display leer. Werde nochmal alles durchmessen, 
vielleicht ist was abgegangen.

Servus
Sven

von Sven (Gast)


Lesenswert?

Hallo,

das muss so sein:
#define LCD_RS      4    //PortD.4
#define LCD_RW      5    //PortD.6
#define LCD_EN      6    //PortD.5
aber ansonsten ist die HW OK! Aber das Display ist leider immer noch 
leer.

von Sven (Gast)


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?

von Peter (Gast)


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!

von Sven (Gast)


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

von Peter (Gast)


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;
}

von Sven (Gast)


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!

von Sven (Gast)


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.

von Ulrich S. (uli)


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

von Matze (Gast)


Angehängte Dateien:

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...

von Uli Spizig (Gast)


Lesenswert?

Meine Vermutung:

Das LCD bekommt über die Drähtchen zu wenig Strom. Und dann macht der 
Treiberbaustein was er will

Gruß

Uli

von Stefan (Gast)


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)?

von Matze (Gast)


Lesenswert?

Ja es muß dreimal gesendet werden....hatte nur ein datenblatt das halb 
englisch halb chineschisch war. da infos rauszuziehen ist schlecht...
vielen dank für die hilfe....

mfg matze

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.