Ich möchte mit meinem Atmel zwei PORT-Bits gleichzeitig beeinflussen (1
Bit setzen und 1 Bit zurücksetzen) ohne die anderen sechs Bits zu
verändern.
Ich weiß, dass ich mit &=~ ein Bit rücksetzen kann und mit |= eins
setzen kann, aber wie kann ich das Gleichzeitig?
Ich brauche zwei Zustände: xxxx xx01 und xxxx xx10
Kann ich das in einem Befehl machen? Toggeln geht nicht, weil ich den
Ausgangszustandnicht kenne und vorher sonst erst auslesen müsste.
Gesucht ist sowas wie <PortB 0x03> (hintere beiden ausgänge) = <0x01>
bzw. <0x02> setzen.
Wisst ihr was ich meine?
Mike schrieb:> aber wie kann ich das Gleichzeitig?
ohne den port einzulesen, manipuliere und ausgeben geht es nicht.
Ich würde es nacheinander machen. Das ist die schnellste lösung, aber
halt nicht gleichzeitig.
Hi
>Kann ich das in einem Befehl machen? Toggeln geht nicht, weil ich den>Ausgangszustandnicht kenne und vorher sonst erst auslesen müsste.
Kommt auf deinen AVR an. Neuere AVRs können Pins direkt durch Schreiben
in das Pin-Register togglen.
MfG Spess
OK, schon mal danke. Dann stehe ich ja doch nicht so auf dem Schlauch
wie vermutet.
Wenn ich das jetzt nacheinander machen möchte (1 Bit setzen, 1 Bit
zurücksetzen) kann ich das über ein #define hinbekommen?
so nach dem Motto:
zur Info:
die Ausgänge an sich brauchen nicht Zeitgleich Ihren Zustand ändern. Was
ich meinte, ist: ich möchte in meinem Programmablauf die Ausgänge mit
einem "Befehl" manipulieren und nicht immer zwei,drei Zeilen schreiben
um Fehler zu verhindern.
Hi
>Aber auch dann muss er den vorherigen Zustand dieser beiden Pins kennen.>Will er aber nicht.
Wenn er immer beide gleichzeitig togglen will, braucht er nur einmal
einen definierten Anfangszustand.
MfG Spess
Matthias Lipinsky schrieb:> Hier wird zwar die Manipulation hintereinander gemacht, aber die> Ausgänge schalten zeitgleich um.
in der hoffnung das nicht eine ISR in der Zeit die ausgänge geändert
hat, das ganze ist nicht meht atomar.
Man könnte aber den Port einlesen und sich danach eine Toggle-Maske
bauen. Dann den Port Togglen. Das hätte den Vorteil das die anderen Pins
nicht angefasst werden.
spess53 schrieb:> Wenn er immer beide gleichzeitig togglen will, braucht er nur einmal> einen definierten Anfangszustand.
Klar, aber er hatte ja ausdrücklich geschrieben, dass er aufgrund
Unkenntnis des Zustands nicht toggeln will.
Mike schrieb:> zur Info:>> die Ausgänge an sich brauchen nicht Zeitgleich Ihren Zustand ändern. Was>> ich meinte, ist: ich möchte in meinem Programmablauf die Ausgänge mit>> einem "Befehl" manipulieren und nicht immer zwei,drei Zeilen schreiben>> um Fehler zu verhindern.
Warum machst du für die 3 Zeilen dann nicht einfach ein Macro?
@ Markus W. (m-w)
>sbi PORTB,0>cbi PORTB,1>Dadurch werden im Register PORTB das Bit 0 gesetzt und das Bit 1>gelöscht. Die übrigen Bits bleiben unberührt.
Aber nicht zeitgleich.
>ich meinte, ist: ich möchte in meinem Programmablauf die Ausgänge mit>einem "Befehl" manipulieren und nicht immer zwei,drei Zeilen schreiben>um Fehler zu verhindern.
Ich weiss ja nicht, wie oft du in deinem Programm diese Port-änderungen
durchführen musst, aber wenn es weniger als 42mal sind, hast du jetzt
eben im Forum mehr blabla geschrieben, als diese ".. zwei, drei Zeilen
.." an Tipparbeit sind...
Matthias Lipinsky schrieb:> Ich weiss ja nicht, wie oft du in deinem Programm diese Port-änderungen> durchführen musst, aber wenn es weniger als 42mal sind, hast du jetzt> eben im Forum mehr blabla geschrieben, als diese ".. zwei, drei Zeilen> .." an Tipparbeit sind...
1.: Dies diente lediglich der allgemeinen Information
2.: Das Wissen wird garantiert auch in Zukunft benötigt
3.: Flüchtigkeitsfehler, C&P-Fehler kennt wohl jeder
4.: Evtl. hat es auch einige Mitleser interessiert
Trotzdem bedanke ich mich bei allen Beteiligten für die Informationen
und den Input, der zusätzlich gegeben wurde.
Vielen Dank
Mike schrieb:> 2.: Das Wissen wird garantiert auch in Zukunft benötigt
Fair enough.
Dann lass dir gesagt sein, dass du im Hinblick auf ...
> ich möchte in meinem Programmablauf die Ausgänge mit> einem "Befehl" manipulieren und nicht immer zwei,drei Zeilen> schreiben um Fehler zu verhindern.
... um derartige Makros einen Bogen machen solltest und das Instrument
einer Funktion in Anspruch nehmen solltest.
Das ist einfach, banal und vermeidet Fehler ganz wunderbar.
1
voidSignalToRed()
2
{
3
LED_PORT~=(1<<GREEN_LED);
4
LED_PORT|=(1<<RED_LED);
5
}
6
7
voidSignalToGreen()
8
{
9
LED_PORT|=(1<<GREEN_LED);
10
LED_PORT~=(1<<RED_LED);
11
}
Dann hast du an der aufrufenden Stelle ebenfalls den Komfort eines
'Befehls', den der Compiler (wenn es sich lohnt) inline expandieren kann
(das kostet dir also keine Mehr-Laufzeit) und bist auf der sicheren
Seite was Nebeneffekte angeht (was du bei Makros nicht unbedingt bist.
Zumindest dann nicht, wenn man das Makro so schreibt wie du das getan
hast).
Generell:
Benutze Makros um Konstanten zu ersetzen
Ab und an kann man auch mal einen einzigen Befehl in einem Makro
verstecken. Sobald es aber etwas komplexer wird (und ja: 2 Befehle
können schon komplex sein), bevorzuge lieber Funktionen.
Markus W. schrieb:> Ist eigentlich sichergestellt, dass diese Zeile in einen atomaren Befehl> übersetzt wird?
Nein. Manche AVRs besitzen Ports ausserhalb des bitadressierbaren
Bereichs.
Ist in dieser Form nicht atomar (sehr wohl aber bei "PIND = 3;") und
benötigt Kenntnis des vorherigen Zustands - dies aber hatte er in seiner
ursprünglichen Frage ausgeschlossen.
Hi
>dies aber hatte er in seiner>ursprünglichen Frage ausgeschlossen.
Mike schrieb:
>Ich möchte mit meinem Atmel zwei PORT-Bits gleichzeitig beeinflussen (1>Bit setzen und 1 Bit zurücksetzen) ohne die anderen sechs Bits zu>verändern.
Das ist bei mir togglen.
>Kann ich das in einem Befehl machen? Toggeln geht nicht, weil ich den>Ausgangszustandnicht kenne und vorher sonst erst auslesen müsste.
Frage mich warum.
MfG Spess
spess53 schrieb:>>Ich möchte mit meinem Atmel zwei PORT-Bits gleichzeitig beeinflussen (1>>Bit setzen und 1 Bit zurücksetzen) ohne die anderen sechs Bits zu>>verändern.>> Das ist bei mir togglen.
Ne, es ist nur dann togglen, wenn er weiß, dass das zu löschende Bit
tatsächlich gesetzt ist und umgekehrt.
Die Instrktionen sbi/cbi arbeiten übrigens auch nicht ganz atomar. Die
machen auch 'nur' Read-Modify-Write.
Naja, ist halt immer die Frage wie atomar es nötig ist. Einzelne Bits
nacheinander setzen/löschen sind ja ebenfalls mehrere Instruktionen.
ursprünglich hiess es ja:
"Ich brauche zwei Zustände: xxxx xx01 und xxxx xx10"
Wenn man also einmalig bei Programmstart auf xxxx xx01 setzt, und
anschliessend mit xxxx xx11 ein XOR macht, toggeln halt beide Bits, und
das halt zur gleichen Zeit. Ich kenne mich mit AVR Assembler nicht so
aus, aber bei einem PIC wäre das z.B.:
MOVLW 0x03
XORWF LATC, F, ACCESS
Also einmal die Maske in das Arbeitsregister laden, und dann mit einem
einzigen Befehl den Ausgangsport verändern. Wäre also atomar was den
reinen Port angeht. Die AVR werden doch sicherlich etwas vergleichbares
haben?
Grüße,
Chris
Sven P. schrieb:> Die Instrktionen sbi/cbi arbeiten übrigens auch nicht ganz atomar. Die> machen auch 'nur' Read-Modify-Write.
Bezogen auf das ganze Byte? Das wär nicht gut... Woher hast du diese
Information?
Christian Klippel schrieb:> Die AVR werden doch sicherlich etwas vergleichbares> haben?
Jein. Wie schon geschrieben: Bei den neueren wirkt ein Schreibzugriff
aufs PIN-Register wie ein Umschießen im PORT-Register.
Ansonsten ist AVR halt RISC und Harvard. Da geht das Umschießen
tatsächlich auch händisch nur als Read-Modify-Write. Setzen und Löschen
dagegen geht (meistens) mit den cbi/sbi-Instruktionen. Umschießen aber
eben nicht... mit o.g. Ausnahme.
Markus W. schrieb:> Sven P. schrieb:>> Die Instrktionen sbi/cbi arbeiten übrigens auch nicht ganz atomar. Die>> machen auch 'nur' Read-Modify-Write.>> Bezogen auf das ganze Byte? Das wär nicht gut... Woher hast du diese> Information?
Aus den Datenblättern. Das ist im Übrigen wohl der Grund, weshalb man
Interruptflaggen durch Beschreiben mit einer '1' löscht. Andernfalls
(lesen, ver-und-en, schreiben, händisch als auch mit cbi/sbi) könnte man
versehentlich eine Flagge plattmachen, die zwischenzeitlich von der
Hardware gesetzt wurde.
Hi
>Ne, es ist nur dann togglen, wenn er weiß, dass das zu löschende Bit>tatsächlich gesetzt ist und umgekehrt.
Bei einem XOR oder, wie vorgeschlagen, Togglen über PIN-Register muss
man es nicht wissen.
MfG Spess
spess53 schrieb:> Hi>>>Ne, es ist nur dann togglen, wenn er weiß, dass das zu löschende Bit>>tatsächlich gesetzt ist und umgekehrt.>> Bei einem XOR oder, wie vorgeschlagen, Togglen über PIN-Register muss> man es nicht wissen.
Er hat doch beschrieben, dass er die Zustände '...01' und '...10'
braucht, aber nicht weiß, welche Bits aktuell gesetzt sind (nicht:
welcher Zustand gerade vorherrscht). Daraus schließe ich, dass er auch
von '...00' und '...11' in einen der beiden Zustände kommen will. Und
das funktioniert mit Umschießen eben gerade nicht mehr.
spess53 schrieb:> Bei einem XOR oder, wie vorgeschlagen, Togglen über PIN-Register muss> man es nicht wissen.
Na dann verrate uns mal, wie du in einer solchen Operation Bit 0 auf 0
und Bit 1 auf 1 setzt, wenn du den bisherigen Zustand dieser beiden Bits
nicht kennst und ihn nicht auslesen darfst.
Hi
>Er hat doch beschrieben, dass er die Zustände '...01' und '...10'>braucht, aber nicht weiß, welche Bits aktuell gesetzt sind (nicht:>welcher Zustand gerade vorherrscht). Daraus schließe ich, dass er auch>von '...00' und '...11' in einen der beiden Zustände kommen will. Und>das funktioniert mit Umschießen eben gerade nicht mehr.
Vielleicht sollte Mike das mal klären. Denn ich glaube das ist der
Knackpunkt. Persönlich kann ich das nämlich nicht so herauslesen.
MfG Spess
Sven P. schrieb:> von '...00' und '...11' in einen der beiden Zustände kommen will.
Unnötig. Es reicht, wenn er nicht weiss, ob es aktuell 01 oder 10 ist,
er aber hinterher 01 haben will. Das geht nicht in einer Operation, ohne
vorher auszulesen. Mit auslesen geht es aber (echt) atomar bezogen auf
die übrigen Bits mit
PINx = (PORTx & 0b11) ^ 0b01;
wenn der AVR diese PINx Toggle-Operation versteht. Da er aber mit zwei
Bit-Operationen leben kann ist auch das unnötig komplex. Vorteil dieser
Variante ist freilich, dass der neue Wert nicht konstant sein muss.
Karl Heinz Buchegger schrieb:> Dann hast du an der aufrufenden Stelle ebenfalls den Komfort eines> 'Befehls', den der Compiler (wenn es sich lohnt) inline expandieren kann> (das kostet dir also keine Mehr-Laufzeit) und bist auf der sicheren> Seite was Nebeneffekte angeht (was du bei Makros nicht unbedingt bist.> Zumindest dann nicht, wenn man das Makro so schreibt wie du das getan> hast).>> Generell:> Benutze Makros um Konstanten zu ersetzen> Ab und an kann man auch mal einen einzigen Befehl in einem Makro> verstecken. Sobald es aber etwas komplexer wird (und ja: 2 Befehle> können schon komplex sein), bevorzuge lieber Funktionen.
Vielen Dank für diese zusammenfassende Ausführung.
spess53 schrieb:>>Er hat doch beschrieben, dass er die Zustände '...01' und '...10'>>braucht, aber nicht weiß, welche Bits aktuell gesetzt sind (nicht:>>welcher Zustand gerade vorherrscht). Daraus schließe ich, dass er auch>>von '...00' und '...11' in einen der beiden Zustände kommen will. Und>>das funktioniert mit Umschießen eben gerade nicht mehr.>> Vielleicht sollte Mike das mal klären.
Ja, es ist richtig.
Ich stoße aktiv die Zustände xx01 und xx10 an. Generell kann es aber
vorkommen, dass der Ausgangszustand auch schon mal xx00 ist. Daher kann
ich auch nicht einfach toggeln. xx11 sollte bei mir auf keinen Fall
vorkommen!
A. K. schrieb:> Mit auslesen geht es aber (echt) atomar bezogen auf> die übrigen Bits mit> PINx = (PORTx & 0b11) ^ 0b01;> wenn der AVR diese PINx Toggle-Operation versteht.
Das ist wirklich elegant, gefällt mir.