Forum: Mikrocontroller und Digitale Elektronik LCD an AT89S8252 Ansteuerung in C


von Thomas H. (bayluga)


Lesenswert?

Hallo, auch!
Ich bräuchte mal Hilfe von den Profis hier, da ich auch nach Google und
Forensuche keine Lösung für mein Bescheidenes Problem finden kann... Ich
habe eine Standard 2x16-Display (Hd44780 o.ä.) an einem AT89S8252 im
8-Bit-Modus im betrieb. Mit Assembler läuft das auch alles wunderbar,
nur in C haperts halt. Hat jmd. zufällig einen Lauffähigen C-Code zur
init. und evtl. noch ein Ausgabebeispiel für Textstrings. Am liebsten
natürlich für den 89s8252. Besten Dank schonmal! Gerne auch direkt an:
bayluga@freenet.de

von Ralf (Gast)


Lesenswert?

Wo ist das Problem?
Setz doch einfach dein ASM-Code in C um...
Fertigen Code wirst du kaum finden, ohne ihn auf dein System anpassen
zu müssen.

Poste doch einfach mal deinen ASM-Code, und was du in C draus gemacht
hast, dann kann dir geholfen werden.

Ralf

von Thomas H. (bayluga)


Angehängte Dateien:

Lesenswert?

Puh, habs dann doch irgendwie geschafft, dass der Apparat irgendwas
anzeigt : ) Habe es jetzt jahre ohne C geschafft, aber wenns halt
komplizierter wird, kommt man mit .asm dann doch nicht mehr so weit.
Ich hab mal den src soweit angehängt und hätte da noch ne Frage oder
zwei an Ralf (und wer auch immer das noch liest):

- Warum wird das erste Zeichen des Textstrings nicht angezeigt?

und

- Wie krieg ichs hin, einen Dezimalwert auszugeben? (z.B. 4stellig)

Konnte für beides keinen Beispielcode finden.

Vielen Dank, Kollegen: )

Thomas.

von Joe (Gast)


Lesenswert?

...Habe es jetzt jahre ohne C geschafft, aber wenns halt
komplizierter wird, kommt man mit .asm...

Mal rein interesse halber, was geht in ASM nicht ?

von Thomas H. (bayluga)


Lesenswert?

Gehen tut natürlich alles. Die Frage ist nur, ob man den Überblick
behält. Aber glaub mir, ich bin der ALLERLETZTE, der Assembler nicht zu
schätzen wüsste : )

von Ralf (Gast)


Lesenswert?

Hi Thomas,

sorry für die späte Rückmeldung.
Zu deinen beiden Problemen:

1. Zeichen fehlt:
Führe doch bitte mal den printf-Befehl zweimal hintereinander aus und
sag Bescheid, ob das erste Zeichen immer noch fehlt.

2. Dezimalzahl ausgeben:
Ich gebe jetzt mal folgendes vor:
- Vierstellige Dezimalzahl heisst, der an die C-Funktion übergebene
Parameter ist ein INT. Also sind maximal 5 Stellen möglich.
Der zweite Parameter gibt die Position an. Du musst jetzt folgendes
machen:
1. Stelle = Zehntausender
Du teilst den int durch zehntausend. Das Ergebnis gibst du auf dem
Display aus. Ist das Ergebnis 0, so gibst du anstatt einer Zahl ein
Leerzeichen aus. Du musst dir merken, ob du eine Zahl oder ein
Leerzeichen ausgegeben hast, damit die nächste Stelle korrekt angezeigt
wird (Tausender), wenn das Teilen dort eine Null ergibt.
Damit sorgst du für eine Unterdrückung der Vorlauf-Nullen.
Und das Schema geht bis hin zu den Einern.

Ich hoffe, ich konnte es verständlich beschreiben.

Bitte um Rückmeldung.

Ralf

von Thomas H (Gast)


Lesenswert?

Hallo, Ralf!
Vielen Dank für Deine Antwort. Tja, also das mit dem fehlenden Zeichen
hat sich erledigt. Und um ganz ehrlich zu sein, hab ich das mit der
Teilerei nicht wirklich verstanden. Kann mann das nicht über modulo
machen? Das "Fehlende Zeichen" war übrigens ein
Cursorsteuerungsproblem. Das Display ist ein 2x16 mit HD44780
(standard) und laut datenblatt hat zeile 1 die adressen 00h bis 0Fh
und zeile zwei geht von 40h bis 4Fh. Ich hab zur Cursorpositionierung
eine Funktion geschrieben, die nicht funktioniert, bzw. funktioniert
sie nur für die 2te Zeile, wenn man statt 40h einfach C0h nimmt. Das
soll einer verstehen. Ich häng den Funktionscode einfach mal an,
vielleicht fällt Dir was dazu ein. Hatte das gleiche Phönomen auch
schon in assembler. Eigentlich ist mir ja egal, ob die 2te zeile jetzt
40h oder C0h "heisst", nur kann ich halt z.b. das 3te zeichen der
1ten zeile ansprechen. Idee dazu? Solange beschäftige ich mal mit der
Teilerei.
Vielen Dank schonmal!

