Forum: Mikrocontroller und Digitale Elektronik Bitanweisung Wert überschreiben


von Samuel (Gast)


Lesenswert?

Sehe ich folgendes richtig?
1
uint8_t val = 0;
2
3
val |= 1<<0; // Schreibt eine 1 an das 0. Bit, egal ob der Wert 0 oder 1 war
4
val |= 0<<0; // macht nichts
5
val &= ~(1<<0); //Schreibt eine 0 an das 0. Bit, egal ob der Wert 0 oder 1 war

Hintergrund der ganzen Sache, ich würde gerne Leds setzen, ohne aber 
jedesmal abzuabfragen, ob das Bit bereits gesetzt oder nicht ist.

Hier der Pseudo Code. Gäbe es auch eine "schönere" Variante von
val &= ~(1<< 0);
val |= status << 0;
bzw. kürzere?
1
uint8_t val = 0;
2
uint8_t status = 1;
3
4
val &= ~(1<< 0); // 0. Bit löschen
5
// 0. Bit ist 0. wurde geloescht
6
val |= status << 0; // 0. Bit setzen
7
// 0. Bit ist 1. wurde gesetzt
8
9
10
status = 0;
11
val &= ~(1<< 0); // 0. Bit löschen
12
// 0. Bit ist 0. wurde geloescht
13
val |= status << 0; // 0. Bit setzen
14
// 0. Bit ist 1. wurde NICHT gesetzt

von Klaus W. (mfgkw)


Lesenswert?

Samuel schrieb:
> Gäbe es auch eine "schönere" Variante von...

Schönheit liegt wie immer im Auge des Betrachters.
Hier im Forum sieht man in aller Regel die Bitfummelei, wie sie dir 
nicht gefällt - mir auch nicht.

Man kann sich aber mit Bitfeldern ganz gut behelfen, wenn ich dein 
Anliegen richtig verstehe.

Beispiel:
1
typedef union
2
{
3
  struct
4
  {
5
    unsigned bit0:1;
6
    unsigned bit1:1;
7
    unsigned bit2:1;
8
    unsigned bit3:1;
9
    unsigned bit4:1;
10
    unsigned bit5:1;
11
    unsigned bit6:1;
12
    unsigned bit7:1;
13
  };
14
  uint8_t  byte;
15
} eightbits_t;
16
...
17
  eightbits_t   val =
18
    {
19
      {
20
        .bit0 = 0,
21
        .bit1 = 1,
22
        .bit2 = 0,
23
        .bit3 = 1,
24
        .bit4 = 0,
25
        .bit5 = 0,
26
        .bit6 = 1,
27
        .bit7 = 0
28
      }
29
    };
30
31
  val.byte = 0;  // alle Bits auf 0
32
  val.bit0 = 0;  // unterstes Bit auf 0
33
  val.bit0 = 1;  // unterstes Bit auf 1
34
...

Wenn man die Variable nicht bitweise, sondern komplett initialisieren 
will, geht das natürlich auch:
1
...
2
  eightbits_t   val = { .byte = 0 };
3
...

Die Frage, ob das jetzt allerdings schöner ist, kann beliebig langes 
Gezeter verursachen.

Auf eine ähnliche Weise mappe ich mir auch Bits oder Bitgruppen in 
Registern auf Bitfelder, wenn mir die übliche Schreibweise mit der 
Bitschieberei auf die Nerven geht.
Dazu kann man mißbrauchen, daß die Register in den Adreßbereich 
eingeblendet sind wie Speicher, und die Registernamen eh nur Makros 
sind, die dann über die Adresse mit etwas Casten aussehen wie Variablen.
Beispiel: in den Headerdateien, die für einen atmega8 verwendet werden, 
steht letztlich etwas wie:
1
...
2
#define PORTB    (*(volatile uint8_t *)((0x17) + 0x20))
3
...
, wenn PORTB an der Stelle 0x37 in den Speicher eingeblendet ist.
Das kann man mißbrauchen, um mit &PORTB wieder an die 0x37 zu kommen und 
sich dort stattdessen ein Bitfeld vorzustellen:
1
...
2
// in einer Headerdatei von mir:
3
#ifdef DDRB
4
#define ddrb  (*(volatile eightbits_t*)(&DDRB))
5
#define portb (*(volatile eightbits_t*)(&PORTB))
6
#define pinb  (*(volatile eightbits_t*)(&PINB))
7
#endif /* ifdef DDRB */
8
...
9
// in einer C++ von mir:
10
ddrb.bit0  = 0;  // Datenrichtung für LED setzen
11
portb.bit0 = 0;  // LED aus
12
portb.bit0 = 1;  // LED ein
13
...
14
// oder etwas sprechender:
15
#define DDR_IN    (0)
16
#define DDR_OUT   (1)
17
...
18
#define MEINELED_PORT portb.bo
19
#define MEINELED_DDR  ddrb.bo
20
21
...
22
  MEINELED_DDR  = DDR_OUT;  // Datenrichtung für LED setzen
23
  MEINELED_PORT = 0;        // LED aus
24
  MEINELED_PORT = 1;        // LED ein
25
...

