Hi, ich arbeite mit AVR Studio und möchte abhänging vom Device meinen Quellcode compilieren. Dazu möchte ich "MCU" auswerten und zwischen ATMEGA und ATTINY unterscheiden. Meine Frage: gibt es eine möglichkeit, bei #if bzw. #ifdef usw. zu schauen, ob in "MCU" ATTINY oder ATMEGA steht und den Rest (bei ATMEGA 32,16,8 usw.) auszublenden, durch Wildcards oder ähnlich?? Gruß, Alex
Nein, wildcards gibt es nicht. Du musst schon einzeln testen:
1 | #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__)
|
2 | # define THIS megaTHIS
|
3 | #elif defined(__AVR_ATtiny13__) || defined(__AVR_ATtiny261__)
|
4 | # define THIS tinyTHIS
|
5 | #else
|
6 | # error "Unknown MCU type"
|
7 | #endif
|
Hallo, da häng ich mich doch gleich mit dran, wenn so ein Thema schonmal offen ist: Ich habe ein ähnliches Problem, ich will eine Initialisierung meines verwendeten Controllers vornehmen. Dazu will ich über eine Art "Case-Struktur" entscheiden, welcher Controller gewählt wurde und nur den dafür zutreffenden Code compilieren lassen. Die restlichen Cases brauch ich aber ja nicht im Code, würde nur Platz verschwenden. Nun dachte ich an eine Bibliothek, die ich dann ins eigentliche Programm einbinde. Im Hauptprogramm wird dann beispielsweise über
1 | #define mcu tiny25
|
der Controller festgelegt. In der Bibliothek würde ich dann - wie oben beschrieben - über ifdefs den linker entscheiden lassen, welchen Init-Code er compiliert. Aber das kann doch unglaublich umfangreich werden, oder nicht? Jetzt hab ich aber mit C leider noch nicht allzu große Erfahrung und frage mich, ob das überhaupt Funktioniert bzw. guter Stil ist, oder ob man besser anders vorgeht. Könnte man das ganze auch über ein Makefile lösen und wenn, wie sollte man da am Besten vorgehen? Ich habe schon einige Beispiele über Makefiles gelesen (u. a. auch den Exkurs im GCC-Tutorial), aber bedingte Compilierungen hab ich da nicht gefunden. Viele Grüße und Danke für eure Vorschläge! Sven
Könnte man im Makefile nach WinAVR-Vorlage so lösen: # fuer alle controller SRC=wieauchimmer.c egal.c foo.c # controllerspezifischer code ifeq($(MCU),atmega128) SRC+=codefueratmega128.c endif ifeq($(MCU),atmega16) SRC+=codefueratmega16.c endif Vgl. z.B. http://www.siwawi.arubi.uni-kl.de/avr_projects/#avrprog_boot Ob das nun übersichtlicher ist, als den Preprocessor zu bemühen, mag jeder selbst entscheiden. Meist sind die Unterschiede nicht so gross, dass eigene Quellcodedateien benötigt werden.
> In der Bibliothek würde ich dann - wie oben beschrieben - > über ifdefs den linker entscheiden lassen, welchen > Init-Code er compiliert. Das geht so nicht. Präprozessoranweisungen wie #ifdef werden vom Präprozessor ausgewertet, und dessen Resultat landet im Compiler. Der Linker bekommt Präprozessoranweisungen nie zu sehen. Dein Ansatz kann -leicht abgewandelt- dennoch funktionieren: Den Prozessorspezifischen Code packst Du in eigene Module (mindestens eines pro Prozessor) und die darin enthaltenen Funktionen benennst Du entsprechend eindeutig, also beispielsweise m128_init in m128.c m32_init in m32.c m16_init in m16.c etc. Die alle übersetzt Du und packst sie in eine Library. Etwaig verwendete globale Variablen müssen ebenfalls dieser Nomenklatur gehorchen. Dein diese Library nutzender Code bindet eine Headerdatei ein, in der per Präprozessoranweisungen aus dem generischen "init" der jeweils zu verwendende Name erzeugt wird: #if defined(_AVR_ATmega16_) #define init m16_init #endif #if defined(_AVR_ATmega128_) #define init m128_init #endif Dein Code ruft "init" auf; durch die Präprozessoranweisung wird das korrekte implementierungsabhängige "init" daraus gemacht und der Linker linkt aus der Library das Modul, in dem der zugehörige Code enthalten ist. So ginge es.
Vielleicht hilft Dir das builtin Define _ARV_ARCH_ ? http://www.roboternetz.de/wissen/index.php/Avr-gcc#Maschinenspezifische_Optionen_f.C3.BCr_avr-gcc
Danke für eure Antworten! @rufus: Gute Idee! Zum testen habe ich mir die entsprechenden Module und die Library erstellt. Das Header-File (msp_init.h) sieht nun so aus:
1 | int msp430_1_init(void); |
2 | int msp430_2_init(void); |
3 | int msp430_3_init(void); |
4 | |
5 | #if defined(_MSP430_1_)
|
6 | #define init msp430_1_init
|
7 | #endif
|
8 | |
9 | #if defined(_MSP_430_2_)
|
10 | #define init msp430_2_init
|
11 | #endif
|
12 | |
13 | #if defined(_MSP_430_3_)
|
14 | #define init msp430_3_init
|
15 | #endif
|
Meine Main hab ich so geschrieben:
1 | #include "msp_init.h" |
2 | #define MSP430_1
|
3 | |
4 | int main(void) |
5 | {
|
6 | init(); |
7 | }
|
Nun bekomme ich leider einen Fehler, dass "init" nicht definiert ist. Verstehe ich das richtig, dass der Präprozessor im Header-File bei den Präprozessoranweisungen in meinem Fall 'init' mit 'msp430_1_init' ersetzt, da ich in der Main ja gesagt habe '#define MSP430_1'? Dann würde im Code ja statt der Funktionsaufruf 'init();' der Aufruf 'msp430_1_init();' erfolgen. Ich komm da grad nicht drauf... Viele Grüße Sven
#include "msp_init.h" #define MSP430_1 ist wohl die falsche Reihenfolge. Generell wäre es auch sinnvoll, ein #if...#elif..#else error "no device defined"-Konstrukt zu verwenden, dann bekommst du eine aussagekräftige Fehlermeldung. Oliver
Perfekt! Danke, das war's. Warum sieht man solche Kleinigkeiten alleine nur so schwer?! Nur zur Info: Zusätzlich muss ich in der Main ja überhaupt
1 | #define _MSP430_1_
|
statt
1 | #define MSP430_1
|
schreiben ;-)
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.