Hi, ich stehe gerade vor einem Problem. Ich möchte eine Liste mit Ports
und Pins anlegen. Eigentlich ein zweidimensionales Array. Nur mal als
Beispiel zur Veranschaulichung
1
liste = {{PORTB, 1},
2
{PORTB, 2},
3
{PORTD, 1},
4
{usw}
5
};
Ich möchte diese Liste durchlaufen und jede Zeile an eine Funktion
übergeben, die dann mit PORTB Pin 1 etwas tut.
Nur wie? Ich hab schon alles mögliche probiert. Ich weiß, dass ich PORTB
so nicht direkt angeben kann, weil das ein Makro ist und ja versuchen
würde, den Inhalt des PORT Registers zu lesen. Mit dem Adressoperator
hat man auch keinen Erfolg.
Wie kann ich das Problem lösen?
(die 20 ist jetzt nur ein Beispiel; tatsächlich muß man sich dafür die
tatsächliche Adresse denken, an der PORTB in den Speicher eingeblendet
wird - je nach konkretem AVR.)
PORTB expandiert also zu einer Referenz auf eine Speicherstelle, also
wie eine Variable, die an der Stelle 20 im Speicher liegt.
Das wiederum heißt, daß man davon auch die Adresse nehmen kann.
Du musst aber bereits in deinem Feld Adressen eintragen, also
etwa so:
Danke für die Erklärung. Wenn ich dein Beispiel jedoch übernehme bekomme
ich folgenden Fehler
main.cpp:19: error: invalid conversion from 'volatile uint8_t*' to
'uint8_t*'
Wenn ich in der Struct folgendes ändere funktioniert es.
Klaus Wachtler schrieb:> Musst du jetzt noch in offenen Wunden bohren? :-)
Mein Gott bist du schnell. Der Beitrag war doch gerade mal 10 Sekunden
da. ;-)
Eine Frage noch. Die Liste müsste ins Flash, weil die doch etwas länger
wird. Wie lege ich das an? Einfach ein PROGMEM anhängen geht nich. Und
wie greife ich darauf zu?
Da war ich schon. Bekomme aber wie gesagt eine Fehlermeldung
> main.cpp:32: warning: only initialized variables can be placed into> program memory area
Markus B. schrieb:> Nein, nach wie vor die Fehlermeldung>>> main.cpp:32: warning: only initialized variables can be placed into>> program memory area
Du compilierst das als C++?
Die Meldung ist ein Fehler in avr-g++.
Siehe Beitrag "avr-gcc, C++ und PROGMEM"
Workaround:
1
externconsttestpin_tliste[]PROGMEM;
2
consttestpin_tliste[]=
3
{
4
{&PORTE,0,&PORTE,1,0,0,&PORTD,2},
5
{&PORTE,0,0,0,0,0,&PORTD,2},
6
{&PORTE,0,0,0,&PORTE,1,&PORTD,2},
7
{&PORTE,0,&PORTE,1,&PORTE,1,&PORTD,2},
8
{&PORTE,0,&PORTE,1,&PORTE,1,&PORTD,2}
9
};
Auch wenn es komisch aussieht funktioniert es so.
Grüße Fabian
Tatsache. Danke. Hab gar nicht daran gedacht, dass ich mit g++
compiliere.
Jetzt fehlt noch das lesen einer Struct aus dem Array. Das fehlt leider
noch im Wiki
Markus B. schrieb:> Tatsache. Danke. Hab gar nicht daran gedacht, dass ich mit g++> compiliere.>> Jetzt fehlt noch das lesen einer Struct aus dem Array. Das fehlt leider> noch im Wiki
Einfach in einer Schleife sizeof(testpin_t) Bytes aus dem Flash lesen
und auf einer im SRAM bereitgestellten testpin_t Variable ablegen. Dazu
muss man ein wenig casten.
Man kann dazu zb die Funktion memcpy_P() sinnvoll benutzen.
Klaus Wachtler schrieb:> Markus B. schrieb:>> Jetzt fehlt noch das lesen einer Struct aus dem Array. Das fehlt leider>> noch im Wiki>> http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29
Sorry für die schroff kurze Antwort; als du nachgesehen hattest, gab es
die Stelle im Tutorial tatsächlich noch nicht.
(Gut daß ich nicht deutlicher gelästert hatte über mangelndes Bemühen
beim Suchen, es lag mir ja auf der Zunge :-)
Das hat Karl-Heinz da gerade schnell reingebaut (Danke!).
Wehe, es beschwert sich noch mal jemand über schlechten Service hier!
Klaus Wachtler schrieb:> Das hat Karl-Heinz da gerade schnell reingebaut (Danke!).
Ach da unten. Ich hatte den neuen Eintrag wohl gesehen, den Teil aber
übersehen. Hab noch keinen Kaffee :)
Johann L. schrieb:> Inzwischen ist das Tutorial wohl so unübersichtlich, daß ein und> dasselbe x-mal erklärt wird:
Unübersichtlich? Ja. Ein und das selbe? Nein, finde ich nicht. Es gibt
halt Menschen wie mich, die die nötigen Informationen aus dem Wust in
dem Tutorial nicht finden und zusammenfügen können, weil die Erfahrung
fehlt.
Ich habe jetzt noch ein anderes Problem, das für mich keinen Sinn
ergibt. Eventuell hat es was damit zu tun, dass ich mit dem g++
compiliere?
Hier erstmal der wichtige Code
1
typedefstruct
2
{
3
volatileuint8_t*p_portT;
4
uint8_tpinT;
5
volatileuint8_t*p_portL;
6
uint8_tpinL;
7
volatileuint8_t*p_portR;
8
uint8_tpinR;
9
volatileuint8_t*p_portC;
10
uint8_tpinC;
11
}testpin_t;
12
13
testpin_tliste[]=
14
{
15
{&PORTA,0,&PORTA,1,0,0,&PORTD,2},
16
{&PORTB,0,0,0,0,0,&PORTD,2},
17
{&PORTC,0,0,0,&PORTE,1,&PORTD,2},
18
{&PORTD,0,&PORTB,1,&PORTE,1,&PORTD,2},
19
{&PORTE,0,&PORTC,1,&PORTE,1,&PORTD,2},
20
{0,0,0,0,0,0,0,0}
21
}
22
23
intmain(void)
24
{
25
sei();
26
uint8_ti=0;
27
while(liste[i].p_portT)
28
{
29
stream<<i<<" ";
30
stream<<&liste[i]<<" ";
31
stream<<*(liste[i].p_portL)<<" ";
32
stream<<sizeof(liste[i]);
33
i++;
34
stream<<xpcc::endl;
35
}
36
while(1)
37
{
38
}
39
return0;
40
}
&liste[i] gibt mir die Adresse des jeweiligen Struct aus.
sizeof(liste[i]) ergibt interessanterweise 12 Byte, nicht 8, wie man
erwarten würde. Braucht ein Struct 4 Byte extra? Oder brauchen die
volatilen Felder ein extra Byte?
*(liste[i].p_portL) gibt jedoch völligen Blödsinn aus. Überall da, wo in
der Liste ein &PORTx eingetragen ist, wird eine 0 ausgegeben. Da wo eine
0 in der Liste steht erhalte ich aber einen Wert. Das ergibt überhaupt
keinen Sinn und ich komme auch nicht dahinter, wieso.
Jemand eine Idee?
Markus B. schrieb:> ergibt interessanterweise 12 Byte, nicht 8, wie man> erwarten würde.
Ein Zeiger braucht auf einem bestimmten System immer eine feste Anzahl
Byte, egal wie groß das ist, worauf er zeigt.
Bei AVR offenbar 2 Byte, auch wenn er auf eine ein Byte große uint8_t
zeigt.
Vier Zeiger, 4 uint8_t macht zumsammen 12 Byte.
Markus B. schrieb:> Überall da, wo in> der Liste ein &PORTx eingetragen ist, wird eine 0 ausgegeben.
Da, wo du eine &PORTx eingetragen hast, und mit * darauf zugreifst,
bekommst du den aktuellen Wert von PORTx.
Auch wenn PORTx eigentlich zur Ausgabe gedacht ist, kannst du aus dem
Register etwas lesen. Meines Wissens ist es der aktuelle ausgegebenen
Wert, also 0, solange du nicht vorher mit PORTx = ... etwas anderes
ausgibst.
Klaus Wachtler schrieb:> Wo nimmst du auf einem AVR streams her, und vor allem: willst du das> wirklich?http://xpcc.sourceforge.net/Klaus Wachtler schrieb:> Ein Zeiger braucht auf einem bestimmten System immer eine feste Anzahl> Byte, egal wie groß das ist, worauf er zeigt.> Bei AVR offenbar 2 Byte, auch wenn er auf eine ein Byte große uint8_t> zeigt.
Ist ja kein uint8_t sondern ein Zeiger auf uint8_t. Das passiert, wenn
man zu wenig geschlafen hat.
Trotzdem bekomme ich immer den Wert 0, sobald ich einen Port in die
Liste schreibe. Komme nicht dahinter, warum.
Daß du in den anderen Fällen irgendwelche Werte bekommst, liegt daran,
daß du den Zeiger mit 0 intialisierst, aber trotzdem mit *(uint8_t)0
dann darauf zugreifst. Je nach AVR (siehe Datenblatt) wird da auch ein
Register sein, dessen Wert du ausgibst.
Böser Junge!
Markus B. schrieb:> Überall da, wo in> der Liste ein &PORTx eingetragen ist, wird eine 0 ausgegeben.
Du hast ja auch nichts in die Port-Register geschrieben, und 0 ist der
Default-Inhalt.
Markus B. schrieb:> Da wo eine> 0 in der Liste steht erhalte ich aber einen Wert.
Ja, den Inhalt von Adresse 0.
Klaus Wachtler schrieb:> Da, wo du eine &PORTx eingetragen hast, und mit * darauf zugreifst,> bekommst du den aktuellen Wert von PORTx.> Auch wenn PORTx eigentlich zur Ausgabe gedacht ist, kannst du aus dem> Register etwas lesen. Meines Wissens ist es der aktuelle ausgegebenen> Wert, also 0, solange du nicht vorher mit PORTx = ... etwas anderes> ausgibst.
Man, ich hab heute Watte im Schädel. Danke