C Lauftschrift auf einem LCD 2 x 20

Janiiix3

Aktives Mitglied
28. Sep. 2013
1.333
10
38
Hannover
Sprachen
  1. ANSI C
  2. C#
Hallo,

bekomme es leider nicht hin, den ganzen Text auf der ersten Zeile darzustellen. Er wird nach 20 x hin und her ja schließlich auf die zweite Zeile gesetzt. Wie kann ich das geschickt umgehen ? und dafür sorgen das der Text auch von links eingeschoben wird und nach rechts raus?



CodeBox C
void laufschrift(char *s)
{
     static uint8_t last = 0;
     static uint8_t x = 0;

     if (Time.spam_ms >= 250)
     {
       Time.spam_ms = 0;
       last = x;
       lcd_gotoxy(x,0);
       lcd_puts(s);
       lcd_gotoxy(last-1,0);
       lcd_putc(' ');
       x++;
     }
    
     if (x >= 20)
     {
       x = 0;
       last = 0;
     }
  
}


Ich muss ja irgendwie die Adresse von dem letzten Zeichen raus finden und verrechnen?!
 
Zuletzt bearbeitet:
Es gibt hier sicherlich x Möglichkeiten.

Ich würde mir die Funktion lcd_puts anschauen und hiervon eine Variante erstellen, mit einem weiteren Parameter, der die maximal auszugebenden Zeichen festlegt.

Aufruf so in etwa:
lcd_puts_max(s, 20-x)

In der Funktion gibst du die Zeichen solage aus, bis zum Stringende, jetzt aber neu zusätzlich: maximal so viele Zeichen, bis das Zeilenende des LCD erreicht ist (also 20-x Zeichen). Also vorher abbrechen, wenn das Zeilenende erreicht wird. Am besten baust du dort auch gleich ein, dass Zeichen von 0 bis x-1 "gelöscht" werden (putc(" ")). Bei dir funktioniert das lcd_gotoxy(last-1,0) nicht richtig, wenn last=0 ist.

Wenn du mal die String-Länge benötigst, kannst du strlen(s) verwenden (<string.h>).
---

Die "Zeitabfrage" würde ich in der aufrufenden Routine/Funktion machen, so dass die eigentliche Funktion für die Laufschrift nicht ständig aufgerufen wird.
(gehört nun nicht direkt zur Frage)


CodeBox C
if (Time.spam_ms >= 250)
{
  Time.spam_ms = 0;
  laufschrift(meinstring);
}


Dirk :ciao:
 
Hallo Dirk, was genau meinst du mit 20-x? 20 die maximale Zeichen Anzahl und x die Zeichen die der string enthält?
 
was genau meinst du mit 20-x? 20 die maximale Zeichen Anzahl und x die Zeichen die der string enthält?

Nein, x die aktuelle Spaltenposition vom LCD und 20 ist die Anzahl der Spalten. Das LCD hat ja 2 Zeilen 20 Spalten.

In deiner Funktion, verwendest du ja x um den Adresszeiger zu setzen lcd_gotoxy(x,0) und inkrementiertst es immer um 1.

Wenn x nun zum Beispiel 5 ist, dann darfst du maximal noch 15 Zeichen (20-5) ausgeben. (Wenn du weiter über das Zeilenende Zeichen ausgibst, erscheinen ggf. irgendwann Zeichen in der zweiten Spalte, je nach verwendetem LCD Controller).
 
Okay, soweit scheint es zu funktionieren.
Wie bekomme ich es hin, dass die "Leerzeichen" automatisch eingefügt werden?

/* hier der aufruf */


CodeBox C
scroll_lcd_left(20,"                    Hallo");


/* hier die funktion */


CodeBox C
void scroll_lcd_left(const uint8_t disp_width,char *MESSAGE)
{
  static int s_nPosition = 0;
  int i;

   const uint8_t mesg_lenght = strlen(MESSAGE);

   if (Time.spam_ms >= 200)
   {
     if(s_nPosition < (mesg_lenght - disp_width))
     {
       for(i = 0 ; i < disp_width ; i++)
       {
         lcd_gotoxy(i, 0);
         lcd_putc(MESSAGE[s_nPosition + i]);
       }
     }
     else
     {
       int nChars = mesg_lenght - s_nPosition;
  
       for(i = 0 ; i < nChars ; i++)
       {
         lcd_gotoxy(i, 0);
         lcd_putc(MESSAGE[s_nPosition + i]);
       }

       for(i = 0 ; i < (disp_width - nChars) ; i++)
       {
         lcd_gotoxy(nChars + i, 0);
         lcd_putc(MESSAGE[I]);
       }
     }

     s_nPosition++;
     
     if(s_nPosition >= mesg_lenght)
     {
       s_nPosition = 0;
     }   
     
     Time.spam_ms = 0;   
   }
}

