Hallo zusammen,
Ich habe da einen Fehler, der für euch wahrscheinlich sehr einfach ist.
Lösung habe ich beim durchsuchen leider keine gefunden.
Also ich habe einerseits diese Deklarationen, welche mir einfch die
I/O's entsprechend setzen:
1
#define Power_Relay_1 PORTA |= BIT1; \
2
PORTA |= BIT2;
3
#define Maintain_Relay_1 PORTA &= ~BIT1
4
#define Release_Relay_1 PORTA &= ~BIT1; \
5
PORTA &= ~BIT2;
6
#define Power_Shutter_1_Up Power_Relay_1
7
#define Maintain_Shutter_1_Up Maintain_Relay_1
8
#define Release_Shutter_1_Up Release_Relay_1
9
#define Status_Relay_1 ((PINA&BIT2) != 0x00)
10
11
#define Power_Relay_2 PORTA |= BIT3; \
12
PORTA |= BIT4;
13
#define Maintain_Relay_2 PORTA &= ~BIT3
14
#define Release_Relay_2 PORTA &= ~BIT3; \
15
PORTA &= ~BIT4;
16
#define Power_Shutter_1_Down Power_Relay_2
17
#define Maintain_Shutter_1_Down Maintain_Relay_2
18
#define Release_Shutter_1_Down Release_Relay_2
19
#define Status_Relay_2 ((PINA&BIT4) != 0x00)
20
21
#define Power_Relay_3 PORTA |= BIT5; \
22
PORTA |= BIT6;
23
#define Maintain_Relay_3 PORTA &= ~BIT5
24
#define Release_Relay_3 PORTA &= ~BIT5; \
25
PORTA &= ~BIT6;
26
#define Power_Shutter_2_Up Power_Relay_3
27
#define Maintain_Shutter_2_Up Maintain_Relay_3
28
#define Release_Shutter_2_Up Release_Relay_3
29
#define Status_Relay_3 ((PINA&BIT6) != 0x00)
30
31
// !!! TEILWEISE PORTG !!!
32
#define Power_Relay_4 PORTA |= BIT7; \
33
PORTG |= BIT2;
34
#define Maintain_Relay_4 PORTA &= ~BIT7
35
#define Release_Relay_4 PORTA &= ~BIT7; \
36
PORTG &= ~BIT2;
37
#define Power_Shutter_2_Down Power_Relay_4
38
#define Maintain_Shutter_2_Down Maintain_Relay_4
39
#define Release_Shutter_2_Down Release_Relay_4
40
#define Status_Relay_4 ((PING&BIT2) != 0x00)
Andererseits habe ich auch diese makros, um die entsprechenden (oben
aufgeführten) I/O's zu setzen:
1
#define Power_Relay_Index if(Index == 0) \
2
Power_Relay_1; \
3
if(Index == 1) \
4
Power_Relay_2; \
5
if(Index == 2) \
6
Power_Relay_3; \
7
if(Index == 3) \
8
Power_Relay_4;
9
10
11
#define Release_Relay_Index if(Index == 0) \
12
Release_Relay_1; \
13
if(Index == 1) \
14
Release_Relay_2; \
15
if(Index == 2) \
16
Release_Relay_3; \
17
if(Index == 3) \
18
Release_Relay_4;
Wenn ich dann aber:
1
Index=1;
2
Power_Relay_Index;
ausführe, erwarte ich dass er ganz einfach Power_Relay_1 ausführt, also
A1 und A2 setzt, aber ...
er setzt mir in der Reihenfolge:
A1, A2, A4 und danach A6...
Nach den "/" sind die Zeilen fertig, also keine Leerzeichen oder so.
Das ";" am Ende jedes #define hab ich auch schon versucht wegzulassen.
Mein Compiler: IAR
Mein Debugger AVR-Studio
Vielen Dank im Voraus !
#defines sind keine Funktionen.
Der grundlegende Fehler ist es sie als Funktionsersatz zu nutzen. Du
merkst, dass ein Fehler irgendwo zu Mist führt und du den nicht so
einfach lokalisieren kannst.
Lass dir vom Compiler den Quellcode nach dem Preprozessor ausgeben. Dann
kannst du zumindest sehen, was der Compiler als Eingabe bekommt.
So kann man das nicht analysieren, weil Dein codeschnipsel umgebrochen
wird (keine code ansicht) ist nicht klar ob Du da irgendwo einen Fehler
gemacht hast.
Wenn Du gcc benutzt kannst Du die Option "-save-temps" nutzen. Dann
bleibt nach dem compilieren eine *.i-Datei liegen. In der kannst Du
sehen was der Preprozessor aus Deinen #defines und Macros gemacht hat.
Hallo und danke erstmal für die raschen Reaktionen !
Also zum debuggen ist es wirklich Mist, da mann es eben nicht
nachverfolgen kann.
*.i Datei habe ich leider keine.
Ich versuche es mal mit den {} !
#define Power_Relay_Index if(Index == 0)
\
Power_Relay_1;
\
if(Index == 1)
\
Power_Relay_2;
\
if(Index == 2)
\
Power_Relay_3;
\
if(Index == 3)
\
Power_Relay_4;
machte einen Fehler in If´s ,in zweierlei Hinsicht.
if (foo) Power_Relay_Index; else bar();
Zum einen macht hier das doppelte Semicolon probleme, gibt
Kompilerfehler.
Zum anderen bezieht sich das Else jetzt nicht mehr auf foo sondern auf
Index == 3.
Entweder du machst es so:
#define Power_Relay_Index if(Index == 0)
\
Power_Relay_1;
\
else \
if(Index == 1)
\
Power_Relay_2;
\
else \
if(Index == 2)
\
Power_Relay_3;
\
else \
if(Index == 3)
\
Power_Relay_4;
else
Dies lässt dir die Freiheit eventuell auch noch weitere Else Zweige
anzuhängen, oder normalerweise wird es so verpackt:
#define Power_Relay_Index do { \
if(Index == 0)
\
Power_Relay_1;
\
if(Index == 1)
\
Power_Relay_2;
\
if(Index == 2)
\
Power_Relay_3;
\
if(Index == 3)
\
Power_Relay_4;
\
while(0)
Muss jetzt aber nicht heissen, daß dies dein Problem lösen könnte, bei
größerer SW oder länger wartbarer SW solltest du es allerdings zu Herzen
nehmen.
Hi Alexandre,
Alexandre schrieb:> Hallo und danke erstmal für die raschen Reaktionen !
...
> Also zum debuggen ist es wirklich Mist, da mann es eben nicht
dem ist natürlich nicht so. Du kannst das debuggen.
> nachverfolgen kann.> *.i Datei habe ich leider keine.
darum habe ich Dir den command line parameter geschickt. Wenn Du uns
verrätst welchen Compiler Du verwendest können wir die vielleicht auch
sagen wie Du das in Deiner Umgebung machen kannst.
> Ich versuche es mal mit den {} !
Versuch macht nicht unbedingt klug. Du solltest Dir wirklich mal die
Ausgabe nach dem Preprozessor anschauen (bei GCC *.i Datei). Dann siehst
Du auch was der Preprozessor aus Deinen Defines und Makros macht.
Einfach mal die ";" weg zu lassen oder "{}" drum zu setzen ohne zu
wissen wie sich das auf den Quellcode auswirkt wird nicht viel bringen
...
> if (foo) Power_Relay_Index; else bar();> Zum einen macht hier das doppelte Semicolon probleme, gibt Kompilerfehler.
Deswegen habe ich einen Vorschlag gemacht, der geschweifte Klammern um
den Block verwendet. Und auch die leere Klammer "()" im Makro Namen
dient der Vermeidung anderer unerwarteter Probleme.
Aber: Ich glaube unser beider Antworten helfen dem Alexandre nicht bei
seinem konkreten Problem. Er braucht wohl wirklich den temporären Output
des pre-compilers.
Alexandre schrieb:> Index = 1;> Power_Relay_Index;> ausführe, erwarte ich dass er ganz einfach ...
Warum erwartest Du es?
Steht sowas in irgendeinem C-Buch?
C kann keine Namen zerlegen.
Macros können aber Argumente übergeben werden:
Der seit Jahren bewährte Trick, um Makros die aus mehreren Statements
bestehen, "if-sicher" zu machen, ist nicht das Einschließen in { },
sondern:
#define make_this_and_that do { make_this; make_that; } while (0)
OHNE!!! abschließendes Semikolon nach dem while(0)!
Alexandre schrieb:> aber ...> er setzt mir in der Reihenfolge:> A1, A2, A4 und danach A6...
Genau das hast du doch auch hingeschrieben:
1
#define Power_Relay_Index if(Index == 0) \
2
Power_Relay_1; \
3
if(Index == 1) \
4
Power_Relay_2; \
5
if(Index == 2) \
6
Power_Relay_3; \
7
if(Index == 3) \
8
Power_Relay_4;
wird vom Preprocessor hierzu expandiert:
1
if(Index == 0)
2
PORTA |= BIT1;
3
PORTA |= BIT2;;
4
5
if(Index == 1)
6
PORTA |= BIT3;
7
PORTA |= BIT4;;
8
9
if(Index == 2)
10
PORTA |= BIT5;
11
PORTA |= BIT6;;
12
13
if(Index == 3)
14
PORTA |= BIT7;
15
PORTG |= BIT2;;
Da die Power_Relay_...-Makros zwei Statements enthalten wirkt das if
immer nur auf den ersten davon.
Ich würde empfehlen für sowas komplett auf Makros zu verzichten und es
mit Funktionen zu formulieren - wenn das Inlining wichtig ist kann man
die immer noch als "static inline" in ein Headerfile schreiben und
vermeidet trotzdem solche Probleme.
Es gibt eben eine sinnvolle Grenze, ab der es keinen Sinn mehr macht,
alles in Makros abzubilen.
Mach Funktionen draus und gut ists. Zuminest aus den 'höherwertigen'
Makros.
Wenn du noch dafür sorgst, dass die Funktionen geinlined werden, ist das
Ergebnis genausogut, wie wenn du dich durch die Makros durchgewurschtelt
hättest und der Optimizer gewütet hat.
Der Versuch mit den {} hat es leider nicht gebracht.
@Chris:
Ich verstehe (denke ich zumindest) zwar den Sinn, aber dachte es sollte
auch ohne do{} gehen.
Da ich in meinen if() KEINE {} habe, sollte es sich nur auf die nächst
Zeile anwenden, allerdings besteht mein Power_Relay_1 aus 2 Zeilen.
Habe es nun so geändert:
#define Power_Relay_1 {\
PORTA |= BIT1; \
PORTA |= BIT2; \
}
und es scheint zu klappen !
Vielen Dank euch allen !
mfg,
Alexandre
Sorry für die anderen Antworten, Ihr seid halt viel schneller als ich.
Unsere Antworten haben sich überschnitten, aber dank euch:
- Habe ich das Problem verstanden
wird vom Preprocessor hierzu expandiert:
if(Index == 0)
PORTA |= BIT1;
PORTA |= BIT2;;
if(Index == 1)
PORTA |= BIT3;
PORTA |= BIT4;;
if(Index == 2)
PORTA |= BIT5;
PORTA |= BIT6;;
if(Index == 3)
PORTA |= BIT7;
PORTG |= BIT2;;
und das mit dem i file muss ich mir auch anschauen, dies hätte es
einfacher gemacht !
Habe übrigens das IAR Embedded Workbench
DANKE NOCH !
Alexandre
Zu Peter:
Klar kann C keine Namen Zerlegen, ich habe es einfach Index genannt weil
Lesbar.
Index wird auf 1 gesetzt
Und in der Makro wir Index auch verwendet
Dass die Makro auch xxx_Index heisst, ist nur damit ich weiss dass diese
"Index" auch intern verwendet.
Danke noch allen,
Alexandre schrieb:> Der Versuch mit den {} hat es leider nicht gebracht.> @Chris:> Ich verstehe (denke ich zumindest) zwar den Sinn, aber dachte es sollte> auch ohne do{} gehen.>> Habe es nun so geändert:>> #define Power_Relay_1 {\> PORTA |= BIT1; \> PORTA |= BIT2; \> }>> und es scheint zu klappen !
Bitte nicht! Du bringst dich selbst in Teufels Küche!
beispiel:
Alexandre schrieb:> Habe übrigens das IAR Embedded Workbench
Der kann man auch irgendwo sagen, dass sie die nach dem
Präprozessorschritt entstehende Datei extra ablegen soll.
Jörg Wunsch schrieb:> Alexandre schrieb:>> Habe übrigens das IAR Embedded Workbench>> Der kann man auch irgendwo sagen, dass sie die nach dem> Präprozessorschritt entstehende Datei extra ablegen soll.
Project Options -> C/C++ Compiler -> Tab "Preprocessor" -> Checkbox
"Preprocessor output to file"
Alexandre schrieb:> Klar kann C keine Namen Zerlegen, ich habe es einfach Index genannt weil> Lesbar.> Index wird auf 1 gesetzt> Und in der Makro wir Index auch verwendet
Ja, ist mir später auch aufgefallen.
Es ist für mich total ungewöhnlich, daß eine Funktion einen Parameter in
einer extra Variablen übergeben kriegt.
Sobald sie von einer Variablen im gleichen Kontext abhängt, übergebe ich
diese immer mit als Argument.
Damit wird dann der Zusammenhang deutlicher und es können weniger Fehler
passieren.
Hi,
Alexandre schrieb:> Der Versuch mit den {} hat es leider nicht gebracht.
ohne jetzt hämisch sein zu wollen ... hatte ich das nicht schon
vermutet?
> @Chris:> Ich verstehe (denke ich zumindest) zwar den Sinn, aber dachte es sollte
...
>> mfg,> Alexandre
Ich möchte Dir noch einmal empfehlen den Sourcecode nach dem
Preprozessor anzuschauen und zu lernen was der Preprozessor aus Deinen
Macros macht. Dann liest Du Dir noch einmal die Hinweise der anderen
durch und wird erkennen warum bestimmte Dinge so und nicht anders macht
und wo Dein Konzept eventuell krankt.
Nimm richtige Funktionen und lass den Compiler für dich optimieren.
#defines und Makros führen nur zu Problemen, insbesondere wenn man
Codefragmente damit abbilden will.
Ich benutze schon seit Jahren keine Makros mehr. Der Code macht das was
er soll und es gibt keine Überraschungen.
Wolfgang Heinemann schrieb:> und wird erkennen warum bestimmte Dinge so und nicht anders macht und wo> Dein Konzept eventuell krankt.
Und vielleicht fängst du ja dann doch auch einfach mal an, statt
des Makrogewurschtels kleine Funktionen zu nehmen.
Deklarier' sie “static”. Wenn der Compiler dann sieht, dass du sie
nur einmal benutzt, inlinet er sie ohnehin automatisch. Oder mach'
sie gleich “static inline”.
Dann hast du syntaktisch eine Funktion, mit einem ordentlichen (und
typenreinen) Parameter wenn nötig, mit einem ordentlich in {}
gefassten Rumpf.
(Edit: PittyJ war schneller. ;)
PittyJ schrieb:> #defines und Makros führen nur zu Problemen, insbesondere wenn man> Codefragmente damit abbilden will.
Jawohl! Und man denke auch mal dran dass enum (gerne auch anonym)
ebenfalls jede Menge dieses #define-Unsinns vermeiden kann. Es sind
nicht nur die Funktionen.
In den 1980er Jahren gab es mal eine Routersoftware. Die war komplett in
Assembler geschrieben. Die Software war dazu gedacht auf mickrige PC zu
setzen und für bestimmte Netzwerkkarten entwickelt worden.
Das gesamte Teil war mit mehreren MACRO-Layern geschrieben. Die
Konfiguration für die Netzwerkkarten war über defines gelöst.
Das Ding hat funktioniert, aber verstehen konnte man den gesamten Code
nicht, ich habe es jedenfalls nicht geschafft ...
Leider habe ich den Namen von der Software vergessen ... ist lange her.
Macros nutze ich schon ab und zu aber doch recht sparsam. Macros sind
kein Teufelswerk sondern ab und zu schon ganz nützlich. Manchmal kann
man damit etwas lesbarer gestalten ohne eine Funktion bauen zu müssen.
Ich halte übrigens den Hinweis auf enum für sinnvoll. Mit enums erhöhst
Du die Lesbarkeit und der Compiler kann Dich weiter bei der Vermeidung
von Fehlern unterstützen. Bei vielen defines interessiert der
eigentliche Wert ja nicht.
Hallo zusammen,
War leider bis jetzht in einer Besprechung, und bin Morgen an einer
Ausstellung, nicht dass ihr meint es sei mir nun alles Wurst.
Aber ich denke Freitag sollte ich mich wieder daran machen können, und
es auch so ändern dass es sauber ist.
Vielen Dank,
Alexandre
P.S.: Tolles Forum, und soooooooo schnell !!!
Hallo zusammen,
Also irgendwie ist mein Freitag-post verloren gegangen.
Ich habe das ganze also über inline gemacht.
Nun hab ich auch ein gutes Gewissen.
Das mit dem *i file ist nun auch eingerichtet, somit ich das ganze auch
genauer anschauen kann.
Vielen Dank noch,
mfg,
Alexandre