AVR - unteres und oberes Nibble von Port getrennt beschreiben

Gast #4138361
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?
#4138412
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;
#4138525
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.
Gast #4138692
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"...
Gast #4139115
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.
#4139153
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.
Gast #4141388
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.
#4141962
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.
#4141983
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.

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