AVRGCC und Programmspeicher

Hallo NG,

ist zwar kein direktes Elektronikproblem aber vielleicht kann mir trotzdem jemand mit einem C-Problem mit dem AVR-GCC Compiler helfen.

Ich habe, wie in der Beschreibung zur AVR-Lib vorgeschlagen mehrere Textarrays im Programmspeicher definiert und dann die Adressen in einem weiteren Array "text[]" zusammen gestellt.

const char TXT_M00[] PROGMEM =3D "Menueintrag 1\0"; const char TXT_M01[] PROGMEM =3D "Menueintrag 2\0"; const char TXT_M02[] PROGMEM =3D "Menueintrag 3\0"; const char TXT_M03[] PROGMEM =3D "Zuruck\0"; //...

PGM_P text[] PROGMEM =3D {TXT_M00, TXT_M01, TXT_M02, TXT_M03 //... };

Mit der Funktion

void print(const char *ptr) { uint8_t c; while((c=3DPRG_RDB(ptr++)) !=3D '\0') lcd_write(c, 1); }

kann ich nun mit dem Aufruf z.B.

print(text[2]);

den gew=FCnschten Text im Display ausgeben.

-Das funktioniert auch wunderbar!-

Nun m=F6chte ich eine Funktion schreiben, mit der ich den Text, den ich im Display ausgeben m=F6chte, zur Laufzeit bestimmen kann und nicht bei der der auszugebende Text bereits w=E4hrend des Kompilierens bekannt ist.

Mein erster Versuch, die vorhande Funktion zu nutzen:

uint8_t i; i=3D2; print(text[i]);

funktioniert nicht. Also "baue" m=F6chte ich mir was Neues: Der Prototyp sollte etwa wie folgt aussehen

CText(uint8_t n);

=DCber 'n' teile ich der Funktion mit welchen Text ich ausgeben m=F6chte. Der Aufruf k=F6nnte dann z.B. so aussehen:

uint8_t i; for(i=3D0; i

Reply to
Artur
Loading thread data ...

volatile * const char Text

sei ein Text mit maximal 20 zeichen, für eine Zeile also, und dann kannst du das in das Display kopieren. Wenn ein anderer Text gesendet werden soll, kann man einen anderen Zeiger verwenden

Gruss

Robert

Reply to
R.Freitag

Hallo Robert,

st du

.=2E.das habe ich jetzt nicht ganz verstanden :-(

Meinst Du ich soll die einzelnen strings als "volatile zeiger" definieren? K=F6nntest Du mir evtl. ein Beispiel geben?

Gru=DF,

Artur

Reply to
Artur

Wie ist PGM_P definiert? Wenn man es ausschreibt sollte es const char (*text)[] sein (Array von Zeigern), eigentlich wird das durch die Operatorpr=E4zedenz schon so festgelegt. Ich w=FCrde das sowieso anders machen:

typedef char *cstr; const cstr TXT_M00 =3D "Menueintrag 1\0";

usw.

Das Verwenden eines Zeigers statt Arrayklammern funktioniert, da fest einkompilierte Strings ohnehin irgendwo im Programmspeicher kleben und nur die Adresse der Strings in der Zeigervariable landet und ein Array ist effektiv auch nix anderes als eine Zeigervariable, mit dem Unterschied, dass bei einem Array nicht notwendigerweise alle Elemente initialisiert werden. In C++ (nicht in C) gibt es zwar ein paar winzige Unterschiede, die in der Praxis aber so gut wie nie auftreten, da die Syntax und Funktionalit=E4t davon nicht betroffen ist, es =E4ndert sich vor allem das Compilerverhalten bzgl. Speicheralloziierung und Optimierung.

Ausserdem sollte der Zeiger konstant sein, der Inhalt darf sich ruhig =E4ndern, solange man nicht =FCber die Grenzin hinaus schiesst. Wenn man aber den Zeiger irgendwie verschustert ist Ende Gel=E4nde.

Mit obigem Typedef kann man dann schreiben

cstr const text[]=3D{TEXT_M00, TEXT_M01} usw.

Wolfgang Draxinger

--=20

Reply to
Wolfgang Draxinger

Also,

man hat mehrere Strings, die im Speicher stehen. Einer davon soll angezeigt werden. Auf jeden der Strings zeigt ein Zeiger, der auf char zeigt. Mein im obigem Postiung genanntes Beispiel zeigt einen konstanten Zeiger, besser wäre hier ein konstanter Zeiger auf eine Textkonstante, zu deklarieren als

const char * const text ...

Diesen Zeiger verwendest du einfach, um die einzelnen chars zu kopieren. Die Auswahl des Textes erfolgt durcch Ändern des Zeigers.

Grüsse

Robert

Reply to
R.Freitag

Hi Artur,

absolut coole Frage ! Da hat man richtig was zu knabbern.

---schnipp //######################################################################### // File: ptrtest.c // // snipped-for-privacy@holger-klabunde.de //

formatting link
// Compiler: AVR-GCC 3.4.3 //######################################################################### #include #include

#include "mydefs.h" #include "lcd.h"

char TXT_M00[] PROGMEM = "Menueintrag 1\0"; char TXT_M01[] PROGMEM = "Menueintrag 2\0"; char TXT_M02[] PROGMEM = "Menueintrag 3\0"; char TXT_M03[] PROGMEM = "Zuruck\0"; //...

//Zeiger zu Texten im Flash PGM_P text[] PROGMEM = {TXT_M00, TXT_M01, TXT_M02, TXT_M03 //... };

//Zeiger zu Texten im RAM const char *text1[] = {TXT_M00, TXT_M01, TXT_M02, TXT_M03 //... };

void print(const char *ptr) { uint8_t c; while((c=pgm_read_byte(ptr++)) != '\0') LCDWriteByte(c); }

void CText(uint8_t n) { uint8_t c;

//Nach der Docu aus der AVR-LIBC PGM_P ptr; memcpy_P(&ptr, &text[n], sizeof(PGM_P));

//ich spar mir hier das strcpy_P() aus der Docu. So gehts auch. while((c=pgm_read_byte(ptr++)) != '\0') LCDWriteByte(c); }

int main(void) { unsigned char i;

DDRC=0xFF; // set io-pins on PortC PORTC=0; //LCD-Datenbus

DDRD=0xF2; // set io-pins on PortD PORTD=0x02; //LCD-Steuersignale siehe lcd.h

LCDInit(); LCDCls();

for(;;) // loop forever { LCDPos(2,1); LCDWrite("From RAM "); for(i=0; i

Reply to
holger klabunde

Artur schrieb:

Mein Programm sieht ähnlich aus, hier ein Ausschnitt:

const char menu1_1[] PROGMEM = "music control"; const char menu1_2[] PROGMEM = "light control";

Und dazu die Zusammenfassung:

PGM_P Mainmenu[] = { menu1_1, menu1_2 };

Sieht bei mir ähnlich aus, jedoch nutze ich PGM_P als Typ:

void LCD_sendcstr(PGM_P str) { char c; while ((c = pgm_read_byte(str++)) != 0) LCD_senddata(c); }

Also bei mir funktioniert das wunderbar. Ich kann dir gerne mal meinen Quellcode mailen wenn dir das weiterhilft.

Gruß, Flo

Reply to
Florian Hirschberg

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.