Forum: Mikrocontroller und Digitale Elektronik Laufschrift auf dem HD44780


von Marcel K. (viewer)


Lesenswert?

Hallo liebes Forum,

ich möchte gerne mit einem HD44780- Display (2x16) einen Lauftext 
erstellen. Leider komme ich nicht weiter :o(
Ich habe einen Text mit 38 Zeichen. Ich habe eine Funktion (in C) die 
schreibt diesen Text auf die 2. Zeile des Displays. Das ganze mach ich 
mit dem Befehl "Display- Shift" (positioniere zuerst an [15/2]). Das 
ganze funktioniert auch so lange bis das 26. Zeichen kommt. Dann wird 
der nachfolgende Text in die 1. Zeile weiter geschrieben. Naja mir ist 
ja schon klar dass irgendwann die DDRAM- Adresse komplett durchgeschoben 
ist und deshalb wird einfach ab den 26. Zeichen in der 1. Zeile 
begonnen. Jetzt ist aber meine Frage, kann ich die Adresse irgendwie 
zurücksetzen auch ohne dass der Text gelöscht wird?
Ich habe es schon über "LCD-RESET" und "LCD-HOME" probiert, allerdings 
wird das Display natürlich gelöscht und ich müsste die letzten 16 
Zeichen noch mal auf das Display schreiben. Das ist nicht wirklich toll.

Hat jemand hier schon mal ein Lauftext auf diesem Display realisiert?
Ich bin über jede Hilfe Dankbar.
Viele Grüße und euch im Forum einen schönen Abend,
Marcel

von Paul B. (paul_baumann)


Lesenswert?

Guck mal hierhin:
http://www.sprut.de/electronic/lcd/index.htm

Dort findet man sehr gut erläutert, wie die RAM-Aufteilung aussieht, 
damit
man die richtige Zeile erwischt.

MfG Paul

von Marcel K. (viewer)


Lesenswert?

Hallo Paul,
vielen Dank für den Link, den habe ich allerdings vorhin schon mal 
"gefunden" als ich nach einer Lösung gesucht habe. Dieser Link hilft mir 
allerdings nicht wirklich weiter da ich ja nicht weiß wie ich vorgen 
soll, wenn bei meinem Beispiel in die 1. Zeile geschrieben wird. Ich 
habe ja das Datenblatt und darin steht bereits dass die 1. Zeile bei 
0x00 und die 2. bei 0x40 beginnt. Ich wollte wissen ob es eine 
Möglichkeit gibt, die Adressen wieder zurückzusetzen ohne das der Inhalt 
auf dem Display gelöscht wird.
Aber trotzdem danke für deine schnelle Antwort.
Gruß Marcel

von Paul B. (paul_baumann)


Lesenswert?

Du könntest den ganzen Text eventuell im RAM des Kontrollers halten,
dortdrin "zurechtmachen" und dann das Ganze auf einen Schlag zum Display
rüberschicken. Wie das in "C" geht, weiß ich aber nicht, -diese Sprache
ist mir zu kryptisch, um sie zu lernen. ;-)

MfG Paul

von Marcel K. (viewer)


Lesenswert?