Thomas

von Thomas H (Gast)


Lesenswert?

Achso.. hier die Cursorfunktion : )

void move (int cline, int crow)  // Funktion für Cursorbewegung
{             // move (zeile 1...2, Zeichen 1...16)
    char pos;
    if(cline==1) pos=0x00;
    if(cline==2) pos=0x40;
     pos=pos+crow-1;
    RS=0;RW=0;P2=pos;EN=1;EN=0;
     busychk();
     RS=1;
}

von Ralf A. (warpnine)


Lesenswert?

Also, bezüglich der Sache mit 0x40 und 0xC0, ich hab jetzt leider keine
Zeit, deinen Code zu prüfen, aber vielleicht komm ich am Wochenende
dazu. Allerdings hab ich zwei Links gefunden, die evtl. weiterhelfen
können:

http://ouwehand.net/~peter/lcd/lcd.shtml
http://www.8052.com/tutlcd.phtml

Wegen der Teilerei:

Ja, das was ich geschrieben habe, ist doch MODULO:
Durch 10000 teilen, das Ergebnis wird ausgegeben, wenn es ungleich 0
ist, ansonsten ein Leerzeichen.
Das mit 10000 multiplizierte Ergebnis des Modulo ziehst du von deinem
Wert ab.
Dann kommt genau die gleiche Sache mit den 1000ern, dann die 100er,
usw.

Ralf

von Thomas H. (Gast)


Lesenswert?

Besten Dank für die Links, Ralf. Nach dem Tutorial auf 8052.com müsste
mein Code eigentlich laufen. Obere Zeile also 0x80...0x8F und untere
0xC0...0xCF, aber leider gehts trotzdem nur in der unteren... Wäre
super, wenn Du am WE kurz Zeit dafür fändest. Kannst mir das gerne auch
per mail senden, falls der Thread für "Könner" zu langweilig wird.
bayluga@freenet.de

Grütze,

Thomaas

von Ralf A. (warpnine)


Lesenswert?

Okay, ich guck mal was ich hinkrieg.

Übrigens, kleine Korrektur:

> Ja, das was ich geschrieben habe, ist doch MODULO:
Das ist nicht ganz richtig, ich hab in der Eile Müll geschrieben. Es
ist eine Mischung aus Teilen ohne Rest und Modulo.

Wenn du es nicht hinbekommst, sag Bescheid...

Ralf

von Ralf A. (warpnine)


Lesenswert?

Hi Thomas,

bist du weitergekommen?
Guck mal unter den Artikeln, da gibts auch was zum 44780, vielleicht
hilft dir das auch schon weiter ?!?

Ralf

von Thomas H. (Gast)


Lesenswert?

Hi, Ralf!

Habs erst heute mal wieder Zeit, mich damit zu befassen. Die
Cursorsteuerung funktioniert nach wie vor nur für die untere Zeile, in
der oberen kann ich immer nur 1. Zeichen ansprechen. Ich muß da
irgendwo nen ganz ganz dämlichen Denkfehler drin haben...
Werde noch n bisschen dran rumfrickeln.

Th

von Ralf (Gast)


Lesenswert?

Hi Thomas,

wie läufts denn? Bist weitergekommen?

Wegen deinem Cursor-Problem, ich kenn mich mit den HD44780 nicht so
aus, ich benutze Grafikdisplays mit T6963C-Controller, aber ein Freund
hat gemeint, die Adresse 0x40 für die zweite Zeile ist richtig, aber
das Bit 7 spielt da noch ne Rolle. Und wenn du bei 0x40 das Bit 7
setzt, dann kommt ja 0xC0 raus... Gucks dir mal im Datenblatt an, was
das sein könnte...

Ralf

von Thomas (Gast)


Lesenswert?

Hallo, Ralf.

In der Tat isses so, mit dem C0. Das Bit 7 muss gesetzt sein, damit der
LCD-Controller "weiss", dass das eine Datenposition ist. Du hast das
mit dem 0xC0 richtig erkannt, denn der zu sendende Wert ist immer 80h
(Bit7) + Position. Bei 40h für Zeile 2 Ergibt sich 0xC0. Zeile eins hat
aber "Positionswerte" von 00h..bis..0Fh, also dürfte dann ja Stelle
eins 80h haben, stelle zwei 81h u.s.w. Das klappt aber leider nicht.
Und keiner weiss warum : )

