Forum: Mikrocontroller und Digitale Elektronik Zeiger auf mehrere lange Strings im Flash


von Heinz (Gast)


Lesenswert?

Hallo!
Ich muss viel Text auf einem Display ausgeben. Dazu habe ich mehrere 
über 1000 Zeichen lange Strings im Flash (PROGMEM) meines Atmega168.
Ich möchte nun den Text scrollen, brauche also einen Zeiger auf die 
aktuelle Position im Flash, ab der dann ausgegeben wird.

Ich möchte der Ausgaberoutine übergeben, ab welchem Buchstaben sie den 
Text darstellen soll. Diese soll dann soviel text wie möglich auf einem 
Bildschirm darstellen und zurückgeben, wo der nächste Ausgabebildschirm 
beginnt. Einfach abzählen geht leider nicht, da u.A. Zeilenumbrüche im 
Text sind.

Vorher müsste ich noch auswählen, welches "Kapitel", also welcher 
Strings angezeigt werden muss.

Wie kann ich das machen?

von Karl H. (kbuchegg)


Lesenswert?

Heinz schrieb:
> Hallo!
> Ich muss viel Text auf einem Display ausgeben. Dazu habe ich mehrere
> über 1000 Zeichen lange Strings im Flash (PROGMEM) meines Atmega168.
> Ich möchte nun den Text scrollen, brauche also einen Zeiger auf die
> aktuelle Position im Flash, ab der dann ausgegeben wird.

Soweit richtig

> Ich möchte der Ausgaberoutine übergeben, ab welchem Buchstaben sie den
> Text darstellen soll. Diese soll dann soviel text wie möglich auf einem
> Bildschirm darstellen und zurückgeben, wo der nächste Ausgabebildschirm
> beginnt. Einfach abzählen geht leider nicht, da u.A. Zeilenumbrüche im
> Text sind.

Dann muss die Ausgaberoutine sowas wie eine rudimentäre Screenverwaltung 
machen um festzustellen, wann der Screen voll ist.
Das sind:
* Zeichen mitzählen um zu wissen, wann ein erzwungener Umbruch erfolgen 
wird
* Umbrüche mitzählen

Kommt die Ausgaberoutine zur Erkentnis, das mit dem nächsten Zeichen 
seine eigene virtuelle Cursorposition unter den sichtbaren Bereich 
fällt, dann hört sie auf auszugeben und liefert die aktuelle 
Flashposition als Returnwert. Ist der String zu Ende, liefert sie NULL

Ist doch nicht so schwer. Ein bischen mitzählen und sich das Zeichen 
ansehen, ehe es zum Display geschickt wird.

Der Fall "runterscrollen" ist leicht.
Interessanter ist der Fall: raufscrollen.

von Detlev T. (detlevt)


Lesenswert?

Hallo Heinz,

Welcher Compiler? avr-gcc?

Warum machst du das nicht mit Zeigern? Aufruf der Routine mit Zeiger auf 
das erste auszugebende Zeichen, Rückgabe eines Zeigers mit dem nächsten 
auszugebenden Zeichen. Der wird dann beim nächsten Aufruf verwendet.

Eventuell Rückgabe von "nil" als Signal, dass der String komplett 
ausgegeben wurde.

Gruß, DetlevT

von Heinz (Gast)


Lesenswert?

Ich würde das schon gerne mit Zeigern machen, weiß aber eben nicht wie.
Die Erkennung ob der Bildschirm voll ist klappt schon. Ist ein 
Grafikdisplay und wird dort gleich mit erledigt.
Die Frage ist eben wie ich die Zeiger machen soll (global?) damit ich 
damit auf einen String im Flash zeigen und den Zeiger weiterschalten 
kann...

von Karl H. (kbuchegg)


Lesenswert?

Heinz schrieb:
> Ich würde das schon gerne mit Zeigern machen, weiß aber eben nicht wie.
> Die Erkennung ob der Bildschirm voll ist klappt schon. Ist ein
> Grafikdisplay und wird dort gleich mit erledigt.
> Die Frage ist eben wie ich die Zeiger machen soll (global?) damit ich
> damit auf einen String im Flash zeigen und den Zeiger weiterschalten
> kann...

