Hallo,
ich möchte gerne diese Funktion ein bisschen Variable gestalten.
Nun meine Frage. Bei meinem ATXMega gibt es beim Timer0 4 div. Compare
Register ( CCA - CCD )
Hier die Struktur
1
/* 16-bit Timer/Counter 0 */
2
typedefstructTC0_struct
3
{
4
register8_tCTRLA;/* Control Register A */
5
register8_tCTRLB;/* Control Register B */
6
register8_tCTRLC;/* Control register C */
7
register8_tCTRLD;/* Control Register D */
8
register8_tCTRLE;/* Control Register E */
9
register8_treserved_0x05;
10
register8_tINTCTRLA;/* Interrupt Control Register A */
11
register8_tINTCTRLB;/* Interrupt Control Register B */
12
register8_tCTRLFCLR;/* Control Register F Clear */
13
register8_tCTRLFSET;/* Control Register F Set */
14
register8_tCTRLGCLR;/* Control Register G Clear */
15
register8_tCTRLGSET;/* Control Register G Set */
16
register8_tINTFLAGS;/* Interrupt Flag Register */
17
register8_treserved_0x0D;
18
register8_treserved_0x0E;
19
register8_tTEMP;/* Temporary Register For 16-bit Access */
20
register8_treserved_0x10;
21
register8_treserved_0x11;
22
register8_treserved_0x12;
23
register8_treserved_0x13;
24
register8_treserved_0x14;
25
register8_treserved_0x15;
26
register8_treserved_0x16;
27
register8_treserved_0x17;
28
register8_treserved_0x18;
29
register8_treserved_0x19;
30
register8_treserved_0x1A;
31
register8_treserved_0x1B;
32
register8_treserved_0x1C;
33
register8_treserved_0x1D;
34
register8_treserved_0x1E;
35
register8_treserved_0x1F;
36
_WORDREGISTER(CNT);/* Count */
37
register8_treserved_0x22;
38
register8_treserved_0x23;
39
register8_treserved_0x24;
40
register8_treserved_0x25;
41
_WORDREGISTER(PER);/* Period */
42
_WORDREGISTER(CCA);/* Compare or Capture A */
43
_WORDREGISTER(CCB);/* Compare or Capture B */
44
_WORDREGISTER(CCC);/* Compare or Capture C */
45
_WORDREGISTER(CCD);/* Compare or Capture D */
46
register8_treserved_0x30;
47
register8_treserved_0x31;
48
register8_treserved_0x32;
49
register8_treserved_0x33;
50
register8_treserved_0x34;
51
register8_treserved_0x35;
52
_WORDREGISTER(PERBUF);/* Period Buffer */
53
_WORDREGISTER(CCABUF);/* Compare Or Capture A Buffer */
54
_WORDREGISTER(CCBBUF);/* Compare Or Capture B Buffer */
55
_WORDREGISTER(CCCBUF);/* Compare Or Capture C Buffer */
56
_WORDREGISTER(CCDBUF);/* Compare Or Capture D Buffer */
Mach doch statt CCA-CCD ein Array "CCn[4]" und nutze "ccx" als Index.
PS: Der Bezeichner _WORDREGISTER in C der Standard-Bibliothek bzw.
Compiler vorenthalten und nicht für User-Code erlaubt, da er mit
Unterstrich+Großbuchstabe beginnt.
Niklas G. schrieb:> Mach doch statt CCA-CCD ein Array "CCn[4]" und nutze "ccx" als> Index.>> PS: Der Bezeichner _WORDREGISTER in C der Standard-Bibliothek bzw.> Compiler vorenthalten und nicht für User-Code erlaubt, da er mit> Unterstrich+Großbuchstabe beginnt.
Okay.. aber wie komme ich dann z.b auf CCD?
Jan H. schrieb:> (( tim0->CCA ) + ccx ) = 0; // haut wohl so nicht hin..
Das ergibt ja auch keinen Sinn. Verkürzt geschrieben wäre das ja das
gleiche wie:
1
a+b=0;
Auf was sollen da a und b gesetzt werden?
Die Klammern haben übrigens keinerlei Effekt.
Ich vermute, was du eigentlich meintest, wäre sowas:
1
>(&tim0->CCA)[ccx]=0;
Das ist aber eher ziemlich hässlich.
Du versuchst, Elemente einer Struktur so anzusprechen, als seien sie
Elemente eines Arrays. Deshalb der Vorschlag von Niklas Gürtler, diese
gleich als Array anzulegen.
Warum?
Sollte ich am besten für jeden Compare Match eine eigene Funktion
schreiben um einen Wert zu setzen? Das soll später mal eine Timer
Bibliothek werden, deshalb würde ich es gerne so machen wollen
Jan H. schrieb:> Warum?
Warum was?
> Sollte ich am besten für jeden Compare Match eine eigene Funktion> schreiben um einen Wert zu setzen?
Nein, du sollst ein Array definieren. Und am besten ein gutes C-Buch
kaufen und durcharbeiten. Ich habe den Eindruck, du hast keine Ahnung,
wovon wir sprechen, obwohl das doch sehr grundlegende Dinge sind.
Ja, das funktioniert wirklich, da der Null-Pointer nie dereferenziert
wird, er dient nur als Basis für die Adressrechnung. Diesen – oder jeden
anderen Offset – kannst Du dann verwenden, um die Adresse des Elements
in einer Struktur zu errechnen:
1
structXx={5,3.141,"hello world"};
2
3
unsignedlongaddr_x=(unsignedlong)&x;
4
int*addr_a=(int*)(addr_x+offset_a);
5
double*addr_b=(double*)(addr_x+offset_b);
6
char**addr_c=(char**)(addr_x+offset_c);
Das Casten der Adresse von X auf unsigned long ist notwendig, da Du
mit den Binärwerten der Adresse rechnen willst. Dagegen wäre
Der Linux Kernel verwendet diese Technik, um auf die Linkelemente
verketteter Listen in Strukturen zuzugreifen. Ob das schön ist, sei
einmal dahin gestellt.
PS: Soweit ich mich erinnere ist unsigned long auf jeder Architektur
garantiert groß genug, um einen Pointer aufzunehmen. Da bin ich mir aber
nicht ganz sicher, im Zweifel müsste man das bitte nochmal im Standard
nachlesen. Weiß das vielleicht jemand aus dem Kopf?
Jan H. schrieb:> Rolf M. schrieb:>> Ich vermute, was du eigentlich meintest, wäre sowas:> (&tim0->CCA)[ccx]>> = 0;>> Danke! Das hilft mir weiter ;)
Das kann und wird auch in den meisten Fällen so funktionieren, ist aber
nicht wirklich portabel. Der Compiler darf zwischen den Elementen einer
Struktur Padding-Bytes einfügen, um sie an den physischen
Speichergrenzen auszurichten und so einen schnelleren Zugriff zu
ermöglichen. Zwischen Elementen eines Arrays gibt es Padding auf keinen
Fall. Abhängig von Compiler und Architektur kann die Pointer-Arithmetik
in diesem Fall also falsch rechnen, es sei denn, die Struktur wurde
explizit als packed definiert, zum Beispiel:
A. H. schrieb:> Ja, das funktioniert wirklich, da der Null-Pointer nie dereferenziert> wird, er dient nur als Basis für die Adressrechnung.
Wird in der Praxis wohl meistens gehen, aber offiziell ist es nicht
erlaubt. Der offizielle Weg ist die Benutzung des Makros offsetof().
Rolf M. schrieb:> A. H. schrieb:> Ja, das funktioniert wirklich, da der Null-Pointer nie dereferenziert> wird, er dient nur als Basis für die Adressrechnung.>> Wird in der Praxis wohl meistens gehen, aber offiziell ist es nicht> erlaubt. Der offizielle Weg ist die Benutzung des Makros offsetof().
Wie sieht das denn dann mit der Funktion aus?
Auch das würde ich so nicht machen:
A. H. schrieb:> unsigned long addr_x = (unsigned long) &x;> int *addr_a = (int*)(addr_x + offset_a);
Warum nicht einfach mit Zeigern arbeiten, wenn man mit Adressen
hantiert? Wenn schon ein Integer, dann intptr_t. Der ist garantiert
groß genug, um einen Zeiger aufzunehmen.
Ich würd's aber so machen:
1
char*addr_x=(char*)&x;
2
int*addr_a=(int*)(addr_x+offset_a);
A. H. schrieb:> PS: Soweit ich mich erinnere ist unsigned long auf jeder Architektur> garantiert groß genug, um einen Pointer aufzunehmen.
Nein. Der ist auf so genannten IL32P64-Architekturen zu klein. Eine
davon wäre z.B. die 64-Bit-Version von Windows.
Dafür ist unsigned long auf kleinen 8-Bittern oft eher unnötig groß, da
er mindesten 32 Bit breit ist.
A. H. schrieb:> Rein technisch kannst Du den Offset eines Strukturelementes mit> folgendem Ausdruck gewinnen:> (unsigned long) &((struct /*Structurname*/ *)0)->/*Elementname*/
Warum sollte man das machen, wenn es offsetof gibt?
A. H. schrieb:> PS: Soweit ich mich erinnere ist unsigned long auf jeder Architektur> garantiert groß genug, um einen Pointer aufzunehmen. Da bin ich mir aber> nicht ganz sicher, im Zweifel müsste man das bitte nochmal im Standard> nachlesen. Weiß das vielleicht jemand aus dem Kopf?
Nein, es ist nicht garantiert, dass unsigned long groß genug ist.