von Ralf A. (warpnine)


Lesenswert?

Hi Thomas,

> also dürfte dann ja Stelle eins 80h haben, stelle zwei 81h u.s.w. Das

> klappt aber leider nicht.

So wie ich es sehe, hast du ja dann eigentlich keinen Fehler mit dem
0xC0, sondern mit dem 0x00, denn ich kann im Datenblatt zum 44780 auf
die schnelle keine Instruktion entdecken, die 0x00 ist...
Erklärs mir bitte nochmal genau, was kommt denn raus, wenn du mit 0x80,
0x81 usw. arbeitest???

Ausserdem ist mir noch was aufgefallen, deine MOVE-Funktion ist so
geschrieben, dass die Zeilenangabe 1 oder 2 sein muss.
Deine Spaltenangabe würde aber 0 als erstes Zeichen der Zeile
akzeptieren. Ist das so beabsichtigt???

Ralf

von Thomas (Gast)


Lesenswert?

Hallo Ralf!
Danke, dass Du Dich so reinhängst!

Hier erstmal die aktuelle move-funktion:

void move (int cline, int crow)  // Funktion für Cursorbewegung
{             // move (zeile 1...2, Zeichen 1...16)
    char pos;
    if(cline==1) pos=0x80;
    if(cline==2) pos=0xC0;
    pos=pos+crow-1;
    RS=0;RW=0;P2=pos;EN=1;EN=0;
    busychk();            // Fkt. prüft busy-flag
    RS=1;
}

Wir sind uns einig, dass der Wert, der den Cursor positioniert sich
zusammensetzt aus: 0x80 (Bit7 High) PLUS der im Datenblatt angegebenen
Konstante für die Entsprechende Stelle (Also 0x00...0x0F für die obere
und 0x40...0x4F für die untere Zeile). Im klartext bedeutet das, dass
der tatsächlich an das  Display zu übermittelnde Wert 0x80...0x8F für
oben und 0xC0...0xCF für unten ist. Das klappt auch. Allerdings nur für
die Zweite Zeile. Das heisst, 0xC2 schiebt den Cursor an Pos. 3 in der
2ten Zeile. Aber in der ersten funktioniert das prinzip  eben nicht.
Egal, welchen wert von 0x80 bis 0x8F ich sende, der Cursor steht IMMER
an 1er Stelle in der 1ten Zeile. Das ist mein Dilemma.

Zu der Frage mit der Spaltenangabe: Zeichen 1 bis 16 einzugeben geht
schon klar, da in der 3. Zeile von unten ja wieder 1 subtrahiert wird.


Thomas.

von Ralf A. (warpnine)


Lesenswert?

> ...da in der 3. Zeile von unten ja wieder 1 subtrahiert wird.
Okay, in deiner LCD2.txt die du gepostet hast, war das noch nicht.

Machen wir das mal Hardcore:
Oben hast du irgendwo erwähnt, dass du Assembler-Code hast, der
funktioniert. Poste bitte mal diesen Assembler-Code, und deine aktuelle
C-Software. Und ich sollte wissen, welchen C-Compiler du verwendest
(Keil?).

Ich wills mir mal auf meinem System angucken.

Ralf

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

Hallo, Ralf.

Nach einer Woche hab ichs endlich mal wieder geschafft, mich mit was
anderem als der Studiererei zu beschäftigen.
Wir machens also mal Hardcore:
Ich hab eben mal lauffähigen assemblercode zusammengekloppt, IDE ist
natöööörlich Keils µV3. Und siehe da: In asm macht der apparat, was er
soll: nämlich den Cursor an die befohlene Adresse setzen. Nur wo ist da
jetzt der unterschied zu meiner C-funktion, die da oben irgendwo
steht???

Grüsse,

Thomas

von Karl heinz B. (kbucheg)


Lesenswert?

> char pos;

Wenn du auf Byteebene arbeitest, dann nimm immer
unsigned char

vor allem wenn du wie hier
pos=pos+crow-1;
Arithmetik machst.

Deine Berechnung könnte man auch kürzer schreiben:

  unsigned char pos;

  pos = 0x80 |                        // Bit 7 für 'Set Cursor'
        ( ( cline - 1 ) << 6 ) |      // Bit 6 fuer Zeile 1 oder 2
        ( crow - 1 );                 // und dann noch die Bits fuer
                                      // die Spalte


