Dumme? Frage zum Präprozessor

Gast #759039
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
Gast #759053
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);
Gast #759062
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
Moderator Persönliche Seite #759063
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
}
#759066
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.
Moderator Persönliche Seite #759073
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
Moderator Persönliche Seite #759077
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.
Gast #759079
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
*/
Gast #759081
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren