Forum: Mikrocontroller und Digitale Elektronik #define soll gleichzeitig Setzen und Löschen


von Stephan R. (Gast)


Lesenswert?

Moin!

Frage vorweg: wie heisst das, was man durch ein #define definiert?

Frage hinterher: ich habe am Atmega einen Demux angeschlossen, der 3 
Adress-Eingänge besitzt, welche an den Atmega-Ports hängen.

A0  A1  A2  Y
0   0   0   0
1   0   0   1
0   1   0   2
1   1   0   3
0   0   1   4

Nun möchte ich gern durch ein einfaches

#define dmux_input_(0-4)

machen, dass die entsprechende Bitmaske gesetzt wird. Ich kenne aber nur 
Maskierungen, bei denen gleichzeitig ein oder mehrere Bits gesetzt (bzw. 
gelöscht) werden, nicht aber gesetzt UND gelöscht.
Wie tut Mann das?

von Εrnst B. (ernst)


Lesenswert?

Stephan R. schrieb:
> ... bei denen gleichzeitig ein oder mehrere Bits gesetzt (bzw. gelöscht) ...

Dann mach das doch:

#define SET_MUX(x) do { PORTX=(PORTX & ~0x07)|(x) } while (0)

und falls es ohne klammer gehen soll:

#define SET_MUX_1 SET_MUX(1)

Stephan R. schrieb:
> Frage vorweg: wie heisst das, was man durch ein #define definiert?

"Makro". ist eine reine Text-Ersetzung, die noch VOR dem Kompilieren 
ausgeführt wird.

von Stephan R. (Gast)


Lesenswert?

Dacht ich auch zuerst, aber der restliche Port wird auch verwendet, es 
dürfen also nur PORTC0 bis PORTC3 verändert werden.

von Εrnst B. (ernst)


Lesenswert?

Stephan R. schrieb:
> Dacht ich auch zuerst, aber der restliche Port wird auch verwendet, es
> dürfen also nur PORTC0 bis PORTC3 verändert werden.

Genau das macht das Makro doch.
Zuerst wird 0x07 invertiert, ergibt eine Bitmaske 0b11111000.

der PORTC-Zustand wird damit ver-UND-et, d.H. alle bits bis auf die 
untersten drei bleiben wie sie sind.

Danach wird der Makro-Parameter dazu ver-ODER-t, es werden also 
zusätzlich wieder bits gesetzt.

Solange X keine bits anfasst, die es nicht darf, bleibt der Rest von 
PORTC also unverändert.

Wenn du dir selbst nicht traust, kann das Makro das auch erzwingen:
1
#define SET_MUX(x) do { PORTX=(PORTX & ~0x07)|((x) & 0x07); } while (0)

von Stephan R. (Gast)


Lesenswert?

Das ist grad mal harter Tobak für mich! Ich hatte mich (gerade aus dem 
Bascom-Lager kommend) schön an die

PORTC |= (1 << PC2)

Schreibweise gewöhnt.

Ich verstehe die Funktion der (x)- Klammer nicht. Steht die nur zur 
Anschauung da oder kann ich die ins Programm übernehmen?

von Εrnst B. (ernst)


Lesenswert?

Stephan R. schrieb:
> Ich verstehe die Funktion der (x)- Klammer nicht. Steht die nur zur
> Anschauung da oder kann ich die ins Programm übernehmen?

Das ist ein Parameter.
Wenn du im Programm später
1
SET_MUX(42);
 schreibst, sieht der Compiler:
1
do { PORTX=(PORTX & ~0x07)|((42) & 0x07); } while (0);
und macht Das Richtige™

von Stephan R. (Gast)


Lesenswert?

Okay, das leuchtet ein, ist halt ne "normale" Funktion. Braucht die denn 
auch einen Prototypen?

Noch was: mein Compiler (Programmers Notepad) formatiert das Makro nicht 
farbig wie in deinem Beispiel sondern nur braun. Warum des?

von Stephan R. (Gast)


Lesenswert?

Anscheinend nicht, zumindest klappts auch so!
Schönen Dank, darfst Dir ein Bier nehmen!

von Jockel (Gast)


Lesenswert?

Stephan R. schrieb:
> Okay, das leuchtet ein, ist halt ne "normale" Funktion. Braucht die denn
> auch einen Prototypen?

Das ist ein Irrtum. Es sieht nur so aus.
Lies nochmal, was Ernst B* oben schrieb (Textersatz).

