Forum: Mikrocontroller und Digitale Elektronik Präprozessor-Makro verschachteln


von __Son´s B. (bersison)


Lesenswert?

Hallo - beisse mir immer noch die Zähne an folgendem Proible aus.

Ich würde gerne aus;
  #define AUSGANG_SET_HIGH(port,mask) ((port) |= (1<<mask))
  #define BATT_ON (AUSGANG_SET_HIGH(PORTA,PA4))
(Funktioniert einwandfrei!)

solch eine Parametrierung machen;
  #define AUSGANG_SET_HIGH(port,mask) ((port) |= (1<<mask))
  #define PORT_BATT_OUT(PORTA,PA4)
  #define BATT_ON (AUSGANG_SET_HIGH(PORT_BATT_OUT))
Compiler meckert!

Obwohl nach meine Verständnis folgender Ersatz raus kommen sollte;
  #define BATT_ON (AUSGANG_SET_HIGH((PORTA,PA4)))

Auch ohne Leerzeichen zw. BATT_ON(AUSG...) klappts nicht.
Syntaxfehler?

von Georg G. (df2au)


Lesenswert?

__Son´s B. schrieb:
> #define PORT_BATT_OUT(PORTA,PA4)

Da fehlt ein Leerzeichen.
#define PORT_BATT_OUT (PORTA,PA4)

von DerDan (Gast)


Lesenswert?

Hallo

und obwohl bei deinem Verständnis was anders rauskommt als bei deiner 1. 
Lösung ist der Compiler schuldig ???

__Son´s B. schrieb:
> Obwohl nach meine Verständnis folgender Ersatz raus kommen sollte;
#define BATT_ON (AUSGANG_SET_HIGH((PORTA,PA4)))

__Son´s B. schrieb:
> #define BATT_ON (AUSGANG_SET_HIGH(PORTA,PA4))

zähl doch einfach mal die Anzahl der Klammern nach ...

mfg

DerDan

von __Son´s B. (bersison)


Lesenswert?

DerDan schrieb:
> zähl doch einfach mal die Anzahl der Klammern nach ...
???
Wie sieht dein Lösungsansatz aus?

von __Son´s B. (bersison)


Lesenswert?

Georg G. schrieb:
> Da fehlt ein Leerzeichen.
> #define PORT_BATT_OUT (PORTA,PA4)

Ob mit oder ohne Leerzeichen verändert nichts!

von Tom (Gast)


Lesenswert?

Was man nicht alles tun muss, um die bösen performance-mordenden 
Funktionen zu vermeiden...

von __Son´s B. (bersison)


Lesenswert?

Tom schrieb:
> Was man nicht alles tun muss, um die bösen performance-mordenden
> Funktionen zu vermeiden...
Deine Bemerkung kann ich gut nachvollziehen.

Versuche aktuell alle Grundparameter, Ports und Pins in einem 
Makro-Block zu hinterlegen. Die PORT/PIN-Zuweisung ist der letzte 
Schritt.

von Peter D. (peda)


Lesenswert?

Tom schrieb:
> Was man nicht alles tun muss, um die bösen performance-mordenden
> Funktionen zu vermeiden...

Niemand muß sowas, es gibt bessere Möglichkeiten, z.B.:
1. Portpins als Bitvariablen definieren
2. Inline-Funktionen

__Son´s B. schrieb:
> Compiler meckert!

Gehts bitte noch ungenauer?
Copy&Paste den genauen Fehlertext!
Hänge den Quelltext als Anhang an, dann kann man sogar die Zeilennummer 
in der Meldung zuordnen.

von __Son´s B. (bersison)


Angehängte Dateien:

Lesenswert?

Peter D. schrieb:
> Copy&Paste den genauen Fehlertext!
> Hänge den Quelltext als Anhang an, dann kann man sogar die Zeilennummer
> in der Meldung zuordnen.
siehe Anhang.

von Walter S. (avatar)


Lesenswert?

nicht der Fehler aber damit wirst Du dir ins Knie schießen:

#define LED_OFF (AUSGANG_SET_LOW(PORTA,PA5)); 
(AUSGANG_SET_LOW(PORTA,PA6)); (AUSGANG_SET_LOW(PORTA,PA7))  // alle LEDs 
werden gelöscht

was kommt da raus wenn du

if ( quark )
 LED_OFF;

schreibst?

von __Son´s B. (bersison)


Lesenswert?

Walter S. schrieb:
> nicht der Fehler aber damit wirst Du dir ins Knie schießen:
Warum?

Alle 3 LEDs liegen auf low.
Funktioniert tatsächlich einwandfrei!

von Walter S. (avatar)


Lesenswert?

__Son´s B. schrieb:
> Alle 3 LEDs liegen auf low.
> Funktioniert tatsächlich einwandfrei!

nee,
die erste geht auf LOW wenn quark true ist
die beiden anderen gehen IMMER auf LOW

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


