Hallo Forenuser. ich habe mir aus den Codebeispielen diese schönen Zeilen zum setzen und löschen von Bits kopiert #define setbit(ADDRESS,BIT) (ADDRESS |= (1<<BIT)) Nun möchte ich aber dieses weitertreiben, so dass ich Proceduren auch auf anderen Ports oder anderen Prozessoren benutzen kann. also z.B. einen gepulsten Port für IR-Kommunikation. Wenn ich das in dieser Form mache #define ir_transmit PORTA,PA6 gibts einen Fehler bei setbit(ir_transmit); mit der Begründung macro "setbit" requires 2 arguments, but only 1 given Die Fehlermeldung ist klar. Versteht der Compiler nicht, dass es sich bei ir_transmit um 2 Argumente handelt? Wie macht man es richtig?
> Versteht der Compiler nicht, dass es sich bei ir_transmit um 2 > Argumente handelt? Für den Präprozessor ist es nur 1 Argument. > Wie macht man es richtig?
1 | #define s(a,b) do { (a) |= 1 << (b); } while (0)
|
2 | #define setbit(x) s(x)
|
3 | #define x PORTD,2
|
4 | |
5 | setbit(x) |
Schräg, ja, ich weiß. :-)
Das SETBIT ist selbst schon ein Makro. Der Präprozessor merkt sich eine Liste von allen Defines zum späteren ersetzen. Wenn im Sourcecode die vorgesehene Ersetzung von SETBIT vor der Ersetzung von IR_TRANSMIT abgearbeitet wird, kommt die Fehlermeldung. Du müsstest zusehen, dass das define von IR_TRANSMIT dem Präprozessor zuerst bekannt wird. Tipp: Wenn man Makros grundsätzlich nur in Grossbuchstaben schreibt, sieht man eher was im Sourcecode los ist.
"Schräg, ja, ich weiß. :-)" Wow ! Die Typüberprüfung erfolgt also nur bei der ersten Macroexpansion und läßt sich durch 3-fach Macros überlisten. Ist das nun ein Bug oder ein Feature des AVR-GCC ? Ist das auch bei anderen Compilern so ? Peter P.S.: Muß ich gleich mal ausprobieren.
ich schließe mich dem wow an. Wäre Stefans lösung auch ok? Dann bliebe nämlich die Funktion von SETBIT für einzeln zu setzende Bits erhalten oder führt das ggf zu anderen Problemen?
> Ist das nun ein Bug oder ein Feature des AVR-GCC ? Kein Bug! Schau mal da: http://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.html#Macro-Arguments Wichtig ist folgender Abschnitt: All arguments to a macro are completely macro-expanded before they are substituted into the macro body. After substitution, the complete text is scanned again for macros to expand, including the arguments. This rule may seem strange, but it is carefully designed so you need not worry about whether any function call is actually a macro invocation. You can run into trouble if you try to be too clever, though. See Argument Prescan, for detailed discussion. > Ist das auch bei anderen Compilern so ? Das ist das im ISO-Standard so vorgesehen. Allerdings gab es in der Vergangenheit etliche Compiler bzw. Präprozessoren (einschließlich derjenigen von Microsoft), die diese Regel falsch umsetzten, so dass das entweder beim Konstrukt von flyingwolf fälschlicherweise kein Fehler oder bei dem von Jörg fälschlicherweise ein Fehler ausgegeben wurde.
@ flyingwolf Kann ich selbst beantworten: Vergiss es wieder. Klappt nicht! Habe es gerade ausprobiert. Sorry!
Die Variante von Jörg funktioniert auch bei Digital Mars, nicht jedoch bei Microsoft (warning C4003: Nicht genügend übergebene Parameter für das Makro 'setbit2'). Eine Variante, die aber bei allen korrekten Präprozessoren funktionieren sollte, und die sich elegant auf Funktionen auf die PINA/DDRA Register erweitert:
1 | #define ir_transmit_PORT A
|
2 | #define ir_transmit_PIN 6
|
3 | |
4 | #define p_port(x) x##_PORT
|
5 | #define p_pin(x) x##_PIN
|
6 | #define p_in(x) PIN##x
|
7 | #define p_out(x) PORT##x
|
8 | #define p_dir(x) DDR##x
|
9 | #define pp_in(x) p_in(x)
|
10 | #define pp_out(x) p_out(x)
|
11 | #define pp_dir(x) p_dir(x)
|
12 | |
13 | #define testbit(x) (pp_in(p_port(x)) & 1<<p_pin(x))
|
14 | #define setbit(x) (pp_out(p_port(x)) |= 1<<p_pin(x))
|
15 | #define clrbit(x) (pp_out(p_port(x)) &= ~(1<<p_pin(x)))
|
16 | #define setout(x) (pp_dir(p_port(x)) |= 1<<p_pin(x))
|
17 | #define setinp(x) (pp_dir(p_port(x)) &= ~(1<<p_pin(x)))
|
18 | |
19 | void
|
20 | f(void) |
21 | {
|
22 | if (testbit(ir_transmit)) { |
23 | do_something(); |
24 | }
|
25 | setout(ir_transmit); |
26 | setbit(ir_transmit); |
27 | }
|
Resultat ist:
1 | void
|
2 | f(void) |
3 | {
|
4 | if ((PINA & 1<<6)) { |
5 | do_something(); |
6 | }
|
7 | (DDRA |= 1<<6); |
8 | (PORTA |= 1<<6); |
9 | }
|
Die Variante von Volker ist aber auch nicht schlecht: http://www.mikrocontroller.net/forum/read-1-324854.html#new Da hat man sogar wieder die vom 8051 gewohnten Bitvariablen. Also ideal, um C51 Programme zu portieren. Peter
Bitfelder werden vom Compiler leider meist ausgesprochen ineffizient implementiert.
Bitfelder = struct? Da habe ich letztens was interessantes gesehen. Alle Variablen waren in einer Struktur definiert auch die 1-Bit-Vars und dann wurde die ganze Structur ins EEProm geschrieben.
Also ich hab das mit den Bitfeldern ausprobiert. Zumindest der AVR-GCC macht dann die SBI- und CBI-Befehle draus, ganz so wie es sein soll. Peter
Hi, >Also ich hab das mit den Bitfeldern ausprobiert. >Zumindest der AVR-GCC macht dann die SBI- und CBI-Befehle draus, ganz >so wie es sein soll. @Peter Weisst du wie es bei Keil und 8051er aussieht? Gruß, Dirk
Solange es um einzelne Bits geht, kann der Compiler was draus machen - wenngleich ich auch schon abschreckende Beispiele gesehen habe (weiss bloss nicht mehr wo). Der Haken bei Bitfeldern liegt aber wesentlich auch darin, dass man keine Chancen hat, es besser zu machen. Jedenfalls nicht solange man bei den Bitfeldern bleibt und nicht nebenbei noch die klassischen Register und Bits pflegt. Sowas wie ControlRegister |= 1<<Enable | 1<<CrashAndBurn; ist bei Bitfeldern nicht drin, und ControlRegister.Enable = 1; ControlRegister.CrashAndBurn = 1; darf bei dem natürlich als "volatile" deklarierten ControlRegister kein Compiler legal zusammenfassen (wenngleich SDCC sowas ähnliches fertigbringt). Mit CBI/SBI ist das ok, u.U. sogar besser, bei nicht bitweise adressierbaren Adressen zieht sich das jedoch arg in die Länge.
"Weisst du wie es bei Keil und 8051er aussieht?" Beim Keil kann man mit "sbit" einzelne Bits einer bitadressierbaren Variable definieren. Näheres im Keil Handbuch oder auf deren Webseite (Knowledegbase). Peter
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.