Aber das wichtigste: unsigned char, unsigned char, unsigned char!

von Thomas H. (bayluga)


Lesenswert?

Vielen Dank, KH!

Aber leider ist das Resultat das gleiche...
Positionierung Zeile 2 (also move(2,X);) klappt wunderbar, nur Zeile
eins (move(1,X);) will nicht. ganz egal, welchen wert ich für x wähle,
der text beginnt immer in spalte 1. Irgendwie ergibt das keinen
Sinn...

Thomas

von Karl heinz B. (kbucheg)


Lesenswert?

Hmm.
Das ergibt wirklich keinen Sinn.
Eigentlich sollte das so klappen.

Knappes Timing?

von Thomas H. (bayluga)


Lesenswert?

Okay, es geht doch. Das Problem ist jetzt aber: Ich hab das immer
getestet, indem ich die Funktion zwei mal hintereinander aufgerufen
habe und beim ersten mal koordinaten für line1 und in der 2ten funktion
koordination für line2 mitgegeben habe. In etwa so:

....
move(1,3);
printf...;
move(2,4);
printf...;
...

Ich hab das jetzt einfach mal andersrum gemacht, also in etwa so:

...
move(2,3);
printf...;
move(1,3);
printf...;
...

Und es hat sich dabei folgendes herausgestellt: Mit dem der beiden
ersten move-aufruf stimmt was nicht, denn die Daten werden danach immer
an pos 1,1 geschrieben. Muss wohl irgendwie mit ner RS-Vertauschung oder
so zu tun haben. Jedenfalls zweifel ich jetzt nicht mehr an meinem
Verstand sonder nur noch an meiner sorgfalt.

von Thomas H. (bayluga)


Lesenswert?

das fehlende wort lautet *tusch*: ersten!

Mit dem >ERSTEN< der beiden ersten move-aufrufe stimmt was...

von Thomas H. (bayluga)


Lesenswert?

Juhuu! Das Problem mit der Cursoposition ist auf ingenieurs-mässige Art
und Weise gelöst. Nämlich gepfuscht : )
Ich lass halt die move-funktion einmal sinnlos in der
initialisierungssequenz mitlaufen und danach geht das ja dann.
Stellt sich direkt die nächste Frage: Wie ist das mit den Variablen,
die Dezimalwerte enthalten und diese auf dem LCD dargestellt werden
sollen?
Sagen wir mal, eine variable "wert" existiere mit dem dezimalwert
3,14 und ich möchte, daß der dezimale inhalt dieser variable auf dem
lcd ausgegeben wird.
Die Vorgehensweise:

float wert;
void main (void)
{
wert=3,14;
wert=putchar(wert);
printf("%cPi gerundet= ");
printf("%f",wert);
}

bringt's nicht.

Vorschläge werden dankend entgegengenommen   : )

von Karl heinz B. (kbucheg)


Lesenswert?

> printf("%cPi gerundet= ");
Ich denke mal das ist ein Tippfehler beim posten :-)
Muss natürlich
  printf( "Pi gerundet= ");
heissen.


> bringt's nicht.
Was heist das?

Beim gcc, musst du eine andere Library benutzen, wenn du
float Zahlen mit printf ausgeben willst.

Mach ich aber nie, daher weis ich auch nicht auswendig
welche das ist, bzw. wie man die Umschaltung macht.
Stöbere mal im GCC Forum, 'printf' 'Library' 'float'.
Jörg hat das schon öfters erklärt.

von Werner B. (Gast)


Lesenswert?

Da smit dem wert=3,14; klappt nicht, wenn dann musst du 3.14 schreiben.

Du musst erst in einen Buffer schreiben.

char buffer[17]; // dein display ist ja nur 16 lang, also reichen 17
char *cp;
snprintf(buffer, 17, "PI=rund %f", wert);
cp = &buffer[0];  // oder einfacher cp = buffer;

move(1,1);
while(*cp != '\0') {
  putchar(*cp++);
}

von Thomas H. (bayluga)


Lesenswert?

snprint???

von Karl heinz B. (kbucheg)


Lesenswert?

snprintf(): die sichere Alternative zu sprintf.
Man gibt zusätzlich noch die Größe des bereitgestellten
Buffers an. Dadurch ist gewährleistet, dass sprintf
den Buffer nicht überrennt.

Sei C-99 eine Standardfunktion.

von Thomas (Gast)


Lesenswert?

Besten Dank!

sprintf funktionert bestens. Ich durchschau zwar den Mechanismus nicht
wirklich, aber das Resultat zählt.

Cheereo,

Thomas

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.