Forum: Compiler & IDEs #defines in AVR-libc


von Thomas (Gast)


Lesenswert?

Moin,

warum sind eigentlich alle Ports, Pins und Register in der AVR-libc 
folgendermaßen definiert:
1
/* DDRC */
2
#define DDC7    7
3
#define DDC6    6
4
#define DDC5    5
5
#define DDC4    4
6
#define DDC3    3
7
#define DDC2    2
8
#define DDC1    1
9
#define DDC0    0

im Code soll man das dann z.B. so nutzen:
1
DDRC = (1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3) | (1 << DDC4);
Das soll dann laut AVR-GCC-Tutorial "übersichtlich und selbsterklärend" 
sein.
1
DDRC = 0x1F;
hingegen soll "unübersichtlich" sein.
1
DDRC = 0b00011111;
Das es auch so geht wird gar nicht erwähnt.

Würde man es in der AVR-libc direkt so definieren:
1
/* DDRC */
2
#define DDC7    128
3
#define DDC6    64
4
#define DDC5    32
5
#define DDC4    16
6
#define DDC3    8
7
#define DDC2    4
8
#define DDC1    2
9
#define DDC0    1
dann könnte man es noch viel übersichtlicher und mit relativ wenig 
Tipparbeit so schreiben:
1
DDRC = DDC0 | DDC1 | DDC2 | DDC3 | DDC4;

Ich frage mich, warum das trotzdem so umständlich gemacht wird. Ist es 
ohne die Shiftoperatoren nicht elitär genug, oder gibt es dafür einen 
richtigen Grund?

Gruß,
Thomas

von Karl H. (kbuchegg)


Lesenswert?

Thomas schrieb:

> Ist es
> ohne die Shiftoperatoren nicht elitär genug, oder gibt es dafür einen
> richtigen Grund?

Manchmal benötigt man tatsächlich die Pinnummer ( also 0, 1, 2, 3 ... 7 
) und nicht die Bit-Maske die daraus ensteht.

Hab ich die defines
1
#define DDC7    7
2
#define DDC6    6
3
#define DDC5    5
4
#define DDC4    4
5
#define DDC3    3
6
#define DDC2    2
7
#define DDC1    1
8
#define DDC0    0

dann hab ich automatisch die Pinnummern. Die zugehörigen Bit-Masken kann 
ich mir ohne grossen Aufwand selbst definieren
1
#define DDC7_MASK    ( 1 << DDC7 )
2
#define DDC6_MASK    ( 1 << DDC6 )
3
#define DDC5_MASK    ( 1 << DDC5 )
4
...

und kann die dann leicht benutzen
1
  DDRC = DDC0_MASK | DDC1_MASK | DDC2_MASK | DDC3_MASK | DDC4_MASK;


aber der umgekehrte Weg ist ungleich schwieriger.
Hab ich nur die Bit-Masken, dann gibt es keinen einfachen Weg um daraus 
die Pinnummern zu generieren.

Die eigentliche Frage lautet daher: Welches ist die sinnvoll einfachste 
Möglichkeit das gewünschte auszudrücken, so dass Alles weitergehende 
daraus auf simple Art und Weise erzeugt werden kann?
Und das sind nun mal die Pin-Nummern

von Stefan E. (sternst)


Lesenswert?

Es gibt auch Fälle, wo man die Bit-Nummer braucht, z.B. bei diversen 
Assemblerbefehlen.

Grundsätzlich ist die Bit-Nummer universeller, weil man sehr einfach von 
der Nummer zur Maske kommt (eben mit dem Shift). Bei der von dir 
vorgeschlagenen Bit-Maske kommt man aber nicht auf ebenso einfachem Weg 
an die Nummer, wenn man die mal braucht.

von Norgan (Gast)


Lesenswert?

> Ich frage mich, warum das trotzdem so umständlich gemacht wird. Ist es
> ohne die Shiftoperatoren nicht elitär genug, oder gibt es dafür einen
> richtigen Grund?

Die Original-Dateien von Atmel haben nun mal die Register-Bits so 
definiert.

Und sind wir mal ehrlich, ein Programmierer der an eine 
Shift-Operationen scheitert sollte vielleicht ans Umsatteln auf BWL 
denken.

von Sven P. (Gast)


Lesenswert?

Liegt am Instruktionssatz des AVR.
Folgende Instruktionen beispielsweise brauchen nicht eine Maske, sondern 
eine Bitnummer:
- sbis und sbic, sbrs und sbrc
- sbi und cbi
- bst und bld
- brbs und brbc
- bset und bclr

von Thomas (Gast)


Lesenswert?

@Karl heinz & Stefan:
Danke für die Erläuterung.

@Norgan
Kein Grund arrogant zu werden.

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


Lesenswert?

Sven P. schrieb:
> Liegt am Instruktionssatz des AVR.

Naja.  Dafür, dass der AVR mit Zielrichtung C konzipiert worden ist,
hätte man auch wirklich die Bitmaske in die Headerdatei schreiben
können.  Ein Assembler sollte mühelos in der Lage sein, aus

SBI PORTA, 0x40

auszurechnen, welches Bit er nun setzen soll und ggf. einen Fehler
zu spucken, falls in der Zahl rechts nicht genau ein Bit gesetzt
sein sollte.

Dafür dürfen wir uns nun den Rest des AVR-Lebens in C mit all
diesen Schiebeoperatoren herumärgern.  Egal ob nun direkt hin
geschrieben oder hinter _BV() versteckt, sie machen den geschriebenen
C-Code reichlich unübersichtlich.

von Sven P. (Gast)


Lesenswert?

Tjo, is wohl wahr.

von hans (Gast)


Lesenswert?

Mit #define geht es auch noch anderst:
1
#define MASK(a)    ( 1 << a)
2
3
#define DDC2    2
4
#define DDC1    1
5
#define DDC0    0
6
7
df=MASK(DDC2)|MASK(DDC0);     // neue Schreibweise
8
9
df=(1<<DDC2)|(1<<DDC0);      // alte Schreibweise



Ob diese Ersetzung schöner ist muß man selber überlegen.

Man braucht es ja nicht MASK zu nennen.

gruß hans

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


Lesenswert?

hans schrieb:

> Man braucht es ja nicht MASK zu nennen.

Man könnte es, ja, ähem, zum Bleistift _BV() nennen. :-)

von hans (Gast)


Lesenswert?

Ich dachte eher an "setzen"

gruß hans

von Thomas (Gast)


Lesenswert?

Ich würde es einfach so nennen:
1
#define BIT7    128
2
#define BIT6    64
3
#define BIT5    32
4
#define BIT4    16
5
#define BIT3    8
6
#define BIT2    4
7
#define BIT1    2
8
#define BIT0    1

Bringt doch Null Mehrwert, wenn da auch noch der Name des Registers mit 
verwurschtelt ist. Der steht ja eh vor dem =.

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


Lesenswert?

Thomas schrieb:

> Bringt doch Null Mehrwert, wenn da auch noch der Name des Registers mit
> verwurschtelt ist. Der steht ja eh vor dem =.

Nur bei PORTx/DDRx/PINx.  Dort benutze ich in aller Regel wirklich
nur die Zahlen.

Interessant wird das ja erst bei den diversen IO-Steuerregistern mit
ihren Bitnamen.

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.