Forum: Mikrocontroller und Digitale Elektronik AVR - unteres und oberes Nibble von Port getrennt beschreiben


von Terry (Gast)


Lesenswert?

Hallo,

ich möchte bei einem AVR-Port das untere und das oberes Nibble 
unabhängig voneinander beschreiben.

Sagen wir mal, im Portregister stünde
a = 0b11101010;
PORTA = a;

Jetzt soll das untere Nibble verändert werden von 1010 zu 1110. Das 
obere Nibble soll aber erst mal erhalten bleiben.

Wie setzt man das am besten in der Praxis um?

von ffff (Gast)


Lesenswert?

verunden? PORTA &= PORTA & 11111110

von Stefan P. (form)


Lesenswert?

Terry schrieb:
> Wie setzt man das am besten in der Praxis um?

PORTA = PORTA & 0b11110000 | 0b00001110;

von Terry (Gast)


Lesenswert?

Danke für die schnellen Antworten!

Also in zwei Schritten:

PORTA = PORTA & 0b11110000; //unteres Nibble löschen

PORTA = PORTA | 0b00001110; //unteres Nibble neu beschreiben

Richtig?

von Ralf G. (ralg)


Lesenswert?


von Max H. (hartl192)


Lesenswert?

Oder so:
1
struct nibbles
2
{
3
  uint8_t low_nibble:4, high_nibble:4;
4
} __attribute__((__packed__));
5
6
#define HIGH_NIBBLE(byte) ((*(volatile struct nibbles*)&byte).high_nibble)
7
#define LOW_NIBBLE(byte) ((*(volatile struct nibbles*)&byte).low_nibble)
8
9
10
// Usage
11
HIGH_NIBBLE(PORTB) = 5;
12
LOW_NIBBLE(PORTB) = 0x08;

: Bearbeitet durch User
von Rainer V. (rudi994)


Lesenswert?

Terry schrieb:
> Also in zwei Schritten:
> PORTA = PORTA & 0b11110000; //unteres Nibble löschen
> PORTA = PORTA | 0b00001110; //unteres Nibble neu beschreiben

Funktioniert zwar, zu beachten ist aber, daß im unteren Nibble evtl. 
auch Bits gesetzt sein könnten, die gesetzt bleiben sollen. Im o.g. Code 
tritt bei solchen Bits durch das kurzzeitige Löschen ein Flackern des 
Signals an den Portpins auf. Das ist egal, wenn nur LEDs angeschlossen 
sind, da man das Flackern bei hoher µC-Taktrate nicht sehen kann. Wenn 
aber kritische Geräte angeschlossen sind, dann ist es nicht egal, ob das 
Signal flackert oder konstant ist. Dann besser so:

1. Port in Variable (Register) einlesen.
2. Bits in der Variablen manipulieren.
3. Variablenwert in den Port schreiben.

von c-hater (Gast)


Lesenswert?

Rainer V. schrieb:

> 1. Port in Variable (Register) einlesen.
> 2. Bits in der Variablen manipulieren.
> 3. Variablenwert in den Port schreiben.

Richtig. Und wenn man sich nicht sicher ist, ob irgendeine verschissene 
ISR Ausgaben auf den gleichen Port tätigt, gehört natürlich ein 
cli/sei-Rahmen um die Sache.

Bei richtigen Programmierern ist das natürlich kein Thema, die wissen, 
ob da eine ISR reingrätschen könnte, aber bei C&P-"Programmierern"...

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> Richtig. Und wenn man sich nicht sicher ist, ob irgendeine verschissene
> ISR Ausgaben auf den gleichen Port tätigt, gehört natürlich ein
> cli/sei-Rahmen um die Sache.

Oder man nimmt auf nicht zu alten AVRs
PINA = (PORTA & 0x0F) ^ 0b1110;
Schützt gegenüber Veränderungen an den oberen Bits.
Die Übersetzung in Asm überlasse ich dir. ;-)

: Bearbeitet durch User
von Kurt (Gast)


Lesenswert?

"0b" eröffnet eine als Byte zu interpretierende Folge von
8 Bits (MSB first).

Wer "0b1110" schreibt, ist für mich DOOF.

von Bastler (Gast)


Lesenswert?

Und wer meint eine "binary constant" habe exakt 8 Bit zu haben, der kann 
(zumindest Englische Doku des GCC) nicht lesen.
Das ist irgendwie auch doof ;-)
Es dürfen nämlich 1..64 (eventuell auch mehr) sein.

von (prx) A. K. (prx)


Lesenswert?

Kurt schrieb:
> "0b" eröffnet eine als Byte zu interpretierende Folge von
> 8 Bits (MSB first).