Jockel

von Karl H. (kbuchegg)


Lesenswert?

Stephan R. schrieb:
> Okay, das leuchtet ein, ist halt ne "normale" Funktion. Braucht die denn
> auch einen Prototypen?

Du brauchst ganz, ganz, ganz dringend ein C-Buch.

Das anlassbedingte Zusammentragen von Halbwissen in einem Forum 
funktioniert einfach nicht, wenn man eine Programmiersprache wie C 
lernen will.

von Verwirrter (Gast)


Lesenswert?

Gibt es einen Grund dafür das Ganze in eine "Schleife" zu packen, warum 
reicht nicht nur die Zuweisung ?

von Εrnst B. (ernst)


Lesenswert?

Verwirrter schrieb:
> Gibt es einen Grund dafür das Ganze in eine "Schleife" zu packen, warum
> reicht nicht nur die Zuweisung ?

in dem Fall würde es ohne das "while"-Konstrukt auch gehen.

bei "#define ABC(x) a=(x); b=(x)+2" z.B
gäbe es aber ein Problem bei Verwendungen wie:

if (a==23) ABC(42);

(Textersetzung mal von Hand durchführen, wenn das Problem nicht 
offensichtlich ist)

durch das "do-while"-Konstrukt wird das umgangen.


Preprozessor-Makros sind da immer etwas eigen. Anfängern würde ich 
vorschlagen davon ganz die Finger zu lassen, und normale C-Funktionen zu 
verwenden. Wenn man die "Verstanden" hat, kann man sich immer noch 
Makros zur "Optimierung" erlernen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Stephan R. schrieb:
> Noch was: mein Compiler (Programmers Notepad) formatiert das Makro nicht
> farbig wie in deinem Beispiel sondern nur braun. Warum des?
Das nennt sich Syntax-Highlighting und die Farben sind in jedem Editor 
entweder anders oder einstellbar...

von Stephan R. (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Das anlassbedingte Zusammentragen von Halbwissen

Oder auch learning by doing find ich eigentlich ganz praktisch. Was ich 
nicht brauch, verlern ich gern schnell wieder.


Karl heinz Buchegger schrieb:
> Du brauchst ganz, ganz, ganz dringend ein C-Buch.

Da hinten in der Schublade liegt´s! DUCK UND WEG

von (Ex-)Verwirrter (Gast)


Lesenswert?

Danke mit so etwas hatte ich gerechnet,
bei manchen Compilern kann man das auch einfach in geschweifte Klammern
{ .... } packen. Solche kleineren Blöcke stören dann nicht weiter. 
Zumindest solange man keine, dadurch lokalen, Variablen anlegt.

von Εrnst B. (ernst)


Lesenswert?

(Ex-)Verwirrter schrieb:
> Danke mit so etwas hatte ich gerechnet,
> bei manchen Compilern kann man das auch einfach in geschweifte Klammern
> { .... } packen. Solche kleineren Blöcke stören dann nicht weiter.
> Zumindest solange man keine, dadurch lokalen, Variablen anlegt.

Nicht immer: ;)
1
#define TEST(X) do { printf("%d\n",(X)); } while(0)
2
3
 if (x)
4
    TEST(x);
5
  else
6
    TEST(x+x);

funktioniert,
1
#define TEST(X)  { printf("%d\n",(X)); }
2
3
 if (x)
4
    TEST(x);
5
  else
6
    TEST(x+x);

Gibt nen Compiler-Fehler:
> »else« ohne vorheriges »if«

von Karl H. (kbuchegg)


Lesenswert?

Stephan R. schrieb:
> Karl heinz Buchegger schrieb:
>> Das anlassbedingte Zusammentragen von Halbwissen
>
> Oder auch learning by doing find ich eigentlich ganz praktisch. Was ich
> nicht brauch, verlern ich gern schnell wieder.

Dazu musst du es aber erst einmal gelernt haben.
Und gerade in C gibt es Unmengen an Fallen und 'Insider-Wissen', ohne 
das man nicht weit kommt.

Und mit Verlaub: So toll ist deine C-Performance nicht. Sie zeigt 
eigentlich genau das Übliche, was man von einem Foren-Zusammenklauber 
erwarten würde: Er kann von allem ein bischen was, aber nichts richtig 
und manchmal einfach nur grundfalsch. Und da red ich noch nicht einmal 
von den wirklich komplizierten Dingen.

