Forum: Compiler & IDEs Dumme? Frage zum Präprozessor


von Rolle (Gast)


Lesenswert?

Hallo,

ich bin noch relativer Anfänger und habe eine Frage:
Folgendes sollte funktionieren:

Am Anfang des Programms:

#define Ausgabeport1 PortB
#define Ausgabeport2 PortC
#define GLUE(a, b)     a##b
#define PORT(x)        GLUE(PORT, x)

#define SET(bit) Ausgabeport1 |= _BV(bit))
#define RESET(bit) Ausgabeport1 &= ~_BV(bit)
#define OUT_RESET 4
#define OUT_Start 5

Irgendwo im Programm:
SET(OUT_RESET)
RESET(OUT_RESET)
SET(OUT_START)

SET und RESET setzen also das definierte Bit in PortB.
Nun die Frage: Wie kann ich die Definition für den Präprozessor so 
abändern, dass durch Nutzung der definierten Port-Bits wie z.B. 
OUT_START auch der Port (Ausgabeport1 oder Ausgabeport2) vorab definiert 
werden kann?
Beispiel: OUT_RESET soll also z.B. Port B4 sein
und OUT_START soll Port C5 sein.

Ich möchte aber trotzdem eine Routine Set / Reset haben. D.h mit SET 
(OUT_START) wird C5 gesetzt und mit SET(OUT_RESET) wird B4 gesetzt. Ich 
komme hier nicht weiter. Danke für die Hilfe

von die ??? (Gast)


Lesenswert?

1
#define Ausgabeport1 PortB
2
#define Ausgabeport2 PortC
3
#define GLUE(a, b)     a##b
4
#define PORT(x)        GLUE(PORT, x)
5
6
#define SET((bit), (port))     ( (port) |= _BV(bit) )
7
#define RESET((bit), (port))   ( (port) &= ~_BV(bit) )
8
#define OUT_RESET 4
9
#define OUT_Start 5
10
11
// ...
12
13
SET(OUT_RESET, Ausgabeport1);

von Rolle (Gast)


Lesenswert?

Oh, die drei Fragezeichen sind auch hier :-)
Das ging ja fix.

Danke für die Hilfe. Das hilft mir schon mal weiter. Ich vermute also, 
dass es nicht möglich mittels #define OUT_RESET .... direkt den Port 
zuzuweisen, so dass ein einfaches
SET(OUT_RESET) für PortB.4 und ein
SET(OUT_START)  für Port C.5 reicht?

Danke nochmals

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

1
#define OUT_RESET B,4
2
#define OUT_START C,5
3
4
#define GLUE(a, b) a##b
5
#define PORT(x) GLUE(PORT,x)
6
7
#define SET_(p, b) PORT(p) |= (1 << (b))
8
#define RESET_(p, b) PORT(p) &= ~(1 << (b))
9
#define SET(...) SET_(__VA_ARGS__)
10
#define RESET(...) RESET_(__VA_ARGS__)
11
12
#include <avr/io.h>
13
14
void
15
foo(void)
16
{
17
        SET(OUT_RESET);
18
        RESET(OUT_START);
19
        SET(OUT_START);
20
}

von Karl H. (kbuchegg)


Lesenswert?

> #define SET(...) SET_(_VA_ARGS_)
> #define RESET(...) RESET_(_VA_ARGS_)

Jetzt bin ich verblüfft.
Das geht ?!?

Ist das Standard oder eine gcc Erweiterung?

#define OUT_RESET B,4
Mit derselben Idee habe ich auch rumgespielt, bin aber an der
falschen Makro Auswertereihenfolge gescheitert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl heinz Buchegger wrote:

> Ist das Standard oder eine gcc Erweiterung?

C99, wobei's der GCC auch im gnu89-Mode (das ist der Default) bereits
kennt.

_VA_ARGS_ löst insbesondere endlich den gordischen Knoten mit den
Debug-printf()s.  Man möchte sie verwenden wie printf() (also mit
variabler Argumentliste), aber sie sollen so als Makro implementiert
sein, dass sie im Nicht-Debug-Code zu rein gar nichts evaluieren.
Das ging im C90 gar nicht.  Im C99 geht es als:
1
#if DEBUG
2
#  define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
3
#else
4
#  define DPRINTF(...) /* nothing */
5
#endif

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

p.s.: Der Trick hier ist allerdings nur die doppelte Auswertung durch
den Präprozessor, ... und _VA_ARGS_ braucht man nicht unbedingt
dafür.  Das hier geht auch, und ist plain ISO C90 compliant:
1
#define OUT_RESET B,4
2
#define OUT_START C,5
3
4
#define GLUE(a, b) a##b
5
#define PORT(x) GLUE(PORT,x)
6
7
#define SET_(p, b) PORT(p) |= (1 << (b))
8
#define RESET_(p, b) PORT(p) &= ~(1 << (b))
9
#define SET(x) SET_(x)
10
#define RESET(x) RESET_(x)
11
12
#include <avr/io.h>
13
14
void
15
foo(void)
16
{
17
        SET(OUT_RESET);
18
        RESET(OUT_START);
19
        SET(OUT_START);
20
}

Ich hatte die __VA_ARGS__-Variante halt nur zuerst ausprobiert.

von let (Gast)


Lesenswert?

Das müßte portabel sein (geht zumindest auch mit Codevision):
1
/* Code to manipulate PORTx, PINx, and DDRx using definitions like those above */
2
#define PORT(port,pin)     (PORT##port)
3
#define DDR(port,pin)      (DDR##port)
4
#define PIN(port,pin)      (PIN##port)
5
#define PIN_MASK(port,pin) (1<<(pin))
6
7
/* Set a pin */
8
#define SETPIN(pindef)      PORT pindef |= PIN_MASK pindef
9
10
/* Clear a pin */
11
#define CLRPIN(pindef)      PORT pindef &= ~PIN_MASK pindef
12
13
/* Get pin value */
14
#define GETPIN(pindef)      (PIN pindef & PIN_MASK pindef)
15
16
/* Toggle a pin */
17
#define TOGGLEPIN(pindef)   PIN pindef |= PIN_MASK pindef
18
19
/* Set a IO to output */
20
#define SET_DDR_OUT(pindef) DDR pindef |= PIN_MASK pindef
21
22
/* Set a IO to input */
23
#define SET_DDR_IN(pindef)  DDR pindef &= ~PIN_MASK pindef
24
25
/* Read the value of a pin - a byte with the correspondig bit set or cleard is returned.
26
   Example:
27
28
   #define PIN7 (D, 7)
29
   ...
30
   SETPIN(PIN7);
31
   x = GETPIN(PIN7);
32
  { x = 128 }
33
*/

von let (Gast)


Lesenswert?

Ups, hatte ich vergessen:
1
/* Alternate port access macros from avr-gcc list */
2
/* http://lists.gnu.org/archive/html/avr-gcc-list/2004-12/msg00097.html */
3
/* Dave Hylands */
Ist also nicht auf meinen Mist gewachsen.

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
Noch kein Account? Hier anmelden.