Hmm, ich denke das wird schwierig! Ich möchte einen Lauftext mit über 
300 Zeichen laufen lassen. Das passt bestimmt nicht in seinem RAM rein 
;o)
Naja, aber trotzdem Danke!!!!
(",)

von Falk B. (falk)


Lesenswert?

@  Marcel K. (viewer)

>allerdings nicht wirklich weiter da ich ja nicht weiß wie ich vorgen
>soll, wenn bei meinem Beispiel in die 1. Zeile geschrieben wird. Ich
>Möglichkeit gibt, die Adressen wieder zurückzusetzen ohne das der Inhalt
>auf dem Display gelöscht wird.

Vergiss die Scrollfunktion im LCD, die hat viel zu enge Grenzen. Mach es 
selber per Controller. ISt auch einfach.

DDRAM Adresse auf 0x00 setzen
8 Zeichen schreiben
DDRAM Adresse auf 0x40 setzen
8 Zeichen schreiben
Datenzeiger im Controller um ein Zeichen weiter setzen
Ein paar Dutzend Millisekunden Warten
Das Ganze von vorn

Das "Warten" macht man sinnvollerweise mit einem Timer-Interrupt

MFG
Falk

von Marcel K. (viewer)


Lesenswert?

Hallo Falk,
danke für deinen Vorschlag. Das hat aber nichts mit einer Laufschrift zu 
tun. Bei eine Laufschrift müsste das erste Zeichen z.b. an (15/1) 
geschrieben werden. Dann beim nächsten mal das erste Zeichen an (14/1) 
und das zweite an (15/1) beim nächsten schreiben das erste Zeichen an 
(13/1), das zwiete an (14/1) und das dritte an (15/1) uns so weiter... 
Wenn ich es so mache wie du es geschrieben hast wäre es ein ganz 
normaler Schreibvorgang.

Grüße Marcel

von Falk B. (falk)


Lesenswert?

@Marcel K. (viewer)

>Wenn ich es so mache wie du es geschrieben hast wäre es ein ganz
>normaler Schreibvorgang.

Lesen bildet.

"Datenzeiger im Controller um ein Zeichen weiter setzen"

MfG
Falk

von Marcel K. (viewer)


Lesenswert?

Hääää, sorry ich hab es anscheinend wirklich nicht "geschnallt" !!!!!!! 
:o(

Wie meinst du das??

Also ich setzte den cursor an (0/0) (das ist ja die Adresse 0, oder?) 
Dann soll ich 8 Zeichen schreiben. Wiso 8 Zeichen?

Falk, es tut mir echt leid aber ich weis echt nicht wie du das meinst. 
Ich sehe bestimmt vor lauter Bäumen den Wald nicht mehr. Könnstest du 
mir etwas auf die Sprünge helfen? Ich wäre über jede Hilfe sehr 
dankbar!!

Grüßer Marcel :.(

von spess53 (Gast)


Lesenswert?

Hi

Bin zwar nicht Falk. Aber was er meint:

-Zeiger auf 1.Buchstaben im Text. Eine komplette Zeile ausgeben.
-Kurz warten
-Zeiger auf 2.Buchstaben im Text. Eine komplette Zeile ausgeben.
-Kurz warten
-Zeiger auf 3.Buchstaben im Text. Eine komplette Zeile ausgeben.
....

MfG Spess

von Kasperle (Gast)


Lesenswert?

Ob Er weiß was ein Datenzeiger ist?

von Falk B. (falk)


Lesenswert?

@  Marcel K. (viewer)

>Also ich setzte den cursor an (0/0) (das ist ja die Adresse 0, oder?)

Ja.

>Dann soll ich 8 Zeichen schreiben. Wiso 8 Zeichen?

Ahhh, das war ein unbewusster halber Denkfehler. Viele 1x16 LCDs werden 
als 2x8 adressiert. Da muss man das so machen.
Bei deinem 2x16 muss man das nicht. Der Rest ist aber identisch.

Im Prinzip ist es einfach. Du willst einen String ala
1
char mein_text[38]"Hallo ich bin eine Laufschrift";

als Laufschrift in die 2. Zeile des LCD bringen. Also musst du beim 
ersten mal die Zeichen 0..15 ausgeben, dann 1..16, 2..17 etc.
Das kann man wie bereits beschrieben in einer Schleife machen, welche 
den Index des ersten Zeichens immer hochzählt. Dann halt bei dir 16 
Zeichen ausgeben, warten, wieder von vorn. Knifflig wird es nur ein 
wenig, wenn das Ende erreicht wird. Will man dann wieder von vorn 
anfangen, gibt es zwei Möglichkeiten.

1.) Man macht den String um soviele Zeichen länger, wie das LCD breit 
ist. Dann kopiert man einmalig die ersten X Zeichen ans Ende, dazu 
bietet C fertige Funktionen. Bei dir hätte dein Sting dann 38+16=54 
Zeichen. Dann lässt man in oben genannter Schleife den Index von 0..37 
laufen, die Anzeige ist immer OK. Wenn sie dann auf 0 zurück springt, 
gibt es einen nahtlosen Übergang.

2.) Man lässt den String wie er ist und prüft bei jedem Zeichen, 
welches, man ausgibt, ob der Index grösser als das zulässige Maximum von 
hier im Beispiel 37 ist. Wenn nein, gibt man das Zeichen aus, wenn ja, 
muss man vorher 37 abziehen, um den richtigen Index zu berechnen. Kann 
man auch per MODULO Operation. die zweite Methode spart etwas Speicher 
für die Daten, braucht dafür etwas mehr Rechenzeit.

MFG
Falk

von Marcel K. (viewer)


Lesenswert?

Hallo Spess,
ich habe es immer noch nicht verstanden, SORRY!!!
Mich würde als erstens interssieren wieso 8 Zeichen. Sind da eventuell 
16 Zeichen gemeint da es sich ja um ein 2x16 Display handelt. als 
zweitens verstehe ich nicht wieso ich nach dem ich an die 1. Zeile 
geschrieben habe (Adresse 0x00) dann als nächstes in die 2. Zeile 
(Adresse 0x40) schreiben soll?

Nach deinem Verfahren:
Wenn ich einen Zeiger auf meinen ersten Buchstaben mache, wo soll diese 
denn dann geschrieben werden? Und dann wohin soll der 2. Buchstaben- 
Zeiger zeigen?

Sorry für das Fragen aber ich stehe echt auf'm Schlauch!!!!

von Marcel K. (viewer)


Lesenswert?

Hallo Falk,

ich war zu langsam!!!

Ich habe's jetzt!!!! Ich werde es ausprobieren!!

Danke erstmal und ich meld mich...

Schönen Abend noch!!!
Marcel (",)

von Marcel K. (viewer)


Lesenswert?

Hallo Falk, (und auch Spess)

Ich wollte Dir noch mal Bescheid geben wie das ganze bei mir ausgegangen 
ist. Ich habe nach deinem Vorschlag vorgestern bis gestern in den 
frühern Morgen "geproggt". Ich habe es mit Deiner Hilfe hinbekommen, 
Vielen Dank. Ich bin mir sicher dass jemand mit etwas mehr Erfahrung das 
ganze etwas komfortabler hin bekommen würde, vielleicht hast du eine 
"Code-optimiertere" Lösung. (Mehr mit Zeiger arbeiten) Auf jeden Fall 
hier mal ein Ausschnitt meines Codes. (Die .c und .h Datei sind hier 
jetzt nicht getrennt)

#define ZEILENLAENGE 16

char displayzeile[ZEILENLAENGE];




// mit dieser Funktion wird die Displayzeile mit "Leerzeichen" gefüllt
void reset_zeile(void)
{
  char i;

  for(i=0; i<ZEILENLAENGE; i++)
  {
    displayzeile[i] = 0x20;
  }

}

// Diese Funktion zählt die Anzahl der Zeichen die in einem String 
enthalten sind
char strleng(char *s)
{
  char n;

  for (n=0; *s != '\0'; s++)
  {
    n++;
  }
  return n;
}


void laufschrift(char zeile, char *text)
{
  char zahl;
  signed char i;  // muss signed sein, da man in der for- Schleife bis 
auf 0 runter muss

  char n =0; // Variable die das aktuelle Zeichen in die Variable 
"displayzeile" schreibt

 char j;

  reset_zeile();
  zahl = strleng(text); // Anzahl der zu übertragenden Zeichen


  for(i=zahl; i>0; i--)
  {
    set_cursor(0,zeile);

    // in dieser Schleife werden die Elemente im Array von hinten nach 
vorne geschoben.
    // Hierbei bekommt das [n-te] Element den Wert vom folgenden [n+1] 
Element.
    for(j=0; j<ZEILENLAENGE; j++)
    {
      displayzeile[j] = displayzeile[j+1];
    }

    displayzeile[ZEILENLAENGE-1] = *(text+n); // Das letzte Element 
bekommt das nächste Zeichen  des übergebenem Text

   lcd_string(displayzeile);

    n++; // erhöhen um das nächste Zeichen zu schreiben
    delay_ms(200);
  }

  // jetzt ist der komplette Text durchgelaufen. Jetzt muss der rest mit
  // Leerzeichen aufgefüllt werden.

  for(i=ZEILENLAENGE; i>0; i--)
  {
    set_cursor(0,zeile);

    for(j=0; j<ZEILENLAENGE; j++)
    {
      displayzeile[j] = displayzeile[j+1];
    }
    displayzeile[ZEILENLAENGE-1] = ' ';
    lcd_string(displayzeile);
    delay_ms(200);
  }



}


Also noch mal vielen Dank für Deine/Eure Hilfe. Hat mir wirklich sehr 
geholfen.

Grüße,
Marcel

von lcd (Gast)


Lesenswert?

hatte da auch mal was gemacht zu meinen Anfängen
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include <util/delay.h>
4
#include <string.h>
5
6
#include <lcd.h>
7
8
#define length 30
9
char sLauftext[length+1];
10
11
char* move_text_left(char* text, uint8_t len)
12
{
13
  char tmp = text[0];  
14
  uint8_t i;
15
16
  for( i = 0; i<len; i++)
17
  {
18
    text[i] = text[i+1];
19
  }
20
  text[len-1] = tmp;
21
  return text;
22
}
23
24
25
void wait (uint16_t zeit) //zeit: wartezeit in ms (0 bis 65536)
26
{
27
   uint16_t i;
28
   for(i=0;i<zeit;i++) _delay_ms(1); //da für _delay_ms max Takt-abhängige Werte erlaubt
29
} 
30
31
int main (void) 
32
{  
33
  char sLauftext[length+1];
34
  uint8_t n;
35
36
  lcd_init(LCD_DISP_ON);
37
  lcd_clrscr();
38
  strcpy(sLauftext,"Dies ist der Lauftext Test    ");
39
  lcd_puts(sLauftext);
40
  n=strlen(sLauftext);
41
  wait(1000);
42
43
while(1)
44
{ 
45
  lcd_clrscr();
46
  strcpy(sLauftext,move_text_left(sLauftext,n)); 
47
  lcd_puts(sLauftext);
48
  wait(200);
49
}
50
51
return 0;           
52
}

die ganzen lcd Funktionen tun ja hier nichts zur sache, geht ja nur um 
das shiften des Textes

von Falk B. (falk)


Lesenswert?

@  Marcel K. (viewer)

Längere Quelltexte bitte als Anhang.

>Vielen Dank. Ich bin mir sicher dass jemand mit etwas mehr Erfahrung das
>ganze etwas komfortabler hin bekommen würde, vielleicht hast du eine
>"Code-optimiertere" Lösung.

Ja, Warum in aller Welt verschiebst du den Text im RAM? Man muss ihn nur 
immer mit neuer Anfangsadresse auslesen.

MfG
Falk

von Stephan (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

also das mit dem Kopieren der zeichen kostet zuviel Zeit!
Im Anhang mal eine Version mit einem Pointer.

Die "Init..." wird einmal aufgerufen, bzw wenn du den Text ändern 
willst.
Die Funktion "Write.." rufst du dann zyklisch auf.

mfg
Stephan

von Frank (Gast)


Lesenswert?

Hallo Marcel K,

kannst du dein Code posten? .c und .h Datei

von Stephan (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

hatte noch was vergessen:
Es musste noch die Pos bei jedem schreiben gesetzt werden.
Jetzt sollte alles klappen.

Stephan

von Marcel K. (viewer)


Angehängte Dateien:

Lesenswert?

@:Frank
Also ich habe Dir mal die zwei Dateien angehängt. Allerdings habe ich 
den Quellcode auch nur aus dem Tutorial  hier im Forum. Ich habe nur die 
Delayfunktion mit in den Code mit reingepackt. Der Inhalt der Dateien 
ist auch nicht aufgeräumt und richtig dokumentiert. Ich komme dieses 
Wochenende auch nicht mehr dazu aber ich möchte unbedingt die hier neu 
erwähnten Vorschläge ausprobieren. Ich weiß also nicht ob es sich lohnt 
diese zwei Dateien zu verwenden.

@ Falk:
 Du hast geschrieben:

Ja, Warum in aller Welt verschiebst du den Text im RAM? Man muss ihn nur
immer mit neuer Anfangsadresse auslesen.

Ich bin mir nicht ganz sicher wie du das meinst. Meinst du ich soll den 
Text, so wie ich ihn in meiner Funktion "laufschrift()" übergeben 
bekomme, direkt an das Display senden ohne ihn in das Array 
"displayzeile" zu schreiben??

@ Stephan:
Danke für deinen "Codeschnipsel" den werde ich ausprobieren so bald ich 
wieder die Gelegenheit dazu habe!!!
Danke!!

Also allen ein schönes Wochenende und viele Grüße,

Marcel

von Frank (Gast)


Lesenswert?

Hallo Marcel,
habe ein bisschen gespielt aber irgendwie fuktioniert nicht! wie sieht 
deine main File aus?
Frank

von Marcel K. (viewer)


Lesenswert?

Hallo Frank,

ich bin noch nicht dazu gekommen. Wird heute bestimmt auch nichts mehr.

In der Main steht auch nur "lcd_init(); Was du aber beachten musst, ist 
dass die Taktfrequenz in der "lcd_hd44780.h" bei "#define XTAL 4000000" 
richtig eingestellt ist. Ich habe in diesem Fall 4MHz.

Vielleicht ist das ja schon das Problem!


Grüße,
Marcel

von Frank (Gast)


Lesenswert?

Hi Marcel vielen Dank,
ok das mit dem lcd_init(); ist klar! aber Datei "lcd_hd44780.h" habe ich 
nicht, ist aus dem Tutorial? oder wo finde ich es?

Gruß

von Karl H. (kbuchegg)


Lesenswert?

Marcel K. schrieb:
>> Ja, Warum in aller Welt verschiebst du den Text im RAM? Man muss ihn nur
>> immer mit neuer Anfangsadresse auslesen.
>
> Ich bin mir nicht ganz sicher wie du das meinst. Meinst du ich soll den
> Text, so wie ich ihn in meiner Funktion "laufschrift()" übergeben
> bekomme, direkt an das Display senden ohne ihn in das Array
> "displayzeile" zu schreiben??

studiere das mal:
1
#include <avr/io.h>
2
#include <lcd.h>
3
4
#define CHARS_PER_LINE  16
5
6
void TextOut( const char* string )
7
{
8
  int nrChars = 0;
9
  
10
  lcd_gotoxy( 0, 0 );
11
  while( nrChars < CHARS_PER_LINE && *string ) {
12
    lcd_data( *string++ );
13
    nrChars++;
14
  }
15
    
16
  while( nrChars++ < CHARS_PER_LINE )   // am Ende mit Leerzeichen auffüllen, falls
17
    lcd_data( ' ' );                    // notwendig, weil der String schon
18
                                        // zu kurz ist
19
}
20
21
int main()
22
{
23
  const char * Text = "Juhu es ist bald wieder Fruehling";
24
  const char * TextTeil;
25
  
26
  lcd_init();
27
  
28
  while( 1 ) {
29
    TextTeil = Text;
30
    while( *TextTeil ) {
31
      TextOut( TextTeil );
32
      TextTeil++;
33
      _delay_ms( 200 );
34
    }
35
  }
36
}

Es gibt keinen Grund da grossartige Texte in der Gegend rumzukopieren.
Es genügt völlig, wenn du der Ausgabefunktion immer nur einen 
veränderten Startpunkt des Textes übergibst.

Die Laufschrift entsteht aus dem Zusammenspiel der inneren while 
Schleife in main() und der speziellen Ausgabefunktion, die ab einer 
gewissen Startposition im Text eine entsprechende Anzahl an Zeichen 
ausgibt.
Man könnte sich jetzt auch noch weiter spielen und dafür sorgen, dass 
der Text auch noch vom rechten Rand hereinscrollt. Am einfachsten ist 
das aber erreicht, indem man im Text einfach eine entsprechende Anzahl 
an Leerzeichen vorsieht.
1
  const char * Text = "                 Juhu es ist bald wieder Fruehling";


lcd_gotoxy ist die Funktion, die den Ausgabecursor an eine bestimmte 
Position setzt.
lcd_data ist die Funktion, die ein einzelnes Zeichen ans LCD ausgibt.
lcd_init sollte selbsterklärend sein

von Marcel K. (viewer)


Lesenswert?

@ Frank:
Ich habe dir leider die falschen Dateien geschickt. Ich habe hier 
bereits versucht die richtigen Dateien hochzuladen allerdings geht das 
im Moment nicht, keine Ahnung wieso. Teil mir einfach deine 
E-Mailadresse mit und dann kann ich dir die zwei Dateien schicken.
(Oder du schickst mit als registrierter User hier im Forum eine 
Nachricht, das ist sicherer....)


@Karl Heinz:
Vielen Dank für deine Antwort, ich werde dies auf jeden Fall 
ausprobieren sobald ich die Zeit dafür finde, DANKE!!!

Viele Grüße,

Marcel

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.