Das "b" kommt von Bit, nicht von Byte. Der Typ entwickelt sich grad wie 
bei 0 oder 0x vorneweg, ist also "int".

https://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html

> Wer "0b1110" schreibt, ist für mich DOOF.

0b1110 ist 0x000E, nicht 0xD00F.

: Bearbeitet durch User
von zappa (Gast)


Lesenswert?

Ein Nibble auf'm 8-Bit AVR Port kann nicht getrennt vom anderen Nibble 
als Einheit beschrieben werden. Bitweise per ASM könnte man noch das 
andere Nibble unangetastet lassen.

von (prx) A. K. (prx)


Lesenswert?

zappa schrieb:
> Ein Nibble auf'm 8-Bit AVR Port kann nicht getrennt vom anderen Nibble
> als Einheit beschrieben werden.

Elektrisch gesehen nicht, funktional schon. Jene AVRs, die beim 
Schreiben auf PINx eine Toggle-Funktion ausführen, können einen 
beliebigen Subset von Portbits geschlossen auf beliebige Werte setzen, 
ohne die übrigen Pins zu beeinflussen oder von ihnen beeinflusst zu 
werden.

Voraussetzung ist nur die Hoheit über die betroffenen Pins, d.h. 
zwischen lesen von PORTx und schreiben von PINx dürfen sich die zu 
modifierenden Pins nicht ändern. Die anderen hingegen schon.

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

A. K. schrieb:
>> Wer "0b1110" schreibt, ist für mich DOOF.
>
> 0b1110 ist 0x000E, nicht 0xD00F.

Der frühe Vogel fängt den Wurm ;-)

von Rolf (Gast)


Lesenswert?

A. K. schrieb:
> Oder man nimmt auf nicht zu alten AVRs
> PINA = (PORTA & 0x0F) ^ 0b1110;

Schaltet PINA nicht lediglich die Pullups auf Port A???

von zappa (Gast)


Lesenswert?

Rolf schrieb:
> Schaltet PINA nicht lediglich die Pullups auf Port A???

Nur wenn die Portpins als Eingang konfiguriert sind. Sonst toggelt eine 
"1" im PIN Register den Ausgang (bei neueren AVR zB ATtiny25, ATMega88 
... und fast alle anderen)

von zappa (Gast)


Lesenswert?

zappa schrieb:
> Rolf schrieb:
>> Schaltet PINA nicht lediglich die Pullups auf Port A???
>
> Nur wenn die Portpins als Eingang konfiguriert sind. Sonst toggelt eine
> "1" im PIN Register den Ausgang (bei neueren AVR zB ATtiny25, ATMega88
> ... und fast alle anderen)

Mist, reingefallen. Bei Eingang werden die Pullups mit dem Portregister 
geschaltet! Im PIN werden die Zustaände abgefragt.

von Rolf (Gast)


Lesenswert?

Rolf schrieb:
>> PINA = (PORTA & 0x0F) ^ 0b1110000;


Müsste es dann nicht eher heißen:

PORTA = (PINA & 0x0F) ^ 0b1110000;

von Karl H. (kbuchegg)


Lesenswert?

Rolf schrieb:
> Rolf schrieb:
>>> PINA = (PORTA & 0x0F) ^ 0b1110000;
>
>
> Müsste es dann nicht eher heißen:
>
> PORTA = (PINA & 0x0F) ^ 0b1110000;

Welchen Zweck hat hier das XOR?
Die oberen 4 Bits des Bytes vom PINA sind auf jeden Fall 0. Die 
Verundung mit 0x0F erzwingt dies. Von diesen 4 Bits mittels einem XOR 3 
Bits auf 1 zu setzen kann man natürlich machen. Allerdings war die 
Vorgabe, dass diese Bits unangetastet bleiben sollen, wenn man auf den 
Port ausgibt.

von (prx) A. K. (prx)


Lesenswert?

Rolf schrieb:
> Müsste es dann nicht eher heißen:
> PORTA = (PINA & 0x0F) ^ 0b1110000;

Nein. Es geht in
  PINA = (PORTA & 0x0F) ^ 0b1110;
um die implizite XOR-Funktion beim Schreiben auf PINA. Gibts noch nicht 
im Mega8, aber im Mega88. Schreiben auf PINA wie in
  PINA = <expr>;
entspricht bei diesen Devices
  PORTA ^= <expr>;
wobei das aber im Port durchgeführt wird und nicht unterbrechbar ist. In
 (PORTA & 0x0F) ^ 0b1110
sind nur jene Bits gesetzt, die geändert werden müssen um in den unteren
4 Bits auf den Zustand 0b1110 zu kommen.

: Bearbeitet durch User
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.