PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C Befehle auflösen bzw. verstehen



googol
18.02.2013, 20:41
Hallo liebe Gemeinde,

ich bin neu hier und versuche mich grad an einem Atmega8 und einem kleinen Evaluationsboard von myAVR. Ich habe es bereits geschafft ein Poti mit dem ADC einzulesen und je nach Wert eine andere LED anzusteuern. Dabei hole ich mir die Werte des ADC wie im AVR-GCC-Tut mit dem Befehl
foo = ADC;Dabei stellt sich mir als (neugieriger) Anfänger natürlich gleich die Frage, woher ich das wissen soll, dass ich mit "ADC" den Wert der beiden Register 0x04 und 0x05 bekomme. Also habe ich versucht das ganze nachzuvollziehen. In der iom8.h bin ich dann auf folgendes gestoßen:
#define ADC _SFR_IO16(0x04)Aus meiner früheren Programmiererfahrung (was leider nicht sehr viel ist) weiß ich noch, dass man eine preprocesser anweisung direkt ersetzen kann. Also habe ich statt dem
foo = ADC;folgendes geschrieben
foo = _SFR_IO16(0x04)Siehe da. Voller Erfolg. Es funktioniert genauso.
Nun weiß ich aber noch nicht was _SFR_IO16(0x04) so anrichtet. Ich also wieder fündig geworden, diesmal in der sfr_defs.h mit dieser Zeile
#define _SFR_IO16(io_addr) ((io_addr) + __SFR_OFFSET)Also habe ich dann die Zuweisungszeile nochmal durch diese ersetzt
foo = ((0x04) + __SFR_OFFSET)Mich hätte es sehr gewundert wenn dies funktioniert hätte, da ich ja der Variablen "foo" nur einen Wert zuweise.
...jetzt bin ich eben mit meinem Latein am Ende. Woher weiß denn der Compiler (AtmelStudio), dass er beim oberen Ersetzen ein bzw. zwei Register auslesen muss und beim zweiten Beispiel versteht er es nicht mehr? Interpretiere ich das Preprocessor Makro vielleicht falsch?

Es wäre nett wenn mir das evtl. jemand erklären könnte.
Grüße
Googol

Besserwessi
18.02.2013, 21:20
Für _SFR_IO16(io_addr) gibt es 2 verschiedene Definitionen. Die oben genutzte definition ist die für ASM files. Für C Code gibt eine 2. Definition:

#define _SFR_IO16(io_addr) _MMIO_WORD((io_addr) + __SFR_OFFSET)
und
#define _MMIO_WORD(mem_addr) (*(volatile uint16_t *)(mem_addr))

Wenn man das einsetzt, sollte es auch direkt ohne die Defines gehen.

googol
19.02.2013, 06:44
Danke, das habe ich übersehen.
Im Klartext heißt das dann?:
volatile uint16_t*definiert einen Zeiger, der auf einen 16-Bit-Wert zeigt. Und mit dem Dereferenzierungsoperator vor der öffnenden Klammer mache ich klar, dass ich den Wert (der dann 16-Bit groß ist und somit auch den Wert aus 0x05 betrifft) aus der Adresse "mem_addr" zurückgegeben haben will.