Forum: Compiler & IDEs LCD Probleme


von jochen (Gast)


Lesenswert?

Hallo Zuammen,

ich hab mal versuch das ASM Beispiel aus dem Tutorial zum ansteuern
eines HD44780 in C zu portieren.
Leider war dieses Vorhaben nich von Erfolg gekrönt.
Anstat dem erwarteten Hallo auf dem Display sehe ich nur einen
blinkenden Cursor.
Vielleicht könnt Ihr euch ja mal den Code anschauen und mir sagen wo
der Fehler ist.

Danke schon mal im Vorraus, der Jochen

#include <avr/io.h>

#define PORT  PORTC
#define DDR    DDRC
#define PIN    PINC
#define E_PIN  5
#define RS_PIN  4
#define BYTE  char

void delay50us(void)
{
  asm("    ldi  r16, 0x42     \n"
      "1:                     \n"
      "    dec  r16           \n"
      "    brne 1b            \n"
      ::);
}

void delay5ms(void)
{
  asm("    ldi  r16, 0x21     \n"
      "1:                     \n"
      "    ldi  r17, 0xC9     \n"
      "2:                     \n"
      "    dec  r17           \n"
      "    brne 2b            \n"
      "    dec  r16           \n"
      "    brne 1b            \n"
      ::);
}

void lcd_enable(void)
{
  outp(0x00, PORT);          // all low
  outp(0xff, DDR);

  sbi(PORT, E_PIN);
  asm("nop\n\tnop\n\tnop"::);
  cbi(PORT, E_PIN);
}

void send_command(BYTE data)
{
  outp(0x00, PORT);          // all low
  outp(0xff, DDR);

  BYTE high_nibble, low_nibble;

  outp(0xf0, DDR);
  outp(0x1f, PORT);

  //High und Lownibble ermitteln
  high_nibble = data>>4;
  low_nibble  = data;

  //unnötige daten auf null setzten
  high_nibble = 0x0f;
  low_nibble  = 0x0f;

    //High Nibble ausgeben
  outp(high_nibble, PORT);
  lcd_enable();

  //Low Nibble ausgeben
  outp(low_nibble, PORT);
  lcd_enable();
}

void lcd_init(void)
{
  outp(0x00, PORT);          // all low
  outp(0xff, DDR);

  // 50 x 5 ms warten
  int i;
  for(i=0; i<50; i++)
    delay5ms();

  //Drei mal 0x03 zum initialisieren schicken
  outp(0x03, PORT);
  for(i=0; i<3; i++)
  {
    lcd_enable();
    delay5ms();
  }

  //4-BIT Modus setzen
  outp(0x02, PORT);
  lcd_enable();
  delay5ms();

  send_command(0x28);

  send_command(0x0c);

  send_command(0x04);
}

void lcd_clear(void)
{
  send_command(0x01);
  delay5ms();
}

void send_data(BYTE data)
{
  outp(0x00, PORT);          // all low
  outp(0xff, DDR);

  BYTE high_nibble, low_nibble;

  outp(0xf0, DDR);
  outp(0x1f, PORT);

  //High und Lownibble ermitteln
  high_nibble = data>>4;
  low_nibble  = data;

  //unnötige daten auf null setzten
  high_nibble = 0x0f;
  low_nibble  = 0x0f;

  //RS-Bit setzten
  high_nibble |= 1<<RS_PIN;
  low_nibble  |= 1<<RS_PIN;

    //High Nibble ausgeben
  outp(high_nibble, PORT);
  lcd_enable();

  //Low Nibble ausgeben
  outp(low_nibble, PORT);
  lcd_enable();
}

int main(void)
{
  lcd_init();
  lcd_clear();
  send_data("H");
  send_data("a");
  send_data("l");
  send_data("l");
  send_data("o");
    return 0;
}

von Alex (Gast)


Lesenswert?

vielleicht hilft dir der link weiter:
http://jump.to/fleury

von jochen (Gast)


Lesenswert?

Danke, für den Link. Ich kenn die Seite. Das Problem ist aber das dort
die R/W Leitung benutzt wird die ich bei mir auf GND gelegt habe.
Deshalb wollte ich eben die ASM Routine von hier in C umschreiben.

Vielleicht hat ja noch jemand ein Tipp was das Problem sein könnte.
 Ein Fehler den ich schon gefunden hab ist der folgende:

