C -> Port Bitset

Gast #6059577
Lesenswert?

SETBIT(LED,GREEN) hiesse es bei mir, Makro dazu:
1
#define SETBIT(REG, PIN) ((REG) |= (uint32_t) 1 << (PIN))
2
#define CLEARBIT(REG, PIN) ((REG) &= ~((uint32_t) 1 << (PIN)))
3
#define CHANGEBIT(REG, PIN, WERT) ((WERT) ? SETBIT((REG), (PIN)) : CLEARBIT((REG), (PIN)))
4
#define READBIT(REG, PIN) (((REG) >> (PIN)) & 1)
LED ist dann dein Ausgangpin und GREEN die Nummer (alles in den defines 
zu erledigen)
#6059618
Lesenswert?

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.
Gast #6059712
Lesenswert?

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
struct sLedPort
3
{
4
unsigned char Green : 1;
5
unsigned char       : 2;
6
unsigned char Blue  : 1;
7
unsigned char       : 3;
8
unsigned char Yellow: 1;
9
}
10

11
/* Zuordnung an eine Adresse ist Compiler-spezifisch, hier mit @ */
12
struct sLedPort Leds @0x80;
13
/* Vielleicht noch das Datenrichtungsregister ...  */
14
struct sLedPort LedsDDR @0x85;
15

16
   /* im Code im Init */
17
   LedsDDR.Green = 1;
18
   LedsDDR.Blue  = 1;
19
   LedsDDR.Yellow= 1;
20
   ...
21
   /* und später */
22
   if(started) {Leds.Green=1;}
23
   else        {Leds.Green=0;}
24
   /* oder gar mit success = 0 oder 1 */
25
   Leds.Blue=success;
Gast #6059740
Lesenswert?

Keep it simple!

In einer Header Datei:
1
// Green LED = PB2 high active
2
#define LED_GREEN_ON  { DDRB |= (1<<PB2)); PORTB |= (1<<PB2)); }
3
#define LED_GREEN_OFF { PORTB &= ~(1<<PB2)); }
4

5
// Button = PB3 low active
6
#define BUTTON_PRESSED (!(PINB & (1<<PB3)))

In einer *.c oder *.cpp Datei:
1
if (BUTTON_PRESSED)
2
{
3
    LED_GREEN_ON;
4
}
5
else
6
{
7
    LED GREEN OFF;
8
}

Der Compiler reduziert das optimal auf Einzelbit-Befehle (cbi und sbi).
#6060201
Lesenswert?

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.
#6060222
Lesenswert?

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.
#6060252
Lesenswert?

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.
#6060267
Lesenswert?

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 ;-)
Gast #6060301
Lesenswert?

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:
1
extern volatile uint16_t  PORTA __attribute__((__sfr__));
2
typedef struct tagPORTABITS {
3
  uint16_t RA0:1;
4
  uint16_t RA1:1;
5
  uint16_t RA2:1;
6
  uint16_t RA3:1;
7
  uint16_t RA4:1;
8
} PORTABITS;
9
extern volatile PORTABITS PORTAbits __attribute__((__sfr__));
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
#6060609
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren