Forum: Mikrocontroller und Digitale Elektronik LCD ansteuern, fragen zu tutorial in assembler


von Oliver D. (highspeed-oliver)


Lesenswert?

Nabend,

also, ich habe mir nun bei pollin ein LCD NAN YA LMK62R gekauft.
Ich habe es an meinen AT89S52 angeschlossen.
Wenn ich Vcc anlege, dann erscheint der obere Balken in schwarz.
Es scheint also schonmal anzugehen ;)

So, nun bin ich dabei zu verstehen, wie man das Display ansteuert.
 Das man, wenn man im 4 bit modus arbeitet, die 8 bit aufteilen und dann 
in 2 nibbles senden muss habe ich wohl verstanden. Dafür setze ich die 
ausgänge auf den wert den ich gern hätte und dann einmal kurz E=1 kurz 
warten und dann E=0.

Soweit so gut.
Um allerdings den rest zu vestehen, müsste ich wohl einigermaßen 
assembler können...denn das AVR LCD tutorial nutzt diese sprache.
Ich würde es allerdings gern in C machen.

Gibts dafür eine gute Seite? Unter den weblinks find ich leider nix.

von Falk B. (falk)


Lesenswert?

@ Oliver D. (highspeed-oliver)

>assembler können...denn das AVR LCD tutorial nutzt diese sprache.
>Ich würde es allerdings gern in C machen.

Gibts doch auch alles.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#LCD-Ansteuerung

MfG
Falk

von Oliver D. (highspeed-oliver)


Lesenswert?

Ah ich glaube bei sprut.de bin ich fündig geworden :)

von Oliver D. (highspeed-oliver)


Lesenswert?

Oh cool.

Ich hatte bei artikel suche LCD eingetippt. In LCD bin ich dann unten 
auf AVR LCD gegangen...

Wer suchet der findet ;)

von Hannes L. (hannes)


Lesenswert?


von Oliver D. (highspeed-oliver)


Lesenswert?

Hmm, bei dem AVR GCC tutorial ist es natürlich für den AVR...somit 
müsste ich mich überall durchwursten.
Ich glaube da ist es schlau mit Anleitung erstmal selber zu 
programmieren.
Das AVR GCC tut ist für meine C kenntnisse ziehmlich riesig.

von Falk B. (falk)


Lesenswert?

@ Oliver D. (highspeed-oliver)

>Hmm, bei dem AVR GCC tutorial ist es natürlich für den AVR...somit
>müsste ich mich überall durchwursten.

????
Es werden lediglich schreibende Portzugriffe gemacht. Der Rest ist 
Standard-C. Das sollte in Null Komma Nix an den 89er anpassbar sein.

>Das AVR GCC tut ist für meine C kenntnisse ziehmlich riesig.

Du braucht nicht mal einen Bruchteil.

MfG
Falk

von Oliver D. (highspeed-oliver)


Lesenswert?

Mag sein, dass ich nur einen bruchteil brauche....da ich aber noch 
garkeine ahnung habe und auch niemanden der es mir am pc erklären kann, 
ist das schon eine kleine herausforderung.

von Oliver D. (highspeed-oliver)


Lesenswert?

Hmm, wenn ich das AVR GCC tutorial an meinen at versuche anzupassen, 
kriege ich ooohne ende fehler....

z.B. void set_cursor(uint8_t x, uint8_t y);

das kommt in die lcd_routines.h  Als fehler erhalte ich Invalid 
parameter declaration.

von Oliver D. (highspeed-oliver)


Lesenswert?

Was ist mit

#define LCD_DDR

gemeint?

von Falk B. (falk)


Lesenswert?

@ Oliver D. (highspeed-oliver)

>z.B. void set_cursor(uint8_t x, uint8_t y);

>das kommt in die lcd_routines.h  Als fehler erhalte ich Invalid
>parameter declaration.

Da fehlt wahrscheinlich

#include <stdint.h>

>Was ist mit
>#define LCD_DDR
>gemeint?

Das ist das Data Direction Register, welches festlegt, ob ein Bit eines 
Ports Ein- oder Ausgang ist.

MfG
Falk

von Oliver D. (highspeed-oliver)


Lesenswert?

Der Fehler bleibt bestehen.
Invalid parameter declaration.

Das Data direction register sitzt doch im avr nicht wahr?
Sowas hat mein AT89S52 garnicht.
Meine ich.... Ich kann einfach einen portpin auf masse ziehen um einen 
zweiten zustand zu haben. Vorher schreibe ich einfach eine 1 rein. Der 
Taster z.b. zieht die 1 dann auf masse.

von Condi (Gast)


Lesenswert?

Ja da hast du Recht, du musst nur die Daten ausgeben ein DDR hat der 
AT89S52 nicht. Deshalb bringt dir das auch nicht wirklich was die Zeilen 
aus dem Tutorial zu kopieren.

Was hast du denn für nen Compiler?
Versuch doch einfach das Tutorial zu lesen und zu verstehen. Dann kannst 
du das in 0,nix für deinen uC umsetzen.

von Oliver D. (highspeed-oliver)


Lesenswert?

Hmm ja, ich versuche natürlich das zu verstehen.

Mir würde es reiche, wenn ich zumindest das display schonmal 
initialisiert bekommen. Dafür gibt es bei sprut.de ein ablaufdiagramm, 
wo was geschrieben werden muss um das display in den 4 bit modi zu 
bekommen.
Das habe ich programmiert und auf den uc geschrieben, aber es wird nur 
der oberste reihe meines LCDs eingeschaltet.

Eigentlich sollten das dann doch beide sein.

von Oliver D. (highspeed-oliver)


