Forum: Compiler & IDEs Pointer auf Strings im FLASH?


von Astro N. (astronookie)


Lesenswert?

Hallo,
vielleicht kann mir jemand bei folgendem Problem helfen. An meinen
ATMEGA 128 habe ich ein LCD-Display angeschlossen, und in C die
Funktion Send_Data_2_LCD(char*) geschrieben, die das senden von Daten
an das LCD erleichtern soll. Der Funktion wird beim Aufruf ein Pointer
mit uebergeben, welcher auf eine Adresse im FLASH zeigt, wo dann die
entsprechende Zeichenkette stehen soll.

Der folgende Code funktioniert aber leider nicht:

main()
{
  static char Zeichenkette1[] PROGMEM = "Hallo Welt";
  :
  :
  Send_Data_2_LCD(Zeichenkette1);
  :
  return;
}

void Send_Data_2_LCD(char* Pointer)
{
  char* temp = Pointer;
  do
  {
    SPDR = *temp;
    :
    :
    ++ temp;
  } while(!temp);
  return;
}

Irgendwie geht beim Funktionsaufruf die Information verloren, wo der
Pointer hinzeigen soll, -RAM oder FLASH-.

Hat jemand eine Idee, wie man das realisieren kann.


Gruesse AstroNookie

von Danyo (Gast)


Lesenswert?

Hi!

Ich geb dir mal ne UART-Funktion:

const char pgmStartString[] PROGMEM = "ATmega32 online!";

int main (void)
{
   char cUseBuffer[30];

   UART_TxStr(strcpy_P(cUseBuffer, pgmStartString));
}

void UART_TxStr(unsigned char *p_pucString)
{
  while(*p_pucString!=0)
  {
     outp(*p_pucString, UDR);
     loop_until_bit_is_set(UCSRA, UDRE);
     p_pucString++;
  }
}

Kannst du dann für's LCD adaptieren.

Gruß Danyo

von Astro N. (astronookie)


Lesenswert?

Hallo Danyo,
vielen Dank fuer die schnelle Antwort. Wenn ich das richtig
interpretiere, dann kopierst Du zuerst den String ins RAM, und
uebergibst dann einen Pointer, der ins RAM zeigt.
Daran habe ich auch schon gedacht! :-)

Das ist sicherlich eine Moeglichkeit, wie man das eigentliche Problem
umgehen kann. Aber gibt es denn nicht eine Loesung, wie man den Pointer
der in das FLASH zeigt "richtig" uebergeben kann? Im Prinzip muesste
das was AVR-spezifisches sein, da ja der AVR eine Harvard-Architektur
hat, und die Daten vom Program-Code getrennt sind. Hmmmmmm???

Vielen Dank nochmals Danyo

Beste Gruesse
AstroNookie

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

(Warum machst du gleich zwei Threads auf?)

Du müsstest eine putchar-Routine schreiben, die die Bytes
einzeln aus dem ROM holt und ausgibt.

von Astro N. (astronookie)


Lesenswert?

Hallo Joerg,
das mit den zwei Threads war keine Absicht, und da ich nicht weiss, wie
man einen Thread loeschen kann, gibt es nun dummerweise zwei Threads,
sorry. Falls es eine Moeglichkeit gibt den Thread zu loeschen, dann bin
ich ganz Ohr. :-)

Nochmal zum Thema, wie soll die routine putchar das Problem loesen? Was
ich moechte ist eine Funktion, der ich einen Pointer mit auf den Weg
gebe, der in das FLASH zeigt. Aber bislang habe ich so etwas noch nicht
gefunden.

Gruss
AstroNookie

von Astro N. (astronookie)


Lesenswert?

Komisch,
jetzt wurde die Antwort auf den letzten Beitrag schonwieder 2 mal
gesendet. Ich habe keine Ahnung woran das liegt???

Gruss
AstroNookie

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Machst du vielleicht Doppelklicks auf den Sende-Knopf?

von Astro N. (astronookie)


Lesenswert?

Ich klick nur einmal auf Submit!!!

Vielleicht prellt ja meine Maus ;-)    (Kleiner Scherz am Rande)

Gruss
AstroNookie

von Danyo (Gast)


Lesenswert?

Du kannst es von mir aus auch mit einem Pointer auf ein einzelnes
Zeichen machen, aber das wär mir zu umständlich...

const char pgmStartString[] PROGMEM = "ATmega32 online!";

for (int i=0; i<sizeof(pgmStartString); i++) {
      UART_TxChar(pgm_read_byte(&pgmStartString[i]));
}

von Astro N. (astronookie)


Lesenswert?

Hallo Danyo,
ja, das sieht etwas umstaendlich aus, sollte aber auch funktionieren.
Vielen Dank fuer deine echt hilfreichen Kommentare.

Gruesse zurueck
AstroNookie

von Frank Wallenwein (Gast)


Lesenswert?

Hallo Danyo,

prinzipiell ne gute Idee. Nur eins scheint mir hier nicht ganz zu
stimmen.

> const char pgmStartString[] PROGMEM = "ATmega32 online!";
> for (int i=0; i<sizeof(pgmStartString); i++) {


sizeof(pgmStartString) liefert Die die Länge des Pointers zurück.
Du brauchst aber die Stringlänge  -  also strlen()
Da strlen() aber nur im RAM geht, bräuchtest Du hier strlen_P()

von A.K. (Gast)


Lesenswert?

pgmStartString ist ein Array, kein Pointer, daher passt sizeof().

von Frank Wallenwein (Gast)


Lesenswert?

A.K. - Da hast Du recht !  - Sorry.
Frank

von Volker (Gast)


Lesenswert?

Hallo,

Stichwort pgm_read_byte

 void displayausg (const prog_char *txt)
  {
    //wenn Pointer auf Flash zeigt

      data2lcd (pgm_read_byte(txt));
  }

Volker

von Astro N. (astronookie)


Lesenswert?

Hallo alle,
vielen Dank für eure zahlreichen Tipps. Die ideale Lösung hab ich jetzt
gefunden. Ich kopiere zuerst die Zeichenkette vom FLASH ins RAM, und
übergebe der Funktion einen Pointer, welcher ins RAM zeigt. Zudem habe
ich noch folgenden Define eingefuehrt, damit der Funktionsaufruf noch
etwas uebersichtlicher wird.
   :
   #define Send(x) (Send_String_2_LCD(strcpy_P(StringInRAM, (x))));
   :
Der Funktionsaufruf vereinfacht sich dann zu
   :
   Send(T_Init);
   :
mit T_Init gleich
   :
   char T_Init[] PROGMEM =  "Dieser Text steht im FLASH";
   :
Die eigentliche Funktion die aufgerufen wird, sieht dann so aus.
   :
   void Send_String_2_LCD(char* Pointer)
   {
  char* P_temp = Pointer;
  char temp;

  while(*P_temp != 0)
  {
    SPDR =  temp;
    do {} while(!(SPSR & (1<<SPIF)));
    ++P_temp;
  }
  return;
}

Die Variante, die Zeichenkette direkt ins RAM zu legen geht auch, aber
warume wertvollen RAM speicher verschwenden, wenn man einen 128KB
Speicher hat.

Viele Gruesse,
und Danke

AstroNookie

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.