Lesenswert?

__Son´s B. schrieb:
> Warum?

Du solltest dir hin und wieder mal ansehen, was aus dem Präprozessor
so hinten „herausfällt“.  (avr-gcc ... -E)  Dann würde dir vielleicht
auffallen, dass der Präprozessor von C keine Ahnung hat sondern stur
Texte ersetzt, und vielleicht entdeckst du dann auch mal das unsinnige
Semikolon im Zeichenstrom. ;)

Ansonsten funktioniert das, was du machen willst, zweistufig.

Ich hatte meine Lösung schon mal gepostet, auch wenn sie „W.S.“ nicht
gefiel. ;-)
1
#define GLUE(a, b)     a##b
2
3
/* single-bit macros, used for control bits */
4
#define SET_(what, p, m) GLUE(what, p) |= (1 << (m))
5
#define CLR_(what, p, m) GLUE(what, p) &= ~(1 << (m))
6
#define GET_(/* PIN, */ p, m) GLUE(PIN, p) & (1 << (m))
7
#define SET(what, x) SET_(what, x)
8
#define CLR(what, x) CLR_(what, x)
9
#define GET(/* PIN, */ x) GET_(x)
10
11
#define ASSIGN_(what, p, m, v) GLUE(what, p) = (GLUE(what, p) & \
12
                                                ~((1 << (m)) | (1 << ((m) + 1)) | \
13
                                                  (1 << ((m) + 2)) | (1 << ((m) + 3)))) | \
14
                                                ((v) << (m))
15
#define READ_(what, p, m) (GLUE(what, p) & ((1 << (m)) | (1 << ((m) + 1)) | \
16
                                            (1 << ((m) + 2)) | (1 << ((m) + 3)))) >> (m)
17
#define ASSIGN(what, x, v) ASSIGN_(what, x, v)
18
#define READ(what, x) READ_(what, x)
19
20
...
21
  SET(PORT, HD44780_E);
22
    x = READ(PIN, HD44780_D4);
23
  CLR(PORT, HD44780_E);
24
...
25
  CLR(PORT, HD44780_RW);
26
  if (rs)
27
    SET(PORT, HD44780_RS);
28
  else
29
    CLR(PORT, HD44780_RS);
30
  ASSIGN(PORT, HD44780_D4, n);

Die HD44780_x-Makros sind dabe projektabhängig definiert:
1
#define HD44780_RS A, 6
2
#define HD44780_RW A, 5
3
#define HD44780_E  A, 4
4
/* The data bits have to be not only in ascending order but also consecutive. */
5
#define HD44780_D4 A, 0

Wenn du obiges mal auf besagte Weise durch den Präprozessor schickst,
siehst du, was er da draus zimmert.

von __Son´s B. (bersison)


Lesenswert?

Walter S. schrieb:
> die beiden anderen gehen IMMER auf LOW
Schau dir die beiden darüber liegenden Makros an - da geht nichts nach 
der ersten Anweisung IMMER auf LOW!

Da diese Anweisung einwandfrei funktioniert, konzentriere ich mich 
lieber auf das was nicht klappt;

__Son´s B. schrieb:
> solch eine Parametrierung machen;
>   #define AUSGANG_SET_HIGH(port,mask) ((port) |= (1<<mask))
>   #define PORT_BATT_OUT(PORTA,PA4)
>   #define BATT_ON (AUSGANG_SET_HIGH(PORT_BATT_OUT))
> Compiler meckert!

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

__Son´s B. schrieb:
> Schau dir die beiden darüber liegenden Makros an - da geht nichts nach
> der ersten Anweisung IMMER auf LOW!

Doch. Dicker Fehler, den Du nur noch nicht verstanden hast.

Ich vereinfache mal, dann wird es klarer:
1
#define A()       a();b();c();
2
...
3
if (x)
4
   A()

Was macht der Preprocessor draus?
1
if (x)
2
   a();b();c();

Das kann man ohne Code-Änderung umschreiben in:
1
if (x)
2
   a();
3
b();
4
c();
Da ohne geschweiften Klammern nur a() im if-Block steckt, werden b() und 
c() IMMER ausgeführt, egal, ob man es nebeneinander oder untereinander 
schreibt.

Merke: Wenn Du sagst: "Es funktioniert aber", dann heisst das lediglich, 
dass Du es nur im falschen Kontext getestet/überdacht hast - hier 
nämlich für x != 0.

von Georg G. (df2au)


Lesenswert?

__Son´s B. schrieb:
> Ob mit oder ohne Leerzeichen verändert nichts!

Aber die Bedeutung der Zeile ist mit und ohne Leerzeichen drastisch 
anders. Du hast eben mehr als nur einen Fehler drin.

von __Son´s B. (bersison)


Lesenswert?