von eProfi (Gast)


Lesenswert?

Also in meinem Buch steht, man solle es mit runden Klammern versuchen.

#define QUADRAT(x) ((x)*(x))

von Stephan R. (Gast)


Lesenswert?

Das stimmt natürlich- wenn man denn den Anspruch hat, C professionell zu 
beherrschen.
Das Gute für mich daran: ich brauch mir nicht meine Brötchen damit 
verdienen sondern will nur ein kleines Uböötchen damit auslaufen lassen.
Aber in der Aussicht, vielleicht mal in die Programmiererriege "meiner" 
Firma aufzurutschen, beleg ich nu ein, zwei Semsester lang 
"Programmieren". Vielleicht kann ich ja noch was lernen...

von schau genau (Gast)


Lesenswert?

Ernst:
> Wenn du im Programm später

>   SET_MUX(42);

> schreibst, sieht der Compiler:

>   do { PORTX=(PORTX & ~0x07)|((42) & 0x07); } while (0);

> und macht Das Richtige™


Nö, stimmt nicht ganz. er sieht um die 42 keine Klammern, die müsstest 
(und sollst) Du im Define angeben.


Probier mal aus:
#define QUAD1(x) (x*x)
#define QUAD2(x) ((x)*(x))

das ist zwar auf den ersten Blick das selbe, aber beim Aufruf von z.B.
  QUAD(6 & 6);
kommt für QUAD1 4 heraus und für QUAD2 36, denn der Compiler sieht bei
  QUAD1 (6 & 6 * 6 & 6)
eben keine Klammern und rechnet 6 & (6*6) & 6 , weil & eine kleinere 
Hierarchiestufe als * hat.

Typische C-Falle, auf die in jedem guten C-Buch hingewiesen wird.

von Karl H. (kbuchegg)


Lesenswert?

schau genau schrieb:

> Probier mal aus:
> #define QUAD1(x) (x*x)
> #define QUAD2(x) ((x)*(x))
>
> das ist zwar auf den ersten Blick das selbe, aber beim Aufruf von z.B.
>   QUAD(6 & 6);

....

Genauso bei

   QUAD( 6 + 1 );

(da ist es vielleicht offensichtlicher und im Kopf leichter zu verfolgen 
als mit einem binären und)

Beliebt sind auch

   i = 7;
   j = QUAD( i++ )

(welchen Wert hat i nach der Operation und was ist das Ergebnis? Ist die 
Operation überhaupt definiert? Wenn ja: warum? Wenn nein: warum nicht?)

> Typische C-Falle, auf die in jedem guten C-Buch hingewiesen wird.
Ganz genau
Dazu muss man aber erst einmal verinnerlicht haben, dass Makros einfach 
nur Textersetzung machen und nicht mehr. Aber auch das steht im besagten 
Buch. Zusammen mit ein paar Beispielen, die zeigen wie sich das auswirkt 
und was da im Präprozessor wirklich passiert.

von Karl H. (kbuchegg)


Lesenswert?

Stephan R. schrieb:
> Das stimmt natürlich- wenn man denn den Anspruch hat, C professionell zu
> beherrschen.

Eben nicht
Ohne einen gewissen Grundstock kannst du auch als Amateur nicht sinnvoll 
programmieren.

Von dem was dir jetzt kompliziert vorkommt, bis zu dem, was von einem 
Profi selbstverständlich erwartet und verlangt wird, ist noch ein 
weiter, weiter Weg. Da passt noch viel dazwischen.


Egal ob du Amateur oder Profi- Radrennfahrer bist, Gleichgewicht halten 
müssen beide können. Und man kann sich bei einem Sturz nicht darauf 
rausreden, dass man eben kein Profi sei.

von Εrnst B. (ernst)


Lesenswert?

schau genau schrieb:
> Ernst:
>> Wenn du im Programm später
>
>>   SET_MUX(42);
>
>> schreibst, sieht der Compiler:
>
>>   do { PORTX=(PORTX & ~0x07)|((42) & 0x07); } while (0);
>
>> und macht Das Richtige™
>
>
> Nö, stimmt nicht ganz. er sieht um die 42 keine Klammern, die müsstest
> (und sollst) Du im Define angeben.

in dem Satz fehlt das "und hast" ...
mein #define hat die extra-Klammerung um das "x", also selber "genau 
schau"en ;)

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.