Hi! Habe hier zwar schon einen Thread aber der wird zu unübersichtlich. Ich möchte ein quasi mehrdimensionales Array erstellen. Genauer genommen ein eindimensionales, in dem verschieden lange Ketten von Werten gespeichert sind. const char scene1[] PROGMEM = { 41, 81, 65, 96 }; const char scene2[] PROGMEM = { 50, 24, 91, 36, 45 }; const char *lightshow[] PROGMEM = { scene1, scene2 }; Ist das so richtig? Ich möchtet nun in zwei ineinander verschachtelten for-Schleifen zunächst die Werte von scene1 nacheinander abrufen und dann eben die werte von scene2. Nur wie mache ich das? pgm_read_byte(&lightshow[0][0]); scheint leider nicht zu funktionieren. Gibt es vielleicht sogar noch eine geschicktere Methode um meine Daten zu speichern? Wieso muss im *lightshow-Array kein & vor scene1 und scene2? (Laut GCC-Tutorial zumindest nicht) lg PoWl
Paul Hamacher wrote: > Hi! > > Habe hier zwar schon einen Thread aber der wird zu unübersichtlich. > > Ich möchte ein quasi mehrdimensionales Array erstellen. Genauer genommen > ein eindimensionales, in dem verschieden lange Ketten von Werten > gespeichert sind. > > const char scene1[] PROGMEM = { 41, 81, 65, 96 }; > const char scene2[] PROGMEM = { 50, 24, 91, 36, 45 }; > > const char *lightshow[] PROGMEM = { > scene1, > scene2 > }; > > Ist das so richtig? Kann man so machen. Damit hast du im Speicher folgende Struktur aufgebaut lightshow +----------+ +----+----+----+----+ | o--------------------->| 41 | 81 | 65 | 96 | +----------+ +----+----+----+----+ | o------------+ +----------+ | +----+----+----+----+----+ +-->| 50 | 24 | 91 | 36 | 45 | +----+----+----+----+----+ > Ich möchtet nun in zwei ineinander verschachtelten > for-Schleifen zunächst die Werte von scene1 nacheinander abrufen und > dann eben die werte von scene2. Da wird es ein Problem geben. So wie deine konmplette Struktur zur Zeit aufgebaut ist, kannst du die Längen der scenexx Arrays zur Laufzeit nicht bestimmen. Die Länge des lightshow Arrays geht noch. Aber die Zeiger dort drinnen zeigen ja jeweils auf unterschiedlich lange scene-Arrays. > > pgm_read_byte(&lightshow[0][0]); Das kann nicht gehen. Denn wenn du dir die Grafik ansiehst, dann ist die komplette 'lightshow' ja kein monolithisches Gebilde, sondern ist quer über den ganzen Speicher verstreut. Um an ein Datenbyte zu kommen musst du daher: zunächst mal den Wert von lightshow[i] holen (mittels pgm_read_word). Laut Grafik ist das ein Pointer, der auf den Anfang des i-ten scene Arrays zeigt. Daher musst du mit diesem Pointer dann einen weiteren pgm_read_byte machen um an das tatsächliche Datenbyte zu kommen. Also so was in der Art (das Problem der Array Längen überlasse ich dir :-)
1 | const char* SceneStart; |
2 | .... SceneLength; |
3 | unsigned char data; |
4 | |
5 | for( i = 0; i < LIGHTSHOW_LÄNGE; ++i ) { |
6 | |
7 | SceneStart = pgm_readword( &lightshow[i] ); |
8 | SceneLength = .... ; |
9 | |
10 | for( j = 0; j < SceneLength; ++j ) { |
11 | data = pgm_readByte( SceneStart + j ); |
12 | |
13 | ... mach was mit data ... |
14 | }
|
15 | }
|
> eine geschicktere Methode um meine Daten zu speichern? Wieso muss im > *lightshow-Array kein & vor scene1 und scene2? Weil die Nennung des Namens eines Arrays ohne einen angehängten Index (also scene1 versus scene1[5]) automatisch als die Startadresse des Arrays aufgefasst wird. scene1 ist also äquivalent zu &scene1[0]
hallo Paul, also bei mir geht dein bespiel wunderbar im falle von pgm_read_byte(&lightshow[0][0]); bekomme ich den wert 41 im falle von pgm_read_byte(&lightshow[1][4); bekomme ich den wert 45 alles ausprobiert auf einenm ATmega88 im simulator g, ATMega Guru
@ Karl Heinz, wiedermal ein astreiner Post. Habe vergessen zu erwähnen, dass die einzelnen scene-Ketten nullterminiert sind :-) Also in lightshow stehen ja die Startadressen der Scene-Arrays. lightshow[x] enthält ja dann die Startadresse der x-ten Szene. lightshow[x][y] müsste demnach die Daten..? des y-ten Elements von Szene x enthalten. Und da pgm_read_byte eine Adresse haben möchte habe ich ein & davor gesetzt. Ich dachte mir eher, der Compiler setzt das automatisch so um. Er ließt zuerst die Adresse der x-ten Scene und addiert dann noch die y drauf und ließt dann das enstprechende Element aus. Das würde doch in etwa deiner Beschreibung entsprechen, oder? Macht der Compiler das nicht automatisch? @ATMega Guru, und das funktioniert bei dir im Simulator? Muss ich gleich selbst nochmal ausprobieren aber das widerspricht sich irgendwie mit den Aussagen deines Vorposters. Ah, ich sehe grad, Karl Heinz hat noch was gecodet. Ich probiere jetzt beides mal aus! lg PoWl
>Also so was in der Art (das Problem der Array Längen überlasse >ich dir :-) Du könntest als ersten Wert in deinen Lightsow Array die Länge ablegen.
Matthias Lipinsky wrote: >>Also so was in der Art (das Problem der Array Längen überlasse >>ich dir :-) > > Du könntest als ersten Wert in deinen Lightsow Array die Länge ablegen. Oder eine Nullterminierung :-) Habe grad mal folgendes Programm im AVR Simulator getestet: Auf PortB tut sich nix, folglich scheint es nicht zu funktionieren. Ich frage mich nur warum ich keinen Compile-Error bekomme bzw., was macht er denn da nun?
1 | #include <avr/pgmspace.h> |
2 | |
3 | const char scene1[] PROGMEM = { 10, 20, 30, 40, 0}; |
4 | const char scene2[] PROGMEM = { 50, 60, 70, 80, 0}; |
5 | |
6 | const char *lightshow[] PROGMEM = { |
7 | scene1, |
8 | scene2
|
9 | };
|
10 | |
11 | int main(void) |
12 | {
|
13 | char x, y, temp; |
14 | |
15 | while(1) |
16 | {
|
17 | for(x=0; x<sizeof(lightshow); x++) |
18 | {
|
19 | y = 0; |
20 | |
21 | while(1) |
22 | {
|
23 | temp = pgm_read_byte(&lightshow[x][y]); |
24 | y++; |
25 | |
26 | if(temp == 0) |
27 | {
|
28 | break; |
29 | }
|
30 | }
|
31 | }
|
32 | }
|
33 | }
|
Vielen Dank für die Hilfe! lg PoWl
Paul Hamacher wrote: > @ATMega Guru, und das funktioniert bei dir im Simulator? Muss ich gleich > selbst nochmal ausprobieren aber das widerspricht sich irgendwie mit den > Aussagen deines Vorposters. Da kommen mal wieder schön die Tücken der Harvard-Architektur zum Vorschein: Der Simulator läuft auf dem PC und der ist eine von-Neumann-Maschine. Der gesamte Speicher liegt in einem einzigen Adressraum und die Simulator-Entwickler haben sich nicht die Mühe gemacht, den Programm-Adressraum der Zielmaschine so nachzubilden, daß Pointer aus dem Daten- in den Programmspeicher (und umgekehrt) auf einen Fehler führen. Das Simulationsergebnis von ATMega Guru könnt ihr getrost unter Zufall buchen...
>und die Simulator-Entwickler haben sich nicht die Mühe gemacht, den >Programm-Adressraum der Zielmaschine so nachzubilden, daß Pointer aus >dem Daten- in den Programmspeicher auf einen Fehler führen. Warum auch? Zeiger vom Daten- in den Programmspeicher sind ja nun weder unüblich, noch verboten, und eine Verwechslung durch den Programmierer führt in der Realität auch nicht zu einem Fehler, es wird halt nur auf die gleiche Adresse im "falschen" Speicherbereich zugegriffen. Was vom Programmieren tatscählich gewollt ist, kann kein Simulator der Welt erahnen. Das der Simulationstest von ATMega Guru funktioniert, dürfte daran liegen, daß Compiler/Linker die Scene-Arrays zufällig hintereinanderliegend im Speicher angelegt haben. Darauf darf man sich aber nicht verlassen. Oliver
Paul Hamacher wrote: > Also in lightshow stehen ja die Startadressen der Scene-Arrays. > lightshow[x] enthält ja dann die Startadresse der x-ten Szene. > lightshow[x][y] müsste demnach die Daten..? des y-ten Elements von Szene > x enthalten. Im Prinzip ja, wenn da nicht noch die Harvard Architektur wäre. &lightshow[x][y] wird vom Compiler so umgesetzt (*(lightshow + x * sizeof(const char*))) + y Das Problem ist das dereferenzieren an dieser Stelle (*(lightshow + x * sizeof(const char*))) Der Compiler weiss ganz einfach nicht, dass er mit der erhaltenen Adresse im Flash Speicher den Lookup machen müsste um die korrekte Adresse zu erhalten, mit der dann weiter gerechnet wird. Wenn es den Flash Speicher nicht geben würde und alles im SRAM liegen würde, dann würde das so funktionieren. Aber du hast ja alles ins Flash verschoben (was ja auch gut ist). Der vorderste *, also die Dereferenzierung, darf nicht im SRAM geschehen, sondern im Flash. Das macht der Compiler aber nicht von alleine, sondern du musst ihm unter die Arme greifen. > Ich dachte mir eher, der Compiler setzt das automatisch so um. Er ließt > zuerst die Adresse der x-ten Scene und addiert dann noch die y drauf und > ließt dann das enstprechende Element aus. Das würde doch in etwa deiner > Beschreibung entsprechen, oder? Macht der Compiler das nicht > automatisch? Das würde auch funktionieren, wenn alles im SRAM liegen würde.
Oliver wrote: > Warum auch? Zeiger vom Daten- in den Programmspeicher sind ja nun weder > unüblich, noch verboten, und eine Verwechslung durch den Programmierer > führt in der Realität auch nicht zu einem Fehler, es wird halt nur auf > die gleiche Adresse im "falschen" Speicherbereich zugegriffen. Was vom > Programmieren tatscählich gewollt ist, kann kein Simulator der Welt > erahnen. Na ja, ich finde, daß solches Verhalten zumindest ein bemerkenswerter Mangel am Simulator ist. Er müßte wenigstens irgendwelchen Unsinn liefern, wenn ein Prgramm läuft, das mit der Adressierung nicht zurecht kommt. Auf jeden Fall müßten controllertypspezifische Speichergrenzen überwacht werden. Die irrtümlich erwarteten Ergebnisse zu liefern, ist die mit Abstand schlechteste Lösung des Problems. Der Punkt, der Entwickler verleitet, keine Trennung der Adressräume zu implentieren, ist natürlich die Performance-Strafe, die das mit sich bringt. Es sollte zumindest eine Option vorhanden sein, mit der man Harvard-Verhalten erzwingen kann.
Hi, so, ich habe das mal folgendermaßen probiert, leider funktioniert das (im Simulator) leider auch nicht :-( Noch ein Fehler?
1 | #include <avr/pgmspace.h> |
2 | |
3 | const char scene1[] PROGMEM = { 10, 20, 30, 40, 0}; |
4 | const char scene2[] PROGMEM = { 50, 60, 70, 80, 0}; |
5 | |
6 | const char *lightshow[] PROGMEM = { |
7 | scene1, |
8 | scene2
|
9 | };
|
10 | |
11 | int main(void) |
12 | {
|
13 | char x, temp, *pointer; |
14 | |
15 | while(1) |
16 | {
|
17 | for(x=0; x<sizeof(lightshow); x++) |
18 | {
|
19 | pointer = pgm_read_word(&lightshow[x]); |
20 | |
21 | while(1) |
22 | {
|
23 | temp = pgm_read_byte(pointer++); |
24 | |
25 | if(temp == 0) |
26 | {
|
27 | break; |
28 | }
|
29 | }
|
30 | }
|
31 | }
|
32 | }
|
>Die irrtümlich erwarteten Ergebnisse zu liefern, ist die mit Abstand >schlechteste Lösung des Problems. Das Programm von AVRGuru wird auch auf der echten Hardware das selbe, richtige Ergebnis liefern. Der Simulator macht das schon richtig. Oliver
Paul Hamacher wrote: > Matthias Lipinsky wrote: > Habe grad mal folgendes Programm im AVR Simulator getestet: Auf PortB > tut sich nix, folglich scheint es nicht zu funktionieren. Wieso sollte sich auf PortB was tun ? Ich kann keine Ausgabe auf PortB in dem Programm finden. Oder hab ich was übersehen ? Frank
Frank Wallenwein wrote: > Wieso sollte sich auf PortB was tun ? > Ich kann keine Ausgabe auf PortB in dem Programm finden. > Oder hab ich was übersehen ? Oh nein ich bin so doof... 6 Stunden Schlaf waren wohl eindeutig zu wenig um zu bemerken, dass ich die Anweisung mit dem PortB garnicht in mein Testprogramm übernommen habe. Nichtsdestotrotz danke für den Hinweis ;-) lg PoWl
Paul Hamacher wrote: > Hi, > > so, ich habe das mal folgendermaßen probiert, leider funktioniert das > (im Simulator) leider auch nicht :-( Noch ein Fehler? Fehler schon. Der hat aber erst mal nichts mit den Flash Zugriffen zu tun. sizeof liefert die Größe eines 'Dings' in Bytes. int a[5]; sizeof(a) ist daher die komplette Größe des Arrays in Bytes. Die willst du aber nicht. Du willst ja wissen wieviele Elemente das Array umfasst. Daher muss diese bytegröße noch durch die Bytegröße eines Array Elements dividiert werden. sizeof(a) / sizeof(a[0]) ergibt dann tatsächlich 5 > for(x=0; x<sizeof(lightshow); x++) for( x=0; x < sizeof(lightshow)/sizeof(lightshow[0]); x++ ) Abgesehen davon, sollte das aber schon funktionieren. Hast du dir mal die Pointer Werte im Simulator angesehen, ob die realistisch sind (in dem Fall ist auch der Memory-View des Simulators eine echte Hilfe, da man mit ihm nachsehen kann, was an einer bestimmten Speicherstelle liegt.) Ich kann das hier leider auf meinem derzeitigen Rechner nicht testen, da ich DevCpp / MingW auf der Maschine habe und das anscheinend das Zusammenspiel AVR-Studio / WinAvr in irgendeiner Form stört. ( Create process error )
Danke Karl Heinz, du hast mir soeben schon die Antworten geliefert, ohne dass ich überhaupt die Fragen gestellt habe. Es solle noch viel mehr Forenuser deiner Sorte geben xD habe mich shcon gewundert was diese sizeof-konstruktion im tutorial zu bedeuten hatte und dass meine for schleife zu weit läuft. ich korrigiere das mal, und die methode von oben (&lightshow[x][y]) probier ich auch nochmal aus wobei die sich beim praxistest schon nicht bewährt hat. lg PoWl
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.