Also außerhalb der Routine funktioniert diese Variante. Innerhalt der Routine natürlich nicht, weil sie mehrmals aufgerufen wird bis alle Zeichen durch das Display gehuscht sind. Daher wird auch die for Schleife öfter aufgerufen und schiebt die Zeichen sonst wo hin.


CodeBox C
[/I]
    STRING_1 = "HALLO";
  for (uint8_t x = 0 ; x < (strlen(MESSAGE) + 20) ; x++)
   {
     if (x < 20)
     {
       VRAM[x] = ' ';
     }
     else
     {
       VRAM[x] = MESSAGE[x - 20];
     }
   
   }
[I]
[/I]
 
Zuletzt bearbeitet:
Moin Dirk,

Nein, habe es mir noch nicht weiter angeschaut, also bin nicht weiter gekommen. War ja nur mal so aus "fun" zu wissen ob das noch einfacher zu lösen ist als mit "Leerzeichen" im String zu arbeiten.
Hättest du ne Idee, wie man das in der Funktion lösen könnte?
 
Hi Janiiix,

ich habe mir deinen Code noch nicht genauer angesehen, ganz verstehe ich den nicht, das liegt aber eher auch daran, dass ich noch nicht so die Zeit gefunden habe. Über die Feiertage kann ich mir das aber mal ansehen, ich habe auch eine Idee wie ich es lösen würde. Vielleicht hat ja ein anderer Benutzer im Forum Lust, sich dem "Problem" auch anzunehmen :cool::D

Dirk :ciao:
 
Ohne jetzt auf den Code einzugehen…

Es gibt viele verschiedene Displays. Einige haben mehr VRAM als benötigt wird, beispielsweise 32 Byte pro Zeile bei 20 Zeichen pro Reihe. Die haben denn auch Befehle zum Schieben. Du schreibst also quasi "off-screen", also in den nicht sichtbaren Bytes und sendest den Befehl zum verschieben. Ob das eventuell beide Zeilen gleichzeitig betrifft… kA, nie probiert.

Leerzeichen musst du immer senden, du musst ja den "dirty" Bereich löschen. Aber ein Leerzeichen reicht hier, es muss nicht die komplette Zeile geschrieben werden.
Beispiel: (- sind leerzeichen)
----Test
---Testt
--Testtt
Also musst du nur ein Leerzeichen am Ende anfügen.
----Test
---Test-
--Test--
Vorausgesetzt natürlich du schiebst nur immer um 1 Zeichen. Wenn 2 dann halt eben 2 Leerzeichen usw..

Ganze Zeile schreiben geht selbstverständlich auch, dauert nur etwas länger.
 
Moin TommyB,

das mit dem Schieben von rechts nach links, funktioniert! Auch mit dem löschen. Es bleiben keine "dirty" Bytes auf dem Display.
Was ich nur nicht so ideal finde ist, dass ich im String "---------------Hallo" (- = Leerzeichen) eingeben muss damit er rechts anfängt.
Ich wollte in der Routine das mit einbauen das er Automatisch je nach Größe des Displays die Leerzeichen vorne anstellt.
Verständlich?
 
Im String brauchst du das ja auch nicht.
Schreib dir einfach eine Routine, nennen wir sie Cls1 (für Zeile 1), Cls2 (für Zeile 2), …
Darin schreibst du die ganze Zeile mit Leerzeichen voll. Die Laufschrift geht ja schon, dann wärste schon fertig.
 
Im String brauchst du das ja auch nicht.
Schreib dir einfach eine Routine, nennen wir sie Cls1 (für Zeile 1), Cls2 (für Zeile 2), …
Darin schreibst du die ganze Zeile mit Leerzeichen voll. Die Laufschrift geht ja schon, dann wärste schon fertig.

Indem ich in meinem String "---------------Hallo" eingebe, steht "Hallo" quasie an 16 Stelle, daher fängt die Schrift von rechts an bis sie komplett links raus ist. Würde ich jetzt einfach nur eine Routine haben, womit ich mir 20 Leerzeichen ins Display schreibe, würde ich die einfach wieder überschreiben.
Ich muss innerhalb des Strings die "Leerzeichen" generieren.

Sprich sieht mein String so aus -> "Hallo", müsste er innerhalb der Routine zum schieben dann so aussehen -> "---------------Hallo"
 
Hindert dich doch keiner daran vorher mit lcd_gotoxy an die richtige Stelle zu springen ?!
Also:
* Zeile löschen (Cls1)
* gotoxy an die richtige Position
* "Test" schreiben
* schleife:
** gotoxy
** "Test-" schreiben
* (schleifen ende)
 
Wenn ich jedes mal an x Position gehen möchte, dauert das ja auch ne gewisse Zeit bis er die Befehle verarbeitet hat. Viel effektiver wäre es doch wenn ich einfach die leerzeichen in meinem String mit einbauen würde...
 
Nunja, Ansätze gibt's viele.
Kommt ja auch immer darauf an, was das Programm/Projekt sonst noch so könne soll.
Die grundsätzliche Zeichenroutine müßte also die einzelnen Zeichen eines Strings (zeichenweise) nacheinander an das Display ausgeben. Also solange bis das Display (Zeile) voll ist, mit der zusätzlichen Abbruchbedingung, daß das zu sendende Zeichen NULL wäre (sind doch nullterminierte Strings, oder?)
Diese Methode ergänzt man um einen Offset - je nach Vorzeichen wirkt der sich entweder auf die Startadresse im String, oder im Display aus (quasi dort das Cursorsetzen).
Nun kann man optional noch miteinbauen, daß alle anderen Zeichen der Zeile gelöscht werden sollen. In Drei Phasen. Cursor im Display auf Anfang. Offset-viele Leerzeichen schreiben (wenn er positiv ist). Den String schreiben (beginnend mit |Offset|, wenn er negativ war - bis NULL). Leerzeichen Schreiben. Das ganze natürlich wieder Zeichenweise, Displayzeile=voll als Abbruchbedingung.
Ließe sich dann noch weiter ausbauen, daß es nur einen Teilbereich einer Zeile betreffen soll...
Ruft man das ganze mit wachsendem/schrumpfendem Offset wiederholt auf, hat man'n Lauftext.
 
Wenn ich jedes mal an x Position gehen möchte, dauert das ja auch ne gewisse Zeit bis er die Befehle verarbeitet hat. Viel effektiver wäre es doch wenn ich einfach die leerzeichen in meinem String mit einbauen würde...
Da irrst du gewaltig.
Die Position zu verändern dauert genau so lange wie ein einzelnes Zeichen zu schreiben. Da du bei "----------------Test" an 16. Stelle anfängst zu schreiben sind das somit 15x mehr als ein gotoxy. Von den ganzen Wartezyklen die der Controller durchlaufen muss mal abgesehen bläht es den Code auf und macht es unübersichtlicher (Anzahl der Leerzeichen wirklich richtig? etc.) Außerdem, vielleicht möchtest du ja irgendwann mal mit "-------------------T" anfangen…
 
ich jedes mal an x Position gehen möchte, dauert das ja auch ne gewisse Zeit bis er die Befehle verarbeitet hat.
??
Der Cursor des Display-RAM zeigt immer auf irgendeine Adresse. Schreibst Du ein Byte als "Daten", wird das korrendespondierende ASCII (*) dort hingeschrieben (und somit auf dem Display sichtbar), und der Cursor autoinkrementiert.
Soll ein Zeichen an einer "anderen" Position erscheinen, muß der Cursor dorthin platziert werden. Dazu muß ein bestimmtes Kommandobyte (word?) als "Instruktion" an's Display gesendet werden, gefolgt von der Zellenadresse.

Ohne geht's nicht wirklich (abgesehen von Spitzfindigkeiten, wie mit autoinkrement solange durch den DisplayRAM rauschen, bis der irgendwann übergalaufen ist, und man an der richtigen Stelle steht - oder alles mit RESET zurücksetzen...

(*) bzw das, was in der Zeichentabelle des Displays steht
 
Dazu muß ein bestimmtes Kommandobyte (word?) als "Instruktion" an's Display gesendet werden, gefolgt von der Zellenadresse
1 Byte, zumindest bei allen Displays die ich kenne. Die ersten Bits definieren den Befehl, die Nachfolgenen Bits die Position. Wartedauer ist auch identisch zum zeichnen eines Bytes (zumindest nahezu, müsste ich jetzt selber nachschaun, viel anders wars aber nicht).
 
Wenn ich jetzt das "H" vom "Hallo" an der 21 Stelle schreiben möchte, ist es ja außerhalb des Display´s, das heißt der Display Controller fängt in der zweiten Zeile wieder an zu schreiben und haut mir dort das "H" rein. Also würde es mit gotoxy doch nicht wirklich funktionieren oder irre ich mich?

P.S

Das "H" soll am Anfang auch nicht sichtbar sein, soll quasie reingeschoben werden.
 
Sollst ja auch nicht bei 21 anfangen sondern bei 20.
Aber bei einigen Displays geht es auch so, da die die besagten Übergänge haben, sagen wir 32 Bytes für 20 Zeichen. Da könntest du das komplette Test an Position 21 schreiben und dann dem Display sagen verschiebe nach links.
Wenn das Display die Funktion nicht hat musst du das so machen wie jetzt. Aber eben ab 20, nicht 21
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)