Forum: PC-Programmierung Makro im Makro C


von Dennis A. (dennis999)


Lesenswert?

Hallo,

ich würde gerne meinen C-Code etwas kompakter mit Makros darstellen. 
Hatte da zwei verschiedene Ideen um ein Makro zum ändern von PINs zu 
erstellen.
1
#define TOGGLE(PORT,SDA,SCL) \
2
  ##PORTSEL &=  ~BIT##SDA; \
3
  ##PORTSEL &=  ~BIT##SCL; \
4
  ##PORTOUT &=  ~BIT##SCL; \
5
  ##PORTOUT &=  ~BIT##SDA; \
6
  ##PORTDIR |=   BIT##SCL; \
7
  ##PORTDIR &=  ~BIT##SDA; \
8
  break;
9
10
TOGGLE(P3,4,5)
1
#define TOGGLE(PORT,SDA,SCL) \
2
  P##PORTSEL &=  ~BIT##SDA; \
3
  P##PORTSEL &=  ~BIT##SCL; \
4
  P##PORTOUT &=  ~BIT##SCL; \
5
  P##PORTOUT &=  ~BIT##SDA; \
6
  P##PORTDIR |=   BIT##SCL; \
7
  P##PORTDIR &=  ~BIT##SDA; \
8
  break;
9
10
TOGGLE(3,4,5)

## am Anfang einer Zeile scheint der Compiler (IAR Workbench; MSP430) 
nicht zu mögen. Und innerhalb mag er es auch nicht - "identifier 
PPORTSEL is undefined"

Vielleicht weiß ja jemand, ob es überhaupt möglich ist in ein Makro in 
ein anderes einzusetzen und wie man das am besten macht.

von Sven P. (Gast)


Lesenswert?

Haben die beiden Doppelkreuze vor PORTSEL denn einen tieferen Sinn? Was 
ist denn PORTSEL überhaupt?

von Dennis A. (dennis999)


Lesenswert?

Das Problem ist, dass PXSEL die Funktion des PORTs auswählt (also I/O 
etc), und selbst ein Makro ist. Hinter P3SEL steht z.B. 0x001B. Daneben 
gibt es dann eben noch P2SEL etc.

Und eben dieses Port-Nummer (X) soll durch den Makroparaemter PORT 
ersetzt werden.

Analog ist gilt dass dann auch für PXOUT und PXDIR.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Das '##' muss zwischen den Makroargumenten und dem Text stehen, mit dem
sie verbunden werden sollen:
1
#define P3SEL (*(volatile unsigned char *)0x001B)
2
#define P3OUT (*(volatile unsigned char *)0x001C)
3
#define P3DIR (*(volatile unsigned char *)0x001D)
4
5
#define TOGGLE1(port,sda,sdl) do {\
6
  port##SEL &=  ~BIT##sda; \
7
  port##SEL &=  ~BIT##sdl; \
8
  port##OUT &=  ~BIT##sda; \
9
  port##OUT &=  ~BIT##sdl; \
10
  port##DIR |=   BIT##sda; \
11
  port##DIR &=  ~BIT##sdl; \
12
  } while(0)
13
14
TOGGLE1(P3,4,5);
15
16
#define TOGGLE2(port,sda,sdl) do {\
17
  P##port##SEL &=  ~BIT##sda; \
18
  P##port##SEL &=  ~BIT##sdl; \
19
  P##port##OUT &=  ~BIT##sda; \
20
  P##port##OUT &=  ~BIT##sdl; \
21
  P##port##DIR |=   BIT##sda; \
22
  P##port##DIR &=  ~BIT##sdl; \
23
  } while(0)
24
25
TOGGLE2(3,4,5);

Zum Testen habe ich P3SEL usw. mal irgendwie definiert. Die Definitionen
in den Headerfiles werden natürlich etwas davon abweichen. Der do-while-
Trick dient dazu, aus mehreren Anweisungen eine einzige zu machen, so
dass das Makroaufruf syntaktisch gleich wie eine Funktion verwendet
werden kann (auch in if-Anweisungen u.ä.).

Präprozessorausgabe für beide Makros:
1
do {
2
  (*(volatile unsigned char *)0x001B) &= ~BIT4;
3
  (*(volatile unsigned char *)0x001B) &= ~BIT5;
4
  (*(volatile unsigned char *)0x001C) &= ~BIT4;
5
  (*(volatile unsigned char *)0x001C) &= ~BIT5;
6
  (*(volatile unsigned char *)0x001D) |=  BIT4;
7
  (*(volatile unsigned char *)0x001D) &= ~BIT5;
8
} while(0);

von Dennis A. (dennis999)


Lesenswert?

Ok hab's herausgefunden:
1
#define TOGGLE(PORT,SDA,SCL) \
2
    P##PORT##SEL &=  ~BIT##SDA; \
3
    P##PORT##SEL &=  ~BIT##SCL; \
4
    P##PORT##OUT &=  ~BIT##SCL; \
5
    P##PORT##OUT &=  ~BIT##SDA; \
6
    P##PORT##DIR |=   BIT##SCL; \
7
    P##PORT##DIR &=  ~BIT##SDA; \
8
    break;
9
10
TOGGLE(2,3,4)
11
TOGGLE(1,2,3)
12
...

Falls nach dem Makroparameter noch was kommt, muss man ## nach dem 
Makroparameter setzen.

von Dennis A. (dennis999)


Lesenswert?

Danke  Yalu. Hab deine Antwort leider erst nach meinem Post gelesen.

Vielleicht weiß noch jemand wie ich ein Makro in " " einbinden kann.

z.B. bei folgendem Code:
1
#define TEST(ID) \
2
   uartSendstr("Mein Parameter ist ID");
3
4
TEST(1)
5
TEST(2)
6
...

Dabei will die Funktion uartSendstr( *char ) übergeben haben.

Habe es mit ID, ##ID, ##ID## ausprobiert. Aber die Ausgabe ist immer ID, 
##ID oder ##ID## und nicht der gewünschte Makroparameter 1, 2...

Mir ist nicht ganz klar woran das liegt, denn der Präprozessor sollte 
doch ID einfach stur ersetzen können? Oder übergeht der das wegen den 
Anführungszeichen?

von Sven P. (Gast)


Lesenswert?

Dennis A. schrieb:
1
#define TEST(ID) \
2
   uartSendstr("Mein Parameter ist " #ID);
3
4
TEST(1)
5
TEST(2)
6
...


> Mir ist nicht ganz klar woran das liegt, denn der Präprozessor sollte
> doch ID einfach stur ersetzen können? Oder übergeht der das wegen den
> Anführungszeichen?
Ne, Token-Paste (##) funktioniert meistens immer nur bei Bezeichnern. 
Der Präpro zieht aber hintereinanderstehende Strings zu einem zusammen, 
daher kann man die ID mit dem Stringify-Operator (#) zum String machen.

von Dennis A. (dennis999)


Lesenswert?

Super funktioniert. Vielen Dank.

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.