Hallo.
Ich möchte den Zustand eines Ports in eine Variable speichern und später
den Port auf den gespeicherten Zustand zurück setzen.
Folgende Idee funktioniert nicht;
main()
...
uint8_t Zustand = (PORTA & (1<<PA4)); // akt.Zustand speichen
...
PORTA & (1<<Zustand); // auf gespeicherten Zustand zurück setzen
Jonas B. schrieb:> PORTA geht nur für Ausgaben... Das Inputregister findest du aber mal> selbst raus ;)
Wie beschrieben geht es um die Zustandsabfrage und dessen
Widerherstellung des Ausgang PORTA/PA4
__Son´s B. schrieb:> Wie beschrieben geht es um die Zustandsabfrage und dessen> Widerherstellung des Ausgang PORTA/PA4
Zustand kann alles mögliche eihentlich sein. INPUT/OUPUT, OUTPUT
HIGH/LOW oder auch INPUT HIGH/LOW
aber ja eigentlich macht ja nur das zweite von allem Sinn, velleicht
noch das erste. Gibt aber immer Leute die lausig gestellte Fragen
nutzen, ihren Senfabzugeben und dann trotzdem nichts beitragen...
Oliver S. schrieb:> Denn im Falle eines AVRs sind an die 100% aller Antworten bisher> falsch...
@ __Son´s Bersi__ (bersison)
>Falk B. schrieb:>> tmp = PORTA;>Also des gesamten PORTA auslesen und speichern?
Sicher, das ist das einfachste. Du sparst keinen Speicher, wenn du nur
ein Bit im Byte "nutzt".
Ich zitiere mal aus dem Tutorial:
"Dabei ist wichtig, zur Abfrage der Eingänge nicht etwa Portregister
PORTx zu verwenden, sondern Eingangsregister PINx. Ansonsten liest man
nicht den Zustand der Eingänge, sondern den Status der internen
Pull-Up-Widerstände. Die Abfrage der Pinzustände über PORTx statt PINx
ist ein häufiger Fehler beim AVR-"Erstkontakt"."
In diesem Sinne...
Oliver
Oliver S. schrieb:> Ich zitiere mal aus dem Tutorial:>> "Dabei ist wichtig, zur Abfrage der Eingänge nicht etwa Portregister> PORTx zu verwenden, sondern Eingangsregister PINx. Ansonsten liest man> nicht den Zustand der Eingänge, sondern den Status der internen> Pull-Up-Widerstände. Die Abfrage der Pinzustände über PORTx statt PINx> ist ein häufiger Fehler beim AVR-"Erstkontakt"."
Das ist schon korrekt, aber wie kann PA4 einmal Eingang und einmal
Ausgang sein?
Von daher ist die Aufgabenstellung des TOs nicht ausreichend umrissen.
Was will er zwischenspeichern? Den Zustand eines Ausgangs oder den
Zustand eines Eingangs?
Da ich nicht annehme, dass er den Pin mittendrin von der Richtung her
umprogrammieren will, sondern sich den ehemaligen Zustand des Ausgangs
PA4 merken will, ist die Verwendung von PORTx durchaus richtig. Ist das
Ding nämlich auf Ausgang geschaltet, liest man nicht den Zustand der
Pullups, sondern tatsächlich den aktuellen Wert des Ausgangs.
Von daher ist Dein Zitat aus dem Tutorial hier nicht passend. Das
bezieht sich nämlich auf Eingänge.
Naja, schöner Trick, aber das ist weder notwendig noch anfängertauglich.
Das geht schon STARK in Richtung Obfuscation! Denn dazu muss man wissen,
dass bein AVR ein Schreibzugriff auf PINx die Ausgangsbits toggelt . . .
Falk B. schrieb:> Naja, schöner Trick, aber das ist weder notwendig noch anfängertauglich.
Es ist kein Trick.
> Das geht schon STARK in Richtung Obfuscation!
Das ist Quatsch.
> Denn dazu muss man wissen,> dass bein AVR ein Schreibzugriff auf PINx die Ausgangsbits toggelt . . .
Falls er es vorher noch nicht gewußt hat weiß er es ja jetzt.
Die Variante ist dann von Vorteil, wenn andere Bits auf dem gleichen
Port durch Interrupts beeinflußt werden. Sie kommt ohne Interrupt-Sperre
aus. Und weil gerade Anfänger sowas leicht übersehen, ist gerade diese
Lösung anfängertauglich. ;-)
Stefan U. schrieb:> Hammer, wie kommt man aus solche Ideen? (Den C Code meine ich)
Indem man ins Datenblatt schaut, und sich fragt, was der Hersteller sich
wohl bei sowas gedacht hat.
Leo C. schrieb:> Indem man ins Datenblatt schaut, und sich fragt, was der Hersteller sich> wohl bei sowas gedacht hat.
Nur leider nicht das, was du dir dabei denkst.
@ Mein grosses Vorbild (vorbild)
>> Indem man ins Datenblatt schaut, und sich fragt, was der Hersteller sich>> wohl bei sowas gedacht hat.>Nur leider nicht das, was du dir dabei denkst.
Doch, das passt schon.
> PINC = (PORTC & (1<<4)) ^ tmp;> 78c: 88 b1 in r24, 0x08 ; 8> 78e: 80 71 andi r24, 0x10 ; 16> 790: 8d 25 eor r24, r13> 792: 86 b9 out 0x06, r24 ; 6
Ist korrekt übersetzt.
> PORTC = (PORTC & ~(1<<4) ) | tmp;> 794: 88 b1 in r24, 0x08 ; 8> 796: 8f 7e andi r24, 0xEF ; 239> 798: 8d 29 or r24, r13> 79a: 88 b9 out 0x08, r24 ; 8
Ist auch korrekt übersetzt.
Der Trick von Leo ist der. Er will das Pin in einer atomaren Operation
auf den richtigen Zustand setzen. Das schafft er mit einem
Schreibzugriff auf das Bit 4 im Register PINA. Wird vorher von PORTA
eine 0 gelesen, das gespeicherte Bit in tmp aber auf 1 steht, dann
ergibt das XOR eine 1. Die wird in Bit4 von PINA geschrieben und damit
das Ausgangspin/bit in PORTA in den richtigen Zustand umgeschaltet. Das
gleiche bei 1/0. Bei 0/0 bzw. 1/1 steht das Bit schon richtig und die
XOR Operation ergibt 0, wodurch das Ausgangsbit auch nicht umgeschaltet
wird.
Modernere CPUs ala Xmega und die allermeisten ARMs haben dafür explizite
Register, womit man einzelne oder mehrere IOs atomar setzen, löschen
oder umschalten kann, die heißen dann meist irgendwie _SET, _Clear,
_Toggle. Dort würde man es genau so machen.
>Ist wohl doch nicht so cool.
Doch, aber den Trick muss man erst einmal durchschauen.
@ Leo C. (rapid)
>Ja, das war Mist. Dann halt so:>PINA = (tmp ^ PORTA) & (1<<PA4);
Ohh, der Meister solpert? Nein, das war schon korrekt.
1
uint8_ttmp=PORTA&(1<<PA4);
2
3
...
4
5
PINA=(PORTA&(1<<PA4))^tmp;
Das ist vollkommen OK. Erst Bit4 allein maskieren, dann XOR-verknüpfen.
Das ist vom Ergebnis isdentisch zu dem oben, WENN vorher in TMP alle
anderen Bits maskiert wurden, was in deinem Beispiel der Fall ist.
Allerdings kann man mit der letzten Version eine Verknüpfung einsparen.
So oder so, sehr schön gecodet.
Falk B. schrieb:> Modernere CPUs ala Xmega und die allermeisten ARMs haben dafür explizite> Register, womit man einzelne oder mehrere IOs atomar setzen, löschen> oder umschalten kann,
Nicht nur das, auch gibt auch noch für jedes Bit n eigenes Register -->
Bit-Banding
@ Felix C. (felix_c13)
>So oder so, sehr schön gecodet.
AHHH! Dafür ums schlechter gedenglischt!!!!
>> Modernere CPUs ala Xmega und die allermeisten ARMs haben dafür explizite>> Register, womit man einzelne oder mehrere IOs atomar setzen, löschen>> oder umschalten kann,>Nicht nur das, auch gibt auch noch für jedes Bit n eigenes Register -->>Bit-Banding
Die 32 Bit Dekadenz ;-)
Naja, mit einzelnen Set/Clear/Toggle Register braucht man das eigentlich
nicht mehr, denn man spart dabei kaum Befehle (jaja, Konstante laden
entfällt)
Falk B. schrieb:> AHHH! Dafür ums schlechter gedenglischt!!!!Falk B. schrieb:> Die 32 Bit Dekadenz ;-)
Hahah, in Bestlaune so kurz vor Ostern? :D
Nene aber so war das nicht gemeint. AVR wird einem immer im Herzen
bleiben wenn man damit mal angefangen hat, aber der Trend geht halt in
Richtung Cortex-M.
Wenn zwischen in und out ein IRQ erfolgt und irgendein Bit im Port
verändert wird, wird dieses beim out wieder zurück gesetzt. Also, nicht
atomar.
1
PINC=(PORTC&(1<<4))^tmp;
2
78c:88b1inr24,0x08;8
3
78e:8071andir24,0x10;16
4
790:8d25eorr24,r13
5
792:86b9out0x06,r24;6
6
7
PINC=(tmp^PORTC)&(1<<4);
8
448:88b1inr24,0x08;8
9
44a:8927eorr24,r25
10
44c:8071andir24,0x10;16
11
44e:86b9out0x06,r24;6
Bit 4 wird zwischen in und out nach einem IRQ geändert. War es zuvor 1
und soll gemäß tmp auf 0 gesetzt werden, muß es getoggelt werden. Wird
es aber durch den dazwischen funkenden Interrupt auf 0 gesetzt, dürfte
es jetzt nicht mehr getoggelt werden. Zur Entscheidung wird aber immer
noch der ursprüngliche Wert(1) verwendet. Also, auch nicht atomar.
Vielleicht ein bißchen atomarer als oben, aber ...
@Mein grosses Vorbild (vorbild)
>ursprüngliche Wert verwendet. Also, auch nicht atomar. Vielleicht ein>bißchen atomarer als oben, aber ...
Das ist ja ganz schöne Atom- ähhh, Haarspalterei!
Nein, das atomar bezieht sich auf alle anderen Bits ausser Bit4! Und
diesbezüglich ist der Zugriff echt atomar! Wenn der Interrupt in der
Zwischenzeit Bit4 verändert ist das Gesamtkonzept fragwürdig.
Falk B. schrieb:> Nein, das atomar bezieht sich auf alle anderen Bits ausser Bit4!
Nun komm, sind wir hier im Häkelbüdelclub?
Entweder es ist atomar oder es ist nicht atomar. Dazwischen ist Raum für
gar nichts.
Falk B. schrieb:> Wenn der Interrupt in der> Zwischenzeit Bit4 verändert ist das Gesamtkonzept fragwürdig.
Passiert bei asynchronen Signalen. Sperrt man den Interrupt, setzt sich
der Interrupt durch. Lässt man ihn zwischendurch reinfunken, erhält man
zu 50% einen Wert, den keiner will.
Zum Gesamtkonzept kann ich nichts sagen. Ist wahrscheinlich auch nur
akademisch.
@ Mein grosses Vorbild (vorbild)
>> Nein, das atomar bezieht sich auf alle anderen Bits ausser Bit4!>Nun komm, sind wir hier im Häkelbüdelclub?
Ich zumindest nicht. ;-)
>Entweder es ist atomar oder es ist nicht atomar. Dazwischen ist Raum für>gar nichts.
Nö.
Beispiel 1.
Bit4 wird von Funktionen in der Hauptschleife verwendet, andere Bits am
Port von Interrupts. Damit das reibungsfrei klappt, müssen die Zugriffe
atomar sein. Entweder mit Interruptsperre oder den genannten
_SET/_CLEAR/_TOGGLE Registern, je nach Verfügbarkeit.
Beispiel 2.
Man will/muss mehrere Flags in ein Byte packen, warum auch immer. Um
diese einzeln und atomar setzen zu können, kann man beim AVR bzw.
ATXmega Register im bitadressierbaren Bereich nutzen (Beim ATXmega sind
sie sogar exclusiv dafür gedacht!) und mittels sbi/cbi sbis/sbic
einzelne Bits in Registern atomar lesen und schreiben, ohne
Interuptsperre.
Das Thema atomar bezieht sich nicht ausschließlich auf Int/Word/Long
whatever Variablen, die als Ganzes benutzt werden.
Falk B. schrieb:> Nö.
Doch.
Falk B. schrieb:> Entweder mit Interruptsperre oder den genannten> _SET/_CLEAR/_TOGGLE Registern, je nach Verfügbarkeit.
Es steht aber nur ein TOGGLE zur Verfügung. Diese Operation ist relativ.
Nämlich abhängig vom momentanen Zustand. Wenn das Bit eingelesen wurde,
wird eine Entscheidung getroffen, ob das Bit getoggelt werden muß oder
nicht. Ändert sich dieses Bit währenddessen, ist diese getroffene
Entscheidung falsch. Damit ist diese Operation nicht per se atomar.
Falk B. schrieb:> Das Thema atomar bezieht sich nicht ausschließlich auf Int/Word/Long> whatever Variablen, die als Ganzes benutzt werden.
Was willst du mir damit sagen? Geht es darum in diesem Thread? Ich denke
nicht.