Ähm
1
const char * DrawOneScreen( const char * Text )
2
{
3
  while(  noch Zeichen auszugeben sind und der Screen noch nicht voll ist ) {
4
    male Zeichen hin
5
    ++Text;
6
  }
7
8
  // warum wurde mit der Ausgabe aufgehört
9
  //
10
  // Weil der Text zu Ende ist?
11
  if( nächstes auszugebendes Zeichen != '\0' )
12
    return NULL;
13
14
  //
15
  // Nö, weil kein Platz mehr war. Einen Pointer auf die Stelle im Text
16
  // liefern, die nicht mehr ausgegeben werden konnte, und ab der es weiter
17
  // gehen soll
18
  //
19
  return Text;
20
}

und beim Aufruf
1
  ...
2
  const char* Text1 = "ein langer langer Text,\n"
3
                      "mit dem die Ausgaberoutine\n"
4
                      "umgehen können soll."
5
6
7
  ....
8
9
  const char* ScrollText;
10
11
  ....
12
13
14
  ScrollText = Text1;
15
  while( ScrollText ) {
16
    ScrollText = DrawOneScreen( ScrollText );
17
    if( ScrollText != NULL )
18
      Warte auf Benutzer, der das Zeichen zum Weiterscrollen gibt
19
  }
20
21
  ...

von Nobody (Gast)


Lesenswert?

Heinz schrieb:
> Die Frage ist eben wie ich die Zeiger machen soll (global?)

Pusten.

von Heinz (Gast)


Lesenswert?

Das Problem ist dass ich die Zeichenketten im Flash speichern muss also

const char Text1[] PROGMEM = "123...";

und da weiß ich eben nicht wie mit Zeigern umgehen...

von Nobody (Gast)


Lesenswert?

Heinz schrieb:
> da weiß ich eben nicht wie mit Zeigern umgehen...

Das ist halt das frustrierende an Deiner Fragestellung: Wir wissen nicht 
und können nicht wissen was Du mit "umgehen" meinst. Dir hier erstmal 
eine Einführung in Zeiger zu geben habe zumindest ich keine Lust. Dafür 
gibt es Bücher.
Von den verbleibenden, nicht-trivialen Möglichkeiten gibt es soviele das 
die wiederrum ganze Bücher füllen könnten. Im allgemeinen leitet man 
sich die auch aus den Grundlagen her. Was also, verd... nochmal, ist 
konkret Dein Problem?

von Falk B. (falk)


Lesenswert?

@  Heinz (Gast)

>Das Problem ist dass ich die Zeichenketten im Flash speichern muss also

>const char Text1[] PROGMEM = "123...";

Das const kannst du weglassen, bringt nix.

>und da weiß ich eben nicht wie mit Zeigern umgehen...

Dann musst du ein C-Buch lesen, dort steht das drin. Und wird 1:1 auch 
auf dem AVR so angewandt. Naja, nicht ganz, der Typ ist dann halt PGM_P 
anstatt char*. Aber das macht vom logischen Gebrauch keinen Unterschied.

MFG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Und im Zweifel gibt es dann immer noch das AVR-GCC-Tutorial das einen 
ganzen Abschnitt über den Flash Speicher und wie man ihn benutzt bietet.

Mit dem Wissen und dem Studium von zb der dort angegebenen Funktion 
uart_puts_p schreibt man sich dann als Ausgangspunkt ganz fix eine 
Ausgabefunktion für Texte, basierend auf einer Ausgabefunktion für 
einzelne Nicht-Flash-Zeichen, die man eh schon hat
1
void drawText_p( PGM_P flashText )
2
{
3
  char c;
4
5
  c = pgm_read_byte( flashText++ );
6
  while( c != '\0' ) {
7
    drawChar( c );
8
    c = pgm_read_byte( flashText++ );
9
  }
10
}

teste die und baut sie dann zur Scroll Maschine aus.

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.