Lesenswert?

Mein compiler ist der RIDE von raisonance

von Condi (Gast)


Lesenswert?

Nee, wenn man Spannung anlegt, leuchtet je Nach Display immer nur ein 
Teil.

z.B. die erste Zeile, erste und dritte, die erste Hälfte der Zeile,...

Deine Initialisierung funktioniert nicht sonst würde es nur kurz 
aufblinken und dann leer sein.

Da stimmt bestimmt das Timing nicht.

von Oliver D. (highspeed-oliver)


Lesenswert?

Ok.

Ich meine aber alle zeiten eingehalten zu haben und eher ein bischen zu 
viel zu haben....

von Condi (Gast)


Lesenswert?

Tja, dann stell doch mal nen Schaltplan und das Programm hier rein. Das 
Datenblatt des LCD ist ja eher dürftig...

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Oliver D. wrote:
> Ok.
>
> Ich meine aber alle zeiten eingehalten zu haben und eher ein bischen zu
> viel zu haben....

Vielleicht hilft Dir das ja weiter...

...

von Oliver D. (highspeed-oliver)


Angehängte Dateien:

Lesenswert?

Ehm schaltplan?

Ich habe das Display so verbunden:
sbit  DB4=0xB0;
sbit  DB5=0xB1;
sbit  DB6=0xB2;
sbit  DB7=0xB3;
sbit  RS=0xB4;
sbit   E=0xB5;

Also einfach an Port B0 das dingen angeklemmt.
RW liegt auf masse.

Mein Board funktioniert 100% einwandfrei.

Die Verkabelung zum Display ist ebenfalls einwandfrei. Habs 
durchgemessen.
Ich habe ausserdem ein zweites Display hier, was sich mit gleichem code 
ebenfalls nicht inititalisieren lässt.
Liegt dann wohl an meinem code ;)

Ich habe den mal in den Anhang gepackt. Wundert euch nicht, dass es 
absoluter Mist vom Stil her ist...Es ist einfach mal für den Anfang 
gedacht um einfach das Display mal zu initialisieren.
Für die Zeit habe ich einfach mal eine For schleife genommen.
Achja, mein uC läuft bei 11,0592Mhz.

von Condi (Gast)


Lesenswert?

Wie gesagt, das Timing stimmt nicht.

Näach anlegen der Betriebsspannung >=15ms warten...
Deine Warteschleifen werden wohl auch wegoptimiert und dann fehlt auch 
noch enable in deinem Code.

von Oliver D. (highspeed-oliver)


Lesenswert?

Enable?

Mir fällt gerade auch auf, das beim Beispiel programm code des AVR GCC 
ein kurzer Enable Impuls eingetragen ist. Dieser wird scheinbar immer 
dann ausgefüht, wenn ein Wert übernommen werden soll?!?!

Im Tutorial von Sprut.de steht aber nur, das sich bei 1 Signal auf E das 
Display ansprechen lässt.

Achja, muss ich unbedingt eine LCD Clear routine ausführen, damit nach 
dem initialisieren der balken verschwindet? Oder geht der automatisch 
weg?

von Condi (Gast)


Lesenswert?

Halt ich für ein Gerücht, das steht da nicht. Nach der Initialisierung 
ist das Display leer, da siehst du ob es funktioniert hat. Das pdf von 
Hannes ist auch ganz toll.

von Oliver D. (highspeed-oliver)


Lesenswert?

Ja, das mag sein.

Naja ich glaube nach 3 stunden rumprobiererei...

Jedenfalls währe es schön einfach mal ein einfaches beispiel nur zur 
initialisierung zu haben.
Gibts nicht irgendeine gute website auf der sowas für "anfänger" 
geschrieben ist?

Ich finde den code sehr groß, vor allem weil in jeder funktion wieder 
eine andere aufgerufen wird etc.

von Condi (Gast)


Lesenswert?

Ja hier das Tutorial auf der Seite. Die Fehler, die oben auftauchen, 
liegen an deinem compiler. Der hat bestimmte Definitionen des gcc nicht 
bzw. andere. Wenn du keine Programmiererfahrung hast, dann solltest du 
erstmal mit ASM loslegen oder das Handbuch zu dem Compiler lesen. Ach 
und fang bei Schritt 1 an. LED Blinken lassen im 2Hz Rhythmus, dann 2 
LED blinken lassen und zwar gleichzeitig und dann mal entgegengesetzt. 
Das erspart dir viel Zeit und Frust...

von Oliver D. (highspeed-oliver)


Lesenswert?

Hmm,

also in C bekomme ich sowas bereits hin.
Mit Timer etc. Auch Interruptroutinen kann ich programmieren.

Z.b. eine Ampelschaltung mit LEDs. BEi Interrupt wird dann den 
Fußgängern das überqueren ermöglicht...
solche spielereien.

Asm möchte ich mir einfach nicht antun.
Ich werde für meine Prüfung ohnehin nur c brauchen, da muss man nicht 
noch soetwas lernen.

von Condi (Gast)


Lesenswert?

Ist ehrlich schwer vorstellbar mit Ampel und Interrupt...
Also ich kann kein C und find das alles recht gut und easy im Tut. 
erklärt.
ASM "antun", man glaubt garnicht wie hilfreich das manchmal sein kann.

Erst wird die Funktion jedes Pins des LCD erklärt, übrigens auch bei 
sprut.
Und dann die einzelnen Funkionen..


void lcd_data(unsigned char temp1);

sendet Daten an das Display

void lcd_command(unsigned char temp1);

sendet einen Befehl an das Display

void lcd_enable(void);