Für spezielle Register mache ich mir dann Bitfelder, die nicht unbedingt 
einzelne Bits abbilden, sondern zusammengehörende Gruppen, die auf 
einmal gesetzt werden können.

Beispiel: Wenn ein Register ADMUX laut Datenblatt aus einem 5 Bit langen 
Bereich mux für die Kanalnummer besteht, einem Bit adlar und einem zwei 
Bit langen refs, dann kann man sowas schreiben:
1
...
2
typedef union
3
{
4
  uint8_t     byte;
5
  struct
6
  {
7
    unsigned int mux:5;
8
    unsigned int adlar:1;
9
    unsigned int refs:2;
10
  };
11
} admux_byte8bits_t;
12
13
#define admux   (*(volatile admux_byte8bits_t*)&ADMUX)
14
...
15
  admux.mux = iKanal; // Kanalnummer setzen (5 Bits)
16
...

Damit will ich jetzt keine Stildiskussion anfachen, sondern zeigen wie 
es technisch gehen kann - wenn man es so will.

von Klaus (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Auf eine ähnliche Weise mappe ich mir auch Bits oder Bitgruppen in
> Registern auf Bitfelder, wenn mir die übliche Schreibweise mit der
> Bitschieberei auf die Nerven geht.

Für die (alle) PICs haben die Microchip Leute das schon mal gemacht und 
in die entsprechenden Header Files geschrieben. Die "Bitschieberei" 
kommt bei mir im Code nicht vor. Da wird ein Interrupt-Flag einfach = 0 
gesetzt und ein Portbit = 1. Da ich das vom Keil 8051 Compiler so 
gewöhnt war, passte das nahtlos für die PiCs.

MfG Klaus

von Stefan F. (Gast)


Lesenswert?

Ich benutze gerne diese Makros:
1
#define writeBit(port,bit,value)   { if ((value)>0) (port) |= (1<<bit); else (port) &= ~(1<<bit); }
2
3
#define readBit(port,bit)          (((port) >> (bit)) & 1)

Anwendung:
1
// LED einschalten
2
writeBit(DDRB,3,1);
3
writeBit(PORTB,3,1);

Wenn bit und value eine konstant ist, kostet das keinen einzigen 
Taktzyklus overhead.

In der Praxis abstrahiere ich I/O Zugriffe häufig noch eine Stufe 
weiter, damit ich sprechende Schlüsselwörter im Quelltext habe und die 
Pin-Zuordnung an einer zentralen Stelle vornehmen kann:
1
#define LED_AN  { writeBit(DDRB,3,1); writeBit(PORTB,3,1); }
2
#define LED_AUS writeBit(PORTB,3,0);

von Peter D. (peda)


Lesenswert?

Klaus Wachtler schrieb:
> Hier im Forum sieht man in aller Regel die Bitfummelei, wie sie dir
> nicht gefällt - mir auch nicht.

Mir auch nicht.
Für IO-Ports habe ich mir daher die sbit.h geschrieben:

Beitrag "Re: LED1 OK. aber LED2 blinkt nicht mit voller Helligkeit"

von Klaus (Gast)


Lesenswert?

Stefan Us schrieb:
> Ich benutze gerne diese Makros:#define writeBit(port,bit,value)   { if
> ((value)>0) (port) |= (1<<bit); else (port) &= ~(1<<bit); }
>
> #define readBit(port,bit)          (((port) >> (bit)) & 1)

Was ein aber nicht hindert, nicht vorhandene Bits auf den falschen 
Adressen zu beschreiben. Wenn man konsequent alle SFRs und Ports als 
Bitfelder (am besten mit den Namen aus dem Datenblatt) beschreibt, kann 
der Compiler schon mal die blödesten Fehler abfangen.

MfG Klaus

von Ralf G. (ralg)


Lesenswert?

Samuel schrieb:
> Hintergrund der ganzen Sache, ich würde gerne Leds setzen, ohne aber
> jedesmal abzuabfragen, ob das Bit bereits gesetzt oder nicht ist.
Ähm..., ich würde sagen: dann frag' doch einfach nicht und setz' das 
Bit!
(Hier sind ja schon einige Antworten, aber ich verstehe den Satz vom 
TO nicht.)
>
> Hier der Pseudo Code. Gäbe es auch eine "schönere" Variante von
> val &= ~(1<< 0);
> val |= status << 0;
> bzw. kürzere?

Siehe oben:
1
//val &= ~(1<< 0);
2
val |= status << 0;

(??) ^^

von Karl H. (kbuchegg)


Lesenswert?

Ralf G. schrieb:
> Samuel schrieb:
>> Hintergrund der ganzen Sache, ich würde gerne Leds setzen, ohne aber
>> jedesmal abzuabfragen, ob das Bit bereits gesetzt oder nicht ist.
> Ähm..., ich würde sagen: dann frag' doch einfach nicht und setz' das
> Bit!
> (Hier sind ja schon einige Antworten, aber ich verstehe den Satz vom
> TO nicht.)


Ich denke, mit 'setzen' war nicht direkt das 'auf 1 setzen' gemeint, 
sondern einfach nur 'auf einen neuen Wert, egal ob 1 oder 0'

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.