Frank M. schrieb:
> Da ohne geschweiften Klammern nur a() im if-Block steckt, werden b() und
> c() IMMER ausgeführt,
Klar, passt doch!
Aber nicht, wie Walter S schrieb; "IMMER auf LOW".

Bsp: Folgend sollen alle 3 Befehle nacheinander ausgeführt werden;
...
#define LED_LOW (AUSGANG_SET_LOW(PORTA,PA5)); 
(AUSGANG_SET_LOW(PORTA,PA6)); (AUSGANG_SET_HIGH(PORTA,PA7))
...
LED_LOW;
...
Somit LED_high aus, LED_mid aus, LED_low ein.
Funktioniert auch Live nach dem 1000-sten mal.

Oder meinst du, dass es eine "unsaubere" Syntax ist?

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


Lesenswert?

__Son´s B. schrieb:
> Oder meinst du, dass es eine "unsaubere" Syntax ist?

Ja, ist es. Er schrieb ja auch, warum.  Wenn du schreibst:
1
  if (some_event)
2
    LED_LOW();

… dann erwartest du vermutlich, dass die LEDs nur dann alle geschaltet
werden, wenn „some_event“ eintrifft, und nicht nur der Ausgang auf PA5
von der Bedingung abhängt.

von __Son´s B. (bersison)


Lesenswert?

Jörg W. schrieb:
> if (some_event)
>     LED_LOW();
Verstehe - habe die Makros bis jetzt in if{}, Abläufen oder case 
eingebunden.

von Walter S. (avatar)


Lesenswert?

__Son´s B. schrieb:
> Klar, passt doch!
> Aber nicht, wie Walter S schrieb; "IMMER auf LOW".

dann lies das noch Mal:

Walter S. schrieb:
> nicht der Fehler aber damit wirst Du dir ins Knie schießen:
>
> #define LED_OFF (AUSGANG_SET_LOW(PORTA,PA5));
> (AUSGANG_SET_LOW(PORTA,PA6)); (AUSGANG_SET_LOW(PORTA,PA7))  // alle LEDs
> werden gelöscht
>
> was kommt da raus wenn du
>
> if ( quark )
>  LED_OFF;
>
> schreibst?


das wird zu:
if ( quark )
 LED1 low;

LED2 low;
LED3 low;

2 und 3 werden also IMMER low

von __Son´s B. (bersison)


Lesenswert?

Walter S. schrieb:
> 2 und 3 werden also IMMER low
in dem Fall soll das auch so sein!
Da bei mir if-Anweisungen in {} stehen, ist die Problematik noch nicht 
aufgefallen.

Lösungsvorschlag von Jörg Wunsch liest sich (als Anfänger) äusserst 
aufwendig.

von Walter S. (avatar)


Lesenswert?

__Son´s B. schrieb:
> Lösungsvorschlag von Jörg Wunsch liest sich (als Anfänger) äusserst
> aufwendig.

ja, ist aber leider so
Aber warum nimmst du nicht inline-Funktionen, du ersparst dir vieles und 
die Laufzeit wirst du normalerweise nicht merken

von __Son´s B. (bersison)


Lesenswert?

Walter S. schrieb:
> Aber warum nimmst du nicht inline-Funktionen
Mag blöd klingen, aber ich finde blockartige Makros im Header einfacher, 
transparenter und schneller zu erfassen...

von Kirsch (Gast)


Lesenswert?

Ob es schön ist, ist eine andere Sache, aber so kann man diese Aufrufe 
kapseln
1
#define A()       do{a();b();c();}while(0)

von nicht"Gast" (Gast)


Lesenswert?

__Son´s B. schrieb:
> Mag blöd klingen, aber ich finde blockartige Makros im Header einfacher,
> transparenter und schneller zu erfassen...

Geil,

du bist selbt der beste Gegenbeweis, dass dem nicht so ist. Du siehst 
bei deinem relativ einfachen Code selber nicht schon durch und auch kein 
anderer kann die wirklich helfen, finden aber Fehler, die du nicht 
siehst.

Vieeeeeeel transparenter.

von nicht"Gast" (Gast)


Lesenswert?

Oo

die vielen Fehler und Wortdreher einfach weg denken.

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


Lesenswert?

__Son´s B. schrieb:
> Lösungsvorschlag von Jörg Wunsch liest sich (als Anfänger) äusserst
> aufwendig.

Den Aufwand hatte aber nur ich damit, mir das auszudenken. ;-)

Du kannst den Kram einfach in einen Header packen und benutzen.

Der wesentliche Trick ist die doppelte Verschachtelung, also ein
FOO(), welches dann ein FOO_() aufruft.  Der weitere Aufwand, den
ich getrieben habe, dient dann nur dazu, die AVR-Eigenheit der
heiligen Registerdreifaltigkeit (PORTx, PINx, DDRx) so abzubilden,
dass man das „x“ nur an genau einer Stelle im Headerfile schreiben
muss.

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.