zwei Bits beeinflussen - ich steh geradeauf dem Schlauch

Gast #2731093
Lesenswert?

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?
Gast #2731100
Lesenswert?

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
Gast #2731115
Lesenswert?

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:
1
#define Zustand1 (PORTC |= 0x01);PORTC &= ~0x02)
2
#define Zustand2 (PORTC |= 0x02);PORTC &= ~0x01)
Gast #2731119
Lesenswert?

1
uint8_t u8Tmp;
2

3
...
4
u8Tmp =  PORTB;
5
u8Tmp &= ~(1<<PBx);
6
u8Tmp ¦=  (1<<PBy);
7
PORTB =  u8Tmp;

Hier wird zwar die Manipulation hintereinander gemacht, aber die 
Ausgänge schalten zeitgleich um.
Gast #2731121
Lesenswert?

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.
Gast #2731122
Lesenswert?

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
Gast #2731125
Lesenswert?

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.
(Firma: guloshop.de) #2731152
Lesenswert?

Hallo,

vielleicht habe ich das Problem auch falsch verstanden, aber es reichen 
doch zwei Befehle. Zum Beispiel:
1
sbi PORTB,0
2
cbi PORTB,1
Dadurch werden im Register PORTB das Bit 0 gesetzt und das Bit 1 
gelöscht. Die übrigen Bits bleiben unberührt.
Gast #2731236
Lesenswert?

>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...
Gast #2731380
Lesenswert?

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
#2731399
Lesenswert?

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
void SignalToRed()
2
{
3
  LED_PORT ~= ( 1 << GREEN_LED );
4
  LED_PORT |= ( 1 << RED_LED );
5
}
6

7
void SignalToGreen()
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.
Gast #2731511
Lesenswert?

>das Instrument einer Funktion

Sehr gut formuliert ;-)


EDIT:

Das ist wohl ein Schnelligkeitsfehler:
1
 LED_PORT ~= ( 1 << GREEN_LED );

soll bestimmt so heissen:
1
 LED_PORT &= ~( 1 << GREEN_LED );
(Firma: guloshop.de) #2731695
Lesenswert?

Karl Heinz Buchegger schrieb:
1
>  LED_PORT |= ( 1 << RED_LED );

Ist eigentlich sichergestellt, dass diese Zeile in einen atomaren Befehl 
übersetzt wird? Wenn ich Pech habe, macht der Compiler sowas draus:

1
in r16,LED_PORT
2
ori r16,( 1 << RED_LED )
3
out LED_PORT,r16

Und das ist funktional doch etwas anderes als

1
sbi LED_PORT,RED_LED

Jedenfalls, wenn am gleichen Port auch Eingänge verarbeitet werden und 
das Programm Interrupts nutzt...
Gast #2731749
Lesenswert?

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
Gast #2731754
Lesenswert?

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.
(Firma: Atelier Klippel) #2731757
Lesenswert?

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
Gast #2731763
Lesenswert?

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.
Gast #2731767
Lesenswert?

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.
Gast #2731769
Lesenswert?

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
Gast #2731773
Lesenswert?

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.
Gast #2731781
Lesenswert?

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
#2731784
Lesenswert?

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.
#2731799
Lesenswert?

PS: Universell ausgedrückt wäre das also:
1
#define CAT(a,b) a##b
2
#define AssignPins(port,mask,value) CAT(PIN,port) = (CAT(PORT,port) & (mask)) ^ (value)
3

4
AssignPins(D,0b11,val);
Resultat:
1
PIND = (PORTD & (0b11)) ^ (val);

Oder für Freunde abartiger Syntax:
1
#define CAT(a,b) a##b
2
#define AssignPins(port,mask) CAT(PIN,port) = (CAT(PORT,port) & (mask)) ^
3

4
AssignPins(D,0b11) val;
Gast #2732101
Lesenswert?

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!

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