Peter K. schrieb:> Okay. Aber da sehe ich nichts vom Port Zugriff?
Es gibt unzählige Versuche, das mit bit-fields zu lösen - auch hier im
Forum.
Die sind alle falsch bis zweifelhaft, weil sie ausnahmslos mindestens
implementation-defined behaviour dabei haben, manche im Kontext von C++
mit union as type-punning UB.
Also: entweder richtig machen (Klasse in C++) oder sein lassen.
Wilhelm M. schrieb:> Ist aber implementation-defined.
Ja. Aber ein Portzugriff ist nicht nur an den Compiler, sondern auch an
die HW genagelt, also relativ überschaubar das Problem.
Wenn der Port ganz normal memory-mapped ist und bitweise adressierbar
ist, dann geht das meistens relativ straight:
1
/* reihenfolge Compiler(setting) und HW-spezifisch */
2
structsLedPort
3
{
4
unsignedcharGreen:1;
5
unsignedchar:2;
6
unsignedcharBlue:1;
7
unsignedchar:3;
8
unsignedcharYellow:1;
9
}
10
11
/* Zuordnung an eine Adresse ist Compiler-spezifisch, hier mit @ */
12
structsLedPortLeds@0x80;
13
/* Vielleicht noch das Datenrichtungsregister ... */
> #define LED_GREEN_OFF { PORTB &= ~(1<<PB2)); }
Immer ein "do-while(0)" um die geschweiften Klammer! Dann geht dein
Beispiel auch ohne die geschweiften Klammern beim "if".
foobar schrieb:> Immer ein "do-while(0)" um die geschweiften Klammer! Dann geht dein> Beispiel auch ohne die geschweiften Klammern beim "if".
bei gcc nicht nötig, da impliziert durch die {} klammer und sowieso
schon alles ugly.
mt
MaWin schrieb:> #define LED_GREEN_ON { DDRB |= BIT_2; PORTB |= BIT_2; }
Was ist denn das für ein Blödsinn: jedesmal, wenn man die LED
einschalten will auch das DDR zu setzen.
Stefan F. schrieb:> // Green LED = PB2 high active> #define LED_GREEN_ON { DDRB |= (1<<PB2)); PORTB |= (1<<PB2)); }> #define LED_GREEN_OFF { PORTB &= ~(1<<PB2)); }
Das ist wirklich sehr unschön: PB2 an drei Stellen redundant zu
verwenden.
Für (1 << X) hatte Atmel/MicroChip schon seit Urzeiten _BV(x)
eingeführt.
A. S. schrieb:> Wenn der Port ganz normal memory-mapped ist und bitweise adressierbar> ist, dann geht das meistens relativ straight:> /* reihenfolge Compiler(setting) und HW-spezifisch */> struct sLedPort> {> unsigned char Green : 1;> unsigned char : 2;> unsigned char Blue : 1;> unsigned char : 3;> unsigned char Yellow: 1;> }
So etwas führt immer zu RMW-Sequenzen im Maschinencode.
Bei µC, die einzelne set/clear oder flag Register haben (also alle etwas
moderneren), ist etwa ein
1
PORTA.DIRSET=_BV(1);
die einzig richtige Möglichkeit.
Das mit den Bit-Fields für µC-Register ist und bleibt ein Hack.
Wilhelm M. schrieb:> So etwas führt immer zu RMW-Sequenzen im Maschinencode.
Das stimmt nicht und wäre auch unlogisch. Wenn der Controller einzelbits
manipulieren kann, tut er es.
Ich sehe nicht, dass irgendeine Makrolösung hier geradlieniger ist.
A. S. schrieb:> Das stimmt nicht und wäre auch unlogisch. Wenn der Controller einzelbits> manipulieren kann, tut er es.
Wenn der µC das kann, und der Compiler diese Optimierung verwendet, ja.
Bei den alten AVR gilt das eben nur für die unteren Register.
Um hier vollkommen neutral zu sein, haben moderne µC (auch die
avr0/tiny1) die set/clear bzw. flag Register. DA funktioniert das dann
bei jedem Register. Bei einem bit-field oberhalb von 0x1f hätten wir
sonst wieder RMW- Sequenzen (mit all ihren sonstigen Nachteilen wie
nicht-Atomarität).
A. S. schrieb:> Ich sehe nicht, dass irgendeine Makrolösung hier geradlieniger ist.
Da sowieso nicht.
Ich sagte ja schon oben: entweder richtig per bit-shift oder eben in
einer Klasse abstrahieren.
Wilhelm M. schrieb:> Ich sagte ja schon oben: entweder richtig per bit-shift> oder eben in einer Klasse abstrahieren.
Oder akzeptieren, dass der ganze Krempel ohnehin hardware- und
compilerspezifisch ist und hässlich sowieso. Es muss nicht vollkommen
neutral sein.
Ob ich nun ein hässliches Makro, ein hässliches Bitfeld-Overlay oder
eine hässliche Templateklasse im Header verstecke, ist (zumindest bei
den üblichen AVR-Anwendungen) relativ egal. Hauptsache, der eigentliche
Code sieht halbwegs sauber und übersichtlich aus.
S. R. schrieb:> Ob ich nun ein hässliches Makro, ein hässliches Bitfeld-Overlay oder> eine hässliche Templateklasse im Header verstecke, ist (zumindest bei> den üblichen AVR-Anwendungen) relativ egal.
Nun, wir sind in C, da geht es halt nicht besser als mit einem
Macro-Hack. Wobei ich immer eine Funktion vorziehen würde (als
header-only Bibliothek mit anderen nettes Sachen).
Wer mit dem IB der bit-fields und den sonstigen Nachteilen leben möchte,
kann das ja gerne machen. In meinen Augen ist das jedenfalls kein Weg.
Natürlich, in C++ hat man dafür sein Klassentemplate und entsprechende
Spezialisierungen für irgendwelche µC-Abnormitäten. Und wenn man das
gescheit macht, finde ich das auch auf der Bibliotheksseite gar nicht
mal so hässlich ;-)
Wilhelm M. schrieb:> MaWin schrieb:>> #define LED_GREEN_ON { DDRB |= BIT_2; PORTB |= BIT_2; }>> Was ist denn das für ein Blödsinn: jedesmal, wenn man die LED> einschalten will auch das DDR zu setzen.
Ist halt so Arduino Style. Wobei da dann noch 29 andere Dinge gemacht
werden. Aber man ist auf dem gleichen Weg.
Cyblord -. schrieb:> foobar schrieb:>>> Wie ist das mit Makros möglich? (diese Schreibweise mit LED._____)>>>> Mit genügend hoher "ugly-hack-Schwelle":>>> #define LED (*(volatile struct { char Red:1,Green:1,Blue:1,rest:5; }>> *)&PORTB)>>> Es gibt einen fest reservierten Platz in der Hölle, für Leute die so was> machen.
Das liefert Microchip in hunderten von Headerfiles für die PICs mit:
Da erinnert einen der Compiler, ist der gcc, auch daran, da0 es Bit 5
auf Port A nicht gibt. Und ich mach mir das mit
#define LED_GREEN PORTAbits.RA0
LED_GREEN = 1;
auch noch den Code lesbarer. In den Himmel komm ich sowieso nicht, dafür
gibts in der Hölle free WLan.
MfG Klaus
Wilhelm M. schrieb:> Nun, wir sind in C, da geht es halt nicht besser als mit einem> Macro-Hack.
Warum schreibst Du das, wo Du doch mein reines C-Beispiel gelesen hast?
Es ist kein Macro nötig und schön sowieso nicht.
A. S. schrieb:> Warum schreibst Du das, wo Du doch mein reines C-Beispiel gelesen hast?
Zitiere mich dann bitte richtig. Das gesamte Statement war:
Wilhelm M. schrieb:> Nun, wir sind in C, da geht es halt nicht besser als mit einem> Macro-Hack. Wobei ich immer eine Funktion vorziehen würde (als> header-only Bibliothek mit anderen nettes Sachen).>> Wer mit dem IB der bit-fields und den sonstigen Nachteilen leben möchte,> kann das ja gerne machen. In meinen Augen ist das jedenfalls kein Weg.
Wilhelm M. schrieb:> Was ist denn das für ein Blödsinn: jedesmal, wenn man die LED> einschalten will auch das DDR zu setzen.
Ist nur ein Vorschlag. Man muss ja nicht alles 1:1 nachmachen.
Cyblord -. schrieb:> Ist halt so Arduino Style.
Ja, geht in die Richtung. Allerdings 30x mal schneller als Arduino.