// erzeugt den Enable-Puls

void lcd_init(void);
// Initialisierung:
// Muss ganz am Anfang des Programms aufgerufen werden.

usw.
void set_cursor(uint8_t x, uint8_t y);
die Funktion macht nen Error weil dein Compiler wohl uint8_t nicht kennt 
aber die Funktion brauchst du eh noch nicht.


also


void lcd_init(void)
{
   LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | (1<<LCD_EN);   // Port auf 
Ausgang schalten

-> brauchst du nicht
   // muss 3mal hintereinander gesendet werden zur Initialisierung

   _delay_ms(15); hm, wie lautet die warte 15ms Funktion in Ride?
->   So jetzt werden die Pins gesetzt.
   LCD_PORT &= 0xF0;
   LCD_PORT |= 0x03;
   LCD_PORT &= ~(1<<LCD_RS);      // RS auf 0

-> Enable Puls
 lcd_enable();

   _delay_ms(5);
->Warten


usw.....


jetzt kannst du das doch für deines anpassen.

void display_init (void)
{
wait (50);   -> ersetzen durch warteschleife 40ms
E=0;         // Enable ausschalten
//initialisieren  f�r 4 bit
RS=0; //Steuerregister auswählen
DB7=0; //Datenleitungen einstellen
DB6=0;
DB5=1;
DB4=1;
E=1;  //Enable Leitung triggern
wait (1us); //kleine Pause
E=0;

.....

So. unt wenn du schon mit Interrupts gearbeitet hast, dann kannst du ja 
den Timerinterrupt nutzen um die Pause zu machen, falls dein Compiler 
keine wartefunktion hat.

von Hannes L. (hannes)


Lesenswert?

> Asm möchte ich mir einfach nicht antun.

Schade eigentlich. Denn der Controller kann kein C, der kann nur 
Maschinencode, der einszueins nur in Assembler notiert werden kann. Mit 
C alleine kommst Du vielleicht unter einem Betriebssystem zurecht, bei 
Mikrocontrollern ist man aber sooooo dicht an der Hardware, dass 
Assemblerkenntnisse schon erforderlich sind. Die Leute, die gute 
C-Programme für Mikrocontroller schreiben, die können auch alle 
Assembler.

...

von Oliver D. (highspeed-oliver)


Angehängte Dateien:

Lesenswert?

Hmm ja, könnte ich machen ;)

Also zu dem enable.
Wenn ich daten an den controller schicken will muss ich zunächst auf E=0 
schreiben.
Dann kurz warten.
Dann in RS und RW=0 schreiben.
kurz warten.
Dann E=1 setzen.
Jetzt gebe ich meine steuerbefehle auf die Leitung.
kurz warten.
E=0 setzen. Mit der negativen Flanke werden die steuerdaten übernommen.

Ist das so korrekt?
Das brauche ich ja dann quasi immer, weil nur dann daten vom HD 
controller bearbeitet werden.

Achja, bei Sprut.de ist eine tabelle für den HD controller, wie man in 
den 4 bit modus kommt. (im anhang)

Wenn ich das schritt für schritt genauso nachprogrammiere, müsste mein 
display doch initialisiert sein, oder?
Natürlich mit dem zwischenschritt, dass ich die daten immer nur per 
wechsel von E auf 0,1,0 in den Controller reinbekomme.

Korrekt?

von Hannes L. (hannes)


Lesenswert?

> Wenn ich das schritt für schritt genauso nachprogrammiere, müsste mein
> display doch initialisiert sein, oder?

Du kannst programmieren was Du willst, wenn Du das Verhalten Deines 
Compilers nicht kennst, kommt sowiso was anderes raus als Du denkst 
programmiert zu haben.

Ich kann kein C, ich programmiere in Assembler, aber nur AVRs. Man liest 
hier aber immer wieder, dass C-Compiler Warteschleifen wegoptimieren und 
auch sonst ein gewisses Eigenleben entwickeln. Einziger Weg, Sicherheit 
zu haben, ist das Überprüfen des vom C-Compiler erzeugten 
Assemblercodes, dazu sollte man aber etwas Assembler können.

Nächster Punkt: Du benutzt einen relativ schnellen Quarz. Könnte es 
sein, dass das Timing deshalb nicht einzuhalten ist? Highspeed ist nicht 
immer der beste Weg...

Im Übrigen habe ixch den Eindruck, dass Du hier völlig orientierungslos 
mit Versuch und Irrtum experimentierst, anstatt die Sache mal 
systematisch anzugehen. Im von mir weiter oben geposteten 
Pollin-Datenblatt (in Deutsch) sind in Kurzfassung die Algorithmen zur 
Initialisierung beschrieben. Du musst sie nur noch in der 
Programmiersprache Deiner Wahl umsetzen und dabei das Timing einhalten. 
Wenn Du aber zuviele Baustellen gleichzeitig hast, also weder den 
Algorithmus verstehst, noch mit Deiner Programmiersprache umgehen 
kannst, dann hast Du schlechte Karten, dann solltest Du wirklich nochmal 
mit kleineren Projekten beginnen, die Aussicht auf Erfolg haben, um 
durch Training sattelfest zu werden.

...

von Condi (Gast)


Lesenswert?

also erst Daten anlegen, dann einmal enable auf 1, kurz warten wieder 
auf 0.

Ja wenn du das so programmierst, dann sollte das Display initialisiert 
werden und auch leer sein.

von Olli (Gast)


Lesenswert?

Irgendwo im Datenblatt steht bestimmt, was man dem Display für Signale 
senden muss, damit es funzt.

Diese Funktionen programmierst du dann selber in C (sollte für dich ja 
kein problem sein, nach der Ampelsteuerung)

Dann noch was zum Thema for-Schleifen optimierung: Den Grad der 
Optimierung kann man in der Regel einstellen. Wenn du Wartezeiten mit 
for-Schleifen programmierst, ist es ratsam ohne Optimierung zu arbeiten, 
da diese sonst wegoptimiert werden.

von Stephan (Gast)


Lesenswert?

Hannes Lux wrote:
> Ich kann kein C, ich programmiere in Assembler, aber nur AVRs. Man liest
> hier aber immer wieder, dass C-Compiler Warteschleifen wegoptimieren und
> auch sonst ein gewisses Eigenleben entwickeln. Einziger Weg, Sicherheit
> zu haben, ist das Überprüfen des vom C-Compiler erzeugten
> Assemblercodes, dazu sollte man aber etwas Assembler können.

"Eigenleben". Hallo. Da wird was optimiert (schneller, kleiner, besser), 
nur weil du die C-Syntax nicht verstehst und noch nie was programmiert 
hast, heisst das nicht das der Compiler etwas falsch macht.
Am besten bleibst du doch bei deinem Assembler, da wirst du nicht vom C 
ueberfordert.

von Stephan (Gast)


Lesenswert?

@ Olli

schonmal was von volatile gehoert?

von Olli (Gast)


Lesenswert?

@Stephan

Klaro kenn ich Volatile!!!

Aber ich will doch den Highspeed-Oliver nicht mit solchen Ausdrücken 
verwirren. Der läuft ja mit dem Display schon auf Anschlag.

Nach meiner Meinung ist eine Antwort nur immer so gut, wie sie vom 
Zuhörer verstanden wird!

von Oliver D. (highspeed-oliver)


Lesenswert?

Hallo Hannes,

ich habe mir natürlich dein Datenblatt durchgelesen.
Dort steht erstmal die eigenschaft mit dem E etwas anders beschrieben, 
als ich das verstanden habe. Z.b. ist dort nirgends die rede von einer 
ansteigenden Flanke, also von low nach high.
Im Internet laß ich, dass ich beim ersten Schritt nach dem ich >15ms 
gewartet habe erst einmal E=0 setze.
Danach lege ich RW und RS auf 0 um zu signalisieren, dass nun daten 
kommen, die ins steuerregister geschrieben werden.
Danach warte ich eine kurze zeit.
Dann setze ich E=1. Mit der steigenden Flanke werden beide werte 
gelesen.
Das Display weiß nun was zu tun ist und mit der nächsten fallenden 
Flanke werden die Werte an DB übernommen.
Dannach soll ich >4,1ms warten.
Danach wieder dasselbe.
E=0. Kurz warten. Dann RS=0 RW=0. Kurz warten. E=1.
kurz warten. An DB 4-7 meine Befehle anlegen, E=0. Es wird übernommen.

Dann warte ich 100us.
Und wieder das gleiche...
 Hiermit habe ich dann 3x D5 und D4 auf 1 gesetzt und den Rest auf Null.

So, nun stelle ich auf 4Bit datenbus um. Dafür schreibe ich eine Hex2 
also 10 rein. DB5 also auf 1 und DB4 auf0. Der Rest liegt auf Null.

Ist für mich bis hierher verständlich.

In deinem text-lcds wird nun der schritt system set ausgeführt. Im 
Tutorial von Sprut.de wird das in 10 Schritten getan. Wohl deshalb, weil 
man ja nun im 4 Bit modus ist und die beiden Nibbles geteilt übertragen 
muss.
Ausserdem wird das display dort noch ein und aus- geschaltet sowie 
gelöscht.


Das letzte was ich dann schreiben müsste währe nurnoch display on.

Dann sollte das Display anspringen...
Ich bin mir eignetlich ziehmlich sicher, dass es dann so funktioonieren 
sollte. Das mit dem  Compiler und wegoptimieren von schleifen kann 
natürlich sein...Ich werde am besten mal einen echten Timer verwenden.

von Hannes L. (hannes)


Lesenswert?

Stephan wrote:
> Hannes Lux wrote:
>> Ich kann kein C, ich programmiere in Assembler, aber nur AVRs. Man liest
>> hier aber immer wieder, dass C-Compiler Warteschleifen wegoptimieren und
>> auch sonst ein gewisses Eigenleben entwickeln. Einziger Weg, Sicherheit
>> zu haben, ist das Überprüfen des vom C-Compiler erzeugten
>> Assemblercodes, dazu sollte man aber etwas Assembler können.
>
> "Eigenleben". Hallo. Da wird was optimiert (schneller, kleiner, besser),
> nur weil du die C-Syntax nicht verstehst und noch nie was programmiert
> hast,

Woher willst Du wissen, ob ich "noch nie was programmiert" habe? Ich 
habe schon einige Dinge programmiert, aber eben nicht in C oder BASCOM, 
sondern in AVR-Assembler. Und natürlich auch nicht für 8051er oder PICs, 
sondern für AVRs. Und ob Du es glaubst oder nicht, meine Programme 
funktionieren, meine LCDs machen das, was sie sollen. Und das alles mit 
eigenem (ASM-)Code, entwickelt aus den Angaben in den Datenblättern, 
also nicht durch Verwendung irgendwelcher Bibliotheken irgendwelcher 
Herkunft.

> heisst das nicht das der Compiler etwas falsch macht.

Das habe ich auch nicht behauptet. Ich habe lediglich behauptet, dass es 
sehr vorteilhaft ist, wenn man seinen Compiler (falls man denn einen 
benutzt) kennen sollte bzw. sein Ergebnis (in ASM) überprüfen sollte.

> Am besten bleibst du doch bei deinem Assembler,

Ja sicher bleibe ich bei Assembler, die von mir benutzten AVRs bleiben 
doch auch bei ASM (bzw. Maschinenvode) und lernen doch auch kein C. 
Assemblerprogrammierung ohne C-Kenntnisse geht ganz gut, 
C-Programmierung ohne ASM-Kenntnisse aber scheinbar nicht oder nur 
begrenzt.

> da wirst du nicht vom C
> ueberfordert.

Da verwechselst Du wohl was... Ich bin nicht der, der Hilfe sucht, Du 
sprichst also den falschen an. Wenn ich ein Verständnisproblem habe, 
dann gehe ich den Dingen auf den Grund, versuche also aus den 
vorhandenen Quellen die nötigen Informationen zu ziehen und die 
Zusammenhänge zu verstehen. Dann bin ich auch in der Lage, mir die 
notwendigen Routinen (in ASM) zu schreiben. Das dauert zwar meist etwas 
länger, hat aber den kleinen Vorteil, dass ich über jedes Byte meines 
Codes Bescheid weiß.

Nichts gegen C, wer es kann, soll damit glücklich werden. Aber wer C 
wirklich kann, der kann auch etwas ASM...

...

von Oliver D. (highspeed-oliver)


Lesenswert?

Womit mir immer noch nicht geholfen wäre...

von Hannes L. (hannes)


Lesenswert?

Oliver D. wrote:
> Womit mir immer noch nicht geholfen wäre...

Wenn Du vermutest, dass Dein Compiler die Warteschleifen nicht korrekt 
umsetzt, dann solltest Du Dir als erstes den vom Compiler erzeugten Code 
in ASM anzeigen lassen und überprüfen, ob der Compiler das gemacht hat, 
was Du von ihm erwartest. Solange diese Unsicherheit da ist, lohnt es 
sich nicht, über den Rest nachzudenken.

Und da ich mich (bezüglich Mikrocontroller) nur in der Niesche 
AVR-Assembler auskenne, kann ich Dir auf dem 8051 leider nicht helfen.

...

von Oliver D. (highspeed-oliver)


Lesenswert?

Hmm ok.

Ich setz mich mal ebend dran mit einem echten Timer die wartezeiten zu 
programmieren.
....

Damit ich den fehler von seiten des compilers her ausschliessen kann.

von Stephan (Gast)


Lesenswert?

Probiers doch mal mit volatile:

statt:

int i;
...
for(i=0;i<100;i++);

machst du einfach:

volatile int i;
...
for(i=0;i<100;i++);

und der compiler kuerzt dir nix weg.

Ach ja Hannes, nur weil du auf ASM beschraenkt bist, musst du nicht 
beleidigt sein.

von Oliver D. (highspeed-oliver)


Angehängte Dateien:

Lesenswert?

So, ich habe hier mal was mit timer programmiert.

Ich habe mich dabei zu 100% an die anleitung von sprut.de gehalten.
Es müsste so funktionieren, tut es aber nicht.
Timing ist auch genug drinne!

von Oliver D. (highspeed-oliver)


Angehängte Dateien:

Lesenswert?

Hier auch einfach mit volatile.

Funktioniert ebenfalls nicht :(

von Jochen S. (schiffner)


Lesenswert?

hallo
du hast da was mit dem Enable E falsch verstanden. Du setzt deine 
Datenleitungen und machst dann kurz Enable an, um den Controller zu 
sagen das er die Daten jetzt verarbeiten kann.

E=0;
DB7=0;
DB6=0;
DB5=1;
DB4=1;    //Daten setzen

warten

E=1;
warten
E=0;    // Enable an und aus
warten

nächster Block

von Oliver D. (highspeed-oliver)


Lesenswert?

Hast du das an meinem Code erkannt?

Ich dachte das es soo richtig ist.

Erst E=0.
Dann RS=0 und RW=0.
Dann setze ich E=1.
Durch die steigende Flanke + RS und RW nimmt der HD controller an, dass 
nun in steuerregister geschrieben wird.
Dann lege ich an die DBs meine daten an.
Ich setze E=0.
Bei der negativen Flanke werden die Daten eingelesen.

von Condi (Gast)


Lesenswert?

Wie schon 10mal erwähnt in dem Thread erwähnt, der Display Controller 
übernimmt immer von low nach high die Daten.

Du setzt erst e=1 und änderst dann die Bits und setzt e=0. Erst e=0, 
dann die Bits setzen und dann erst e=1;


void display_init (void)
{
wait (500);
E=0;// E auf 0 Setzen.
//initialisieren  f?it
RS=0; //Interface auf 8 bit setzen
tst_nop();
DB7=0;
DB6=0;
DB5=1;
DB4=1;
tst_nop();
tst_nop();
tst_nop();
E=1;//Bei wechsel von low auf high wird die flanke erkannt und mit 
R/Wlow ein Schreibzugriff sowie mit RS=0
  // die Daten als Kommande verstanden und in den Steuerregister 
geschrieben.
E=0;

von Oliver D. (highspeed-oliver)


Lesenswert?

????

Also das tut mir jetzt leid, dass ich hier etwas falsches schreibe, aber 
auf Sprut.de steht:

Im Moment der Low-High-Flanke von ENABLE liest das Dislplay die Werte 
von RS und R/W ein. Ist zu diesem Zeitpunkt R/W=0, dann liest das 
Display mit der folgenden High-Low-Flanke von ENABLE  den Datenbus ein 
(Schreibzyklus). War aber R/W=1, dann legt das Display ein Datenword auf 
den Datenbus (Lese-Zyklus), solange bis die High-Low-Flanke von ENABLE 
das Interface wieder deaktiviert.

Schreiben zum Display
Die folgende Abbildung zeigt einen Schreibzugriff auf ein Display. Das 
Display überwacht den Pegel von ENABLE. Ändert sich dieser Pegel von Low 
nach High, dann fragt es die Leitungen RS und R/W ab. Liegt zu diesem 
Zeitpunkt R/W auf Low, dann weiß das Display, daß ein Schreibzugriff 
erfolgt, und bereitet sich darauf vor, mit der High-Low Flanke von 
ENABLE die Daten vom Datenbus ( DB0..DB7 ) einzulesen. Dazu muß das 
Display aber noch wissen, wohin diese Daten geschrieben werden sollen. 
Liegt RS auf low, so werden die Daten als Kommando verstanden, und in 
ein Steuerregister geschrieben. Liegt aber RS auf High, so handelt es 
sich um Daten, die angezeigt werden sollen, und in den Textpuffer 
(DDRAM) zu schreiben sind. (oder um die Definition eines neuen Zeichens)



Ist also das, was auf Sprut.de steht, falsch?!?!
Denn dort steht ja drin, das man erst RS und RW mit positiver flanke 
lesen soll.
Bei der negativen werden dann die die daten vom datenbus gelesen.

von Oliver D. (highspeed-oliver)


Lesenswert?

Und was soll das bedeuten?

Du setzt erst e=1 und änderst dann die Bits und setzt e=0. Erst e=0,
dann die Bits setzen und dann erst e=1;

Das widerspricht sich doch.

von Uwe (Gast)


Lesenswert?

Hi!
>Wie schon 10mal erwähnt in dem Thread erwähnt, der Display Controller
>übernimmt immer von low nach high die Daten.
Das ist ein ganz schlimmer Irrtum. Mit HL werden die Daten übernommen, 
jedenfalls bei HD44780 & Co. E kann übrigens immer auf H stehen, nur zur 
Datenübernahme muss es mal auf L.

Viel Erfolg, Uwe

von Oliver D. (highspeed-oliver)


Lesenswert?

LOL



Also kann mir nunmal jemand die korrekte Reihenfolge geben?

Ist es richtig, dass ich zumindest fürs schreiben in den steuerregister:

E=0;
RS=0;
RW=0;
E=1;
DB7..
DB6..
DB5..
DB4..
E=0;

schreiben muss?
Ist das so vom ablauf her korrekt?

von Hannes L. (hannes)


Lesenswert?

Also ich setze zuerst, während E noch auf L ist, RS und die Daten (RW 
ist fest auf L, da ich kein Busy-Flag abfrage), dann warte ich einige 
Takte, dann setze ich E auf H, warte wieder einige Takte und setze 
danach E wieder auf L. Und das funktioniert.

...

von Jochen S. (schiffner)


Lesenswert?

@Oliver
nein das ist noch nicht richtig so.

Du stellt zuerst die Daten richtig ein (E steht auf E=0):

RS..
RW..
DB7..
DB6..
DB5..
DB4..

dann sagst du dem Displaycontroller, dass die Zustände jetzt da sind und 
er sie einlesen/bearbeiten kann:

E=1;
kurz warten
E=0;
(erst durch das setzen und rücksetzen von E liest der Displaycontroller 
die Daten die auf RS,RW,DB7 usw. sind)

dann wartest du deine Vorgeschriebene Zeit ab. Jetzt kannst du 
Datenleitungen auf den nächsten gewüschten Zustände setzen:

RS..
RW..
DB7..
DB6..
DB5..
DB4..

jetzt musst du dem Controller wieder sagen das die Daten fertig sind und 
er sie einlesen kann:

E=1;
kurz warten
E=0;

so geht das jetzt jedesmal weiter (das siehst du auch im tut., da kommt 
nach jeder Befehlseingabe [lcd_enable(); und _delay_ms(5);])

von Oliver D. (highspeed-oliver)


Lesenswert?

Ok Dankeschön.

Ich probier es nachher aus.

Aber was mich wundert ist, dass es in dem Tutorial von sprut.de, welches 
ja auch hier auf der seite verlinkt ist, etwas anders steht!
....

Egal.
Ich probiers nachher aus.
Danke nochmal.

von Oliver D. (highspeed-oliver)


Lesenswert?

Hmm funktioniert immer noch nicht...
auch nicht mit timer.
Die Zeiten sind dabei schon ziehmlic lang eingestellt...

von Murmel (Gast)


Lesenswert?

Vielleicht hilft dir das ja weiter, ist allerdings für einen Mega8
1
.equ  F_CPU,  3686400
2
.include  "AVR.H"
3
;---------------------------------------------------------------------------
4
; Reset- und Interruptvektoren          ; VNr.  Beschreibung
5
  rjmp  main  ; 1     POWER ON RESET
6
  reti    ; 2     Int0-Interrupt
7
  reti    ; 3     Int1-Interrupt
8
  reti    ; 4     TC2 Compare Match
9
  reti    ; 5     TC2 Overflow
10
  reti    ; 6     TC1 Capture
11
  reti    ; 7     TC1 Compare Match A
12
  reti    ; 8     TC1 Compare Match B
13
  reti    ; 9     TC1 Overflow
14
  reti    ; 10    TC0 Overflow
15
  reti    ; 11    SPI, STC Serial Transfer Complete
16
  reti    ; 12    UART Rx Complete
17
  reti    ; 13    UART Data Register Empty
18
  reti    ; 14    UART Tx complete
19
  reti    ; 15    ADC Conversion Complete
20
  reti    ; 16    EEPROM Ready
21
  reti    ; 17    Analog Comperator
22
  reti    ; 18    TWI (I²C) Serial Interface
23
  reti    ; 19    Store Program Memory Ready
24
;---------------------------------------------------------------------------
25
; Start, Power ON, Reset
26
main:  ldi  r16,lo8(RAMEND)
27
  out  SPL,r16  ; Init Stackpointer LO
28
  ldi  r16,hi8(RAMEND)
29
  out  SPH,r16  ; Init Stackpointer HI
30
  rcall  LCD_init
31
  rcall  LCD_clear
32
;---------------------------------------------------------------------------
33
mainloop:  rcall  wait
34
  ldi  r16,'H'
35
  rcall  LCD_data
36
  ldi  r16,'a'
37
  rcall  LCD_data
38
  ldi  r16,'l'
39
  rcall  LCD_data
40
  ldi  r16,'l'
41
  rcall  LCD_data
42
  ldi  r16,'o'
43
  rcall  LCD_data
44
  ldi  r16,' '
45
  rcall  LCD_data
46
47
  rcall  LCD_line2
48
49
  ldi  r16,'W'
50
  rcall  LCD_data
51
  ldi  r16,'e'
52
  rcall  LCD_data
53
  ldi  r16,'l'
54
  rcall  LCD_data
55
  ldi  r16,'t'
56
  rcall  LCD_data
57
  ldi  r16,' '
58
  rcall  LCD_data
59
60
  rcall  LCD_home
61
62
  rjmp  mainloop
63
;===========================================================================
64
; hier Unterprogramme und Interruptroutinen zufügen
65
;---------------------------------------------------------------------------
66
wait:  push  r24
67
  ldi  r24,0x13  ; hier delay einstellen 13 = ca. 20yS
68
w1:  subi  r24,0x01
69
  rcall  wait20ms
70
  brcc  w1
71
  pop  r24
72
  ret
73
;---------------------------------------------------------------------------
74
wait5ms:  ldi  r16,255
75
  ldi  r17,26
76
w5ms:  dec  r16
77
  brne  w5ms
78
  dec  r17
79
  brne  w5ms
80
  ret
81
;---------------------------------------------------------------------------
82
wait20ms:  ldi  r16,255
83
  ldi  r17,104
84
w20ms:  dec  r16
85
  brne  w20ms
86
  dec  r17
87
  brne  w20ms
88
  ret
89
;---------------------------------------------------------------------------
90
LCD_init:     sbi  DDRD,2          ; LCD RS = OUT
91
    sbi  DDRD,3          ; LCD E  = OUT
92
    sbi  DDRD,4        ; LCD D4 = OUT
93
    sbi  DDRD,5        ; LCD D5 = OUT
94
    sbi  DDRD,6         ; LCD D6 = OUT
95
    sbi  DDRD,7         ; LCD D7 = OUT
96
    cbi  PORTD,2          ; LDC RS = Low
97
98
    ; warte bis PowerUp
99
    ldi  r18,20
100
powerup:  rcall   wait5ms
101
    dec  r18
102
    brne  powerup          ; Power-Up Wartezyklus min 30 ms
103
104
    ; sende Resetsequenz kompatibel zu HD44780 Industriestandard
105
    ldi  r16,0b00110000      ; Reset-Sequenz Teil 1
106
    out  PORTD,r16
107
    rcall  LCD_enable      ; Enable-Impuls
108
    rcall  wait5ms
109
    ldi  r16,0b00110000      ; Reset-Sequenz Teil 2
110
    out  PORTD,r16
111
    rcall  LCD_enable      ; Enable-Impuls
112
    rcall  wait5ms
113
    ldi  r18,100        ; Wartezyklus bei RESET LCD min 100 µs
114
resetLCD:  
115
    nop
116
    nop  
117
    nop
118
    dec  r18
119
    brne  resetLCD
120
    ldi  r16,0b00110000      ; Reset-Sequenz Teil 3
121
    out  PORTD,r16
122
    rcall  LCD_enable      ; Enable-Impuls
123
    rcall  wait5ms
124
125
                ; sende init 1
126
    ldi  r16, 0b00100000        ; 4 Bit Modus aktivieren
127
    out  PORTD, r16
128
    rcall   LCD_enable       ; Enable-Impuls
129
    rcall   wait5ms
130
    ldi  r16, 0b00101000
131
    rcall   LCD_cmd             ; Function Set 4 Bit, 2 Zeilen, 5x7
132
    rcall   LCD_off
133
    rcall   LCD_clear
134
    ldi  r16, 0x06
135
    rcall   LCD_cmd        ; Entry Mode Set, increase+shifted
136
    rcall   LCD_on
137
    ret
138
;---------------------------------------------------------------------------
139
LCD_data:  ldi  r18,0b0000100  ; RS = hi
140
  rjmp  LCD_out
141
;---------------------------------------------------------------------------
142
LCD_cmd:  ldi  r18,0b0000000  ; RS = lo
143
LCD_out:  mov  r17,r16
144
  swap  r17
145
  andi  r16,0b11110000
146
  or  r16,r18
147
  andi  r17,0b11110000
148
  or  r17,r18
149
  out  PORTD,r16
150
  rcall  LCD_enable
151
  out  PORTD,r17
152
  rcall  LCD_enable
153
  rcall  wait5ms
154
  ret
155
;---------------------------------------------------------------------------
156
LCD_enable:  sbi  PORTD,3  ; Enable high
157
  nop    ; kurz warten
158
  nop
159
  nop
160
  cbi  PORTD,3  ; Enable wieder low
161
  ret
162
;---------------------------------------------------------------------------
163
LCD_clear:  ldi  r16,0b00000001  ; Display löschen
164
  rcall  LCD_cmd
165
  rcall  wait5ms
166
  ret
167
;---------------------------------------------------------------------------
168
LCD_off:  ldi  r16,0b00001000
169
  rcall  LCD_cmd
170
  rcall  wait5ms
171
  ret
172
;---------------------------------------------------------------------------
173
LCD_on:  ldi  r16,0x0E
174
  rcall  LCD_cmd
175
  rcall  wait5ms
176
  ret
177
;---------------------------------------------------------------------------
178
LCD_home:  ldi  r16,0b00000010  ; Display Cursor HOME
179
  rcall  LCD_cmd
180
  rcall  wait5ms
181
  ret
182
;---------------------------------------------------------------------------
183
LCD_line1:  ldi  r16,0b10000000  ; DRAM auf Adresse 0x00
184
  rcall  LCD_cmd
185
  rcall  wait5ms
186
  ret
187
;---------------------------------------------------------------------------
188
LCD_line2:  ldi  r16,0b11000000  ; DRAM auf Adresse 0x40
189
  rcall  LCD_cmd
190
  rcall  wait5ms
191
  ret
192
;---------------------------------------------------------------------------
193
; Goto r16 = Adresse (Zeile 1 = 0x00..0x0F, Zeile 2 = 0x40..0x4F)
194
LCD_goto:  ori  r16,0b10000000  ; Goto DRAM auf Adresse r16
195
  rcall  LCD_cmd
196
  rcall  wait5ms
197
  ret
198
;---------------------------------------------------------------------------

von Philipp B. (philipp_burch)


Lesenswert?

Kleiner Tipp: Mach den Takt des Controllers mal gaaanz lahm (100Hz z.B.) 
und häng an jede Daten- und Steuerleitung eine LED. Dann siehst du, was 
sich wirklich tut und was eben nicht. Sofern dein Controller mit einem 
solchen Takt noch läuft natürlich. Kannst auch einen Taster an den 
Takteingang hängen, dann hast du sowas wie Einzelschrittmodus. Nur 
sollte der dann nicht zu stark prellen.
Oder hast du sowas wie einen Logic Analyser?

von Oliver D. (Gast)


Lesenswert?

Ah jo, da sieht man ebenfalls, wie erst die daten bei EN= Low 
geschrieben werden. Dann kurz mit enable fuktion einmal an und 
ausgeschatet wird...


Ich werde es nun erstmal ordentlich mit timerfunktion etc. 
programmieren, bevor ich hier weitere Fragen stelle ;)

von Murmel (Gast)


Lesenswert?

Ich kenne deine Verdrahtung ja nicht, aber ich würde die nicht genutzen 
Signaleingänge des Displays alle auf GND legen. Nur um keine Zicken rein 
zubekommen.

von Jochen S. (schiffner)


Lesenswert?

Oliver D. wrote:
> So, ich habe hier mal was mit timer programmiert.
>
> Ich habe mich dabei zu 100% an die anleitung von sprut.de gehalten.
> Es müsste so funktionieren, tut es aber nicht.
> Timing ist auch genug drinne!

nochmal was zu deinem Code vom 09.11.2007 17:41 :

  void display_init (void)
  {
  unsigned int timerstate;
  LED=0xFF;

  if(TF0==1) // Bei einem Z�hler�berlauf wird timerstate inkrementiert
  {
  timerstate++;
  }
  //mindestens 15ms warten, getan durch timestate >= 20

  if(timerstate>=20 && timerstate <= 23)

  {
  EN=0;//Low setzen
  LED=0;
  }usw.

das is ja schön und gut mit deinem timer, aaaber
da solltest du mal mindestens eine while-Schleife oder so drum setzen, 
sonst rennt dein Programm genau einmal komplett durch "display_init" 
ohne irgend eine if Bedingung zu erfüllen und springt wieder zurück zu 
main und nichts passiert.
nur mal so nebenbei :-)

von Oliver D. (highspeed-oliver)


Lesenswert?

Hallo,

oben siehst du, dass die funktion display init heisst.
Sie wird einmal in meinem hauptprogramm ausgeführt.

Danach kommt for schleife mit (;;)

Das problem kann ich also ausschliessen.


Der Tipp mit den LEDs und takt ist ne gute geschichte...

Leider habe ich nur ein 11,0592mhz quarz und sonst nix :(

Ich werde heute mal alles ordentlich programmieren und dann nochmal 
reinstellen!

von Oliver D. (highspeed-oliver)


Lesenswert?

Achja, ist es zwingend erforderlich oder überhaupt machbar, die ports 
des Displays bei nichtverwenden auf GND zu legen?
Ich arbeite ja nur im 4 bit modus und viele pins sind unbenutzt...

Sollte man dann alles auf GND legen oder eher nicht?

von Oliver D. (highspeed-oliver)


Angehängte Dateien:

Lesenswert?

WUUUUHUUUUUUUUU

JABBA DABBA DOOOO

ES KLAPPT!!!!


Ich habe endlich alles ordentlich programmiert und ich sehe wie das 
display in den 2 zeilen modus wechsel!!!


Oh man geil. Das ist echt toll als Anfänger sowas hinzubekommen und 
bestärkt einen, einen weiteren nachmittag dran zu arbeiten.

Ich poste einfach mal den source code...
Vielleicht gibts ja noch jemanden der dasselbe am at89s52 machen will.

Danke nochmal an alle, die an mich geglaubt haben ;)

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.