//unnötige daten auf null setzten
  high_nibble = 0x0f;
  low_nibble  = 0x0f;

muss natürlich so aussehen:

//unnötige daten auf null setzten
  high_nibble &= 0x0f;
  low_nibble  &= 0x0f;

Hat sonst noch jemand Fehleer entdeckt?

Der Jochen

von Alex (Gast)


Lesenswert?

Auf der letzten Seite in der "Codesammlung" ist noch ein
Codebeispiel... wirst du wahrscheinlich aber auch schon kenne.

Ich bin auch noch auf der Suche nach einem gutem Beispiel oder Tutorial
für LCD mit C und nicht Assembler in C.

von jochen (Gast)


Lesenswert?

Ich hab schon einige Beispiele gefunden, aber immer mit der R/W Leitung.
Deshalb wollte ich ja auch den ASM-Code von dem Tutorial hier 1:1 in C
umsetzen.
Ist mir aber im Moment noch nicht gelungen.

Der Jochen

von Alex (Gast)


Lesenswert?

Die ganzen codes aus der sammlung kenne ich - jeden einzelnen link hier
angeklickt - Meistens in Assembler und eins war in C++...

könntes du vielleicht mal deine links posten, die du für LCD steuerung
gut findest?

von jochen (Gast)


Lesenswert?

Ich denke, das ist so der Standart Link:
http://www.mysunrise.ch/users/pfleury/avr-software.html#libs

Hier ist halt das Problem das er die R/W Leitung verwendet um das
BussyFlag zu lesen. Ich hab das bei mir halt auf GND, darum müsste ich
die ganzen Abfragen nach dem BussyFlag in delays umwandel.

Mir wäre es auch ganz lieb wenn ich meinen eigenen Code zum laufen
bekommen würde, dann weis ich nämlich das ich verstanden habe was ich
da so mache.

Kann mir vielleicht einer Sagen wofür folgeder Code in der ASM Variante
der LCD ansteuerung ist?

ldi temp1, LOW(RAMEND)      ; LOW-Byte der obersten RAM-Adresse
           out SPL, temp1
           ldi temp1, HIGH(RAMEND)     ; HIGH-Byte der obersten
RAM-Adresse
           out SPH, temp1

Danke, der Jochen

von Joerg Wunsch (Gast)


Lesenswert?

> Danke, für den Link. Ich kenn die Seite. Das Problem ist aber das
> dort die R/W Leitung benutzt wird die ich bei mir auf GND gelegt
> habe.

Typischer Fall von »selbst schuld«.  Sowas macht man nicht, zumindest
nicht ohne Not.  (»Not« wäre es, wenn Du in einer Massenfertigung
durch die eingesparte Leitung den nächstkleineren Controller nehmen
kannst, oder wenn Du aus irgendwelchen Gründen gezwungen bist, ein
Display zu nehmen, das R/W nicht herausführt.)

Wenn Du das busy-Flag nämlich nicht mehr lesen kannst, mußt Du oftmals
ein Vielfaches dessen an Wartezeit einplanen, was tatsächlich
notwendig wäre, um auf der sicheren Seite zu liegen.

Damit ist eigentlich auch schon beschrieben, wie man ein HD44780
Display ansteuert, wenn man R/W nicht zur Verfügung hat: jeder Test
des busy-Flags muß durch die im Datenblatt vorgeschriebenen
Verzögerungen ersetzt werden.

> Kann mir vielleicht einer Sagen wofür folgeder Code in der ASM
> Variante der LCD ansteuerung ist?

> ldi temp1, LOW(RAMEND)      ; LOW-Byte der obersten RAM-Adresse
>            out SPL, temp1
>            ldi temp1, HIGH(RAMEND)     ; HIGH-Byte der obersten
RAM-Adresse
>            out SPH, temp1

Nun, ist das wirklich so schwer zu raten?  Hast Du denn überhaupt eine
Vorstellung von der Wirkungsweise des Controllers?

Damit wird der Stackpointer auf das obere RAM-Ende initialisiert.
Irgendwer hier hat Dir auch schon mal beschrieben, daß Dein Controller
gar nicht wirklich ein SPH-Register hat, da er nur 256 Byte RAM
besitzt, damit kannst Du diesen Teil klemmen.

Außerdem ist das Ganze natürlich nur einmal pro Applikation nötig.
Wenn Du die Applikation im Ganzen in C schreibst, erledigt das das
C-Laufzeitsystem für Dich, Du mußt Dich da nicht mehr drum kümmern,
egal ob Du dann die LCD-Bibliothek in Assemblercode einbinden willst
oder nicht.

Allerdings beschleicht mich das Gefühl, daß Du Dich erstmal mit den
Grundlagen der Controller vertraut machen solltest, um diese von Grund
auf zu verstehen.  LCD und UART sind da leider schon so komplex, daß
sie keinen guten Einstieg bieten.  Fang mal wirklich mit dem
einfachsten an, das typische ,,Hello world!'' Programm der
Microcontroller ist wirklich nur die blinkende Leuchtdiode (oder die
auf- und abschwellende mit einem PWM, wie im demo.c der avr-libc).

Wenn Du bei diesem verstanden hast, wie's geht, einschließlich des
Timings (Deine LED also wirklich im von Dir gewünschten Takt blinkt,
und zwar durch Berechnung der Zeiten, nicht etwa durch trial&error
Verzögerungsschleifen, bei denen Du die Schleifenzähler empirisch
ermittelst), dann kannst Du weiter machen.  Als nächsten Schritt würde
ich sehen, daß man sich einen simplen RS232-Treiber an die UART-Pins
anschließt (MAX232 oder Äquivalent), auf dem PC ein einfaches
Terminalprogramm, und ein paar Zeichen ausgibt.  Wenn das
funktioniert, hast Du zumindest mal eine simple Debug-Möglichkeit.

Erst dann würde ich mich dran machen, eine LCD anzuschließen.  Den ADC
kannst Du ggf. ja schon zuvor mal ausprobieren, die Ausgaben können ja
auch anfangs über die UART gehen.

Beispielcode findest Du im Netz ausreichend, aber wenn Du ihn nicht
verstehen kannst, nützt Dir das alles überhaupt nichts.

von Jochen (Gast)


Lesenswert?

Ich muss Dir insoweit REcht geben das ich die Funktionen des atmega8
nicht alle im Detail kenne.
Allerdings ist es auchnicht so das ich keinen Plan von uC im
allegmeinen habe.
Nun muß ich noch etwas zu den "Lernmethoden" sagen. Mag sein das es
für Dich der richtige Weg ist alles von Grund auf zu machen und dabei
zu lernen. Ich habe für mich jedoch die Erfahrung gemacht das ich
Sachen besser begreife wenn ich etwas hab das funktioniert und dan step
by step mir anschaue wie es geht.
Ich denke gnaz einfach jeder hat seinen eigen Lernstiel.

Nun noch etwas zu dem Display:
Ich hab mittlerweile die R/S-Leitung angeschlossen und alles tut
einwandfrei. Auch hab ich es zuvor geschaft durch ersetzen der BusyFlag
Abfrage durch Delays das Display zum laufen zu bekommen.

Das ich moch viel lernen muss das weis ich auch selber. Aber auf einem
langen Weg zum behersche des ARs ist es auch immer wieder schön mal ein
Erfolgserlebnis zu haben.

BTW: Bei meinem letzten Problem mit dem UART hat mir Dein Tipp ja auch
weiter geholfen und ich konnte das Problem lösen.

So, einen schönen Abend noch und Danke, der Jochen

P.S. PWM muss ich mir allerding auch noch ansehen.

von Joerg Wunsch (Gast)


Lesenswert?

> Aber auf einem langen Weg zum behersche des ARs ist es auch immer
> wieder schön mal ein Erfolgserlebnis zu haben.

Ja, daher ja mein Vorschlag, das schrittweise anzugehen.  Aber klar,
wenn Du für Dich andere Schritte bevorzugt, nur zu!  Hat ja offenbar
nun auch funktioniert.

> PWM muss ich mir allerding auch noch ansehen.

Nun, siehe demo.c, ist bei avr-libc dabei und wird auch von WinAVR mit
installiert.  Die Doku enthält einiges an Kommentaren dazu.  Die Idee
dafür ist übrigens nicht von mir sondern von Rich Neswold.  Er hatte
vor Jahren mal eine separate Doku und ein Einsteigerdokument für
AVR-GCC & Co. geschrieben und dort die Idee dieses Demo-Projektes drin
gehabt, war aber selbst nicht zur Realisierung gekommen.

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.