Forum: Mikrocontroller und Digitale Elektronik AVR/C: Bits in Register in einem Schritt löschen und andere setzen


von Patrick S. (psar04)


Lesenswert?

Hallo,

ich möchte gerne auf einem ATmega 328p im Register TCCR2B die Bits CS22 
und CS20 setzen und die Bits CS21 und WGM22 löschen.
Ich kann das in zwei Schritten mittels
1
TCCR2B |= ((1<<CS22|(1<<CS20));
2
TCCR2B &= ~((1<<WGM22)|(1<<CS21));
bewerkstelligen. Der Timer/Counter2 soll allerdings asynchron laufen und 
ich müsste das Setzen erst abwarten (Prüfung des Bits TCR2BUB aus ASSR) 
bevor ich den Löschvorgang starte. Die Werte landen ja erst in einem 
temporären Register und würden ansonsten möglicherweise überschrieben.
Kann ich mit
1
((1<<CS22|(1<<CS20)|(0<<WGM22)|(0<<CS21))
irgendwie arbeiten??

Viele Grüße,
Patrick

: Bearbeitet durch User
von __avrdude (Gast)


Lesenswert?

Patrick S. schrieb:
> Kann ich mit((1<<CS22|(1<<CS20)|(0<<WGM22)|(0<<CS21))irgendwie
> arbeiten??

nein, weil das der Oder Operator ist. Und irgendwas | X = irgendwas und 
eben nicht gelöscht.

Außerdem bringts dir von der Laufzeit her überhaupt nichts, es sieht nur 
etwas unübersichtlicher aus

von Patrick S. (psar04)


Lesenswert?

__avrdude schrieb:
> nein, weil das der Oder Operator ist. Und irgendwas | X = irgendwas und
> eben nicht gelöscht.

Ok, vielen Dank. Mir ist noch eingefallen, dass ich sowas wie
1
TCCR2B = ((1<<CS22|(1<<CS20)|(0<<WGM22)|(0<<CS21))
machen könnte. Allerdings nur in diesem Fall, da die anderen Bits des 
Registers auch 0 sein dürfen. Wäre allerdings unschön und bringt 
vielleicht später komische Probleme hervor...

> Außerdem bringts dir von der Laufzeit her überhaupt nichts, es sieht nur
> etwas unübersichtlicher aus

Wenn ich die Zuweisung in einem Schritt machen könnte, würde ich doch 
etwas Zeit sparen?! So muss ich ja noch warten, dass die Daten aus dem 
temporären Register in das Zielregister übertragen wurden und kann erst 
dann die Bits löschen.

von Georg G. (df2au)


Lesenswert?

Patrick S. schrieb:
> (0<<WGM22)|(0<<CS21)

Eine Null kannst du schieben, wohin du möchtest, es bleibt wirkungslos 
beim Verodern.

von Wolfgang (Gast)


Lesenswert?

Patrick S. schrieb:
> Ok, vielen Dank. Mir ist noch eingefallen, dass ich sowas wie TCCR2B =
> ((1<<CS22|(1<<CS20)|(0<<WGM22)|(0<<CS21)) machen könnte.

Könntest du machen - bringt aber nichts. Du solltest dein Verständnis 
vom "|"-Operator (Bitweises ODER) noch deutlich vertiefen.

von chris (Gast)


Lesenswert?

Patrick S. schrieb:
> Wenn ich die Zuweisung in einem Schritt machen könnte, würde ich doch
> etwas Zeit sparen?!

NEIN du sparst keine Zeit. An der Basis wird trotzdem dein Ausdruck

TCCR2B = ((1<<CS22|(1<<CS20)|(0<<WGM22)|(0<<CS21))

wie folgt ausgeführt

ldi  REGISTER , (1<<CS22|1<<CS20|0<<WGM22|0<<CS21)
out  TCCR2B , REGISTER
.

Wenn du gewisse Bits hast die nicht verändert werden sollen/dürfen... 
dann bietet sich eine Ver(oder)ung oder Ver(und)ung an.

z.B. fürs setzen

in   REGISTER , TCCR2B                             ; ins REGISTER laden
or   REGISTER , (1<<CS22|1<<CS20|0<<WGM22|0<<CS21) ; REGISTER verodern
out  TCCR2B   , REGISTER                           ; Wert ins TCCR2B 
laden

z.B. fürs löschen

in   REGISTER , TCCR2B                             ; ins REGISTER laden
and  REGISTER , (1<<CS22|1<<CS20|0<<WGM22|0<<CS21) ; REGISTER verodern
out  TCCR2B   , REGISTER                           ; Wert ins TCCR2B 
laden

ACHTUNG dort wo eine 0 steht wird am Ende das Bit (falls gesetzt) 
gelöscht.

von Patrick S. (psar04)


Lesenswert?

Georg G. schrieb:
> Eine Null kannst du schieben, wohin du möchtest, es bleibt wirkungslos
> beim Verodern.

Ja klar, statt
1
TCCR2B = ((1<<CS22)|(1<<CS20)|(0<<WGM22)|(0<<CS21));
kann ich auch
1
TCCR2B = ((1<<CS22)|(1<<CS20));
schreiben.
Mir ging es in dem Beispiel nur darum, dass ich = statt |= verwendet 
habe.
1
(0<<WGM22)|(0<<CS21)
 habe ich stehengelassen, damit klar wird, was ich vorhatte.

von Karl M. (Gast)


Lesenswert?

Hallo,
wobei der Schreiber hier eine Fehler gemacht hat.
Löschen immer noch mit dem
<reg> &= <reg> ~<bit-mask>

Richtig:
1
;z.B. fürs löschen
2
in   REGISTER , TCCR2B                             ; ins REGISTER laden
3
and  REGISTER ,not (1<<CS22|1<<CS20|0<<WGM22|0<<CS21) ; REGISTER 
4
out  TCCR2B   , REGISTER                           ; Wert ins TCCR2B 
5
laden

von chris (Gast)


Lesenswert?

Karl M. schrieb:
> and  REGISTER ,not (1<<CS22|1<<CS20|0<<WGM22|0<<CS21) ; REGISTER

Ging mir nur um das WIE. Der TO muss die Transferleistung selber bringen 
falls der Hinweis überhaupt nützlich war

von Patrick S. (psar04)


Lesenswert?

chris schrieb:
> Patrick S. schrieb:
>> Wenn ich die Zuweisung in einem Schritt machen könnte, würde ich doch
>> etwas Zeit sparen?!
>
> NEIN du sparst keine Zeit. An der Basis wird trotzdem dein Ausdruck
>
> TCCR2B = ((1<<CS22|(1<<CS20)|(0<<WGM22)|(0<<CS21))
>
> wie folgt ausgeführt
>
> ldi  REGISTER , (1<<CS22|1<<CS20|0<<WGM22|0<<CS21)
> out  TCCR2B , REGISTER
> .
Das ist soweit klar. Das sind in diesem Fall 2 Assembler-Befehle und in 
diesem Fall braucht jeder 1 Takt, damit insgesamt 2 Takte.

> Wenn du gewisse Bits hast die nicht verändert werden sollen/dürfen...
> dann bietet sich eine Ver(oder)ung oder Ver(und)ung an.
>
> z.B. fürs setzen
>
> in   REGISTER , TCCR2B                             ; ins REGISTER laden
> or   REGISTER , (1<<CS22|1<<CS20|0<<WGM22|0<<CS21) ; REGISTER verodern
> out  TCCR2B   , REGISTER                           ; Wert ins TCCR2B
> laden
>
> z.B. fürs löschen
>
> in   REGISTER , TCCR2B                             ; ins REGISTER laden
> and  REGISTER , (1<<CS22|1<<CS20|0<<WGM22|0<<CS21) ; REGISTER verodern
> out  TCCR2B   , REGISTER                           ; Wert ins TCCR2B
> laden
>
> ACHTUNG dort wo eine 0 steht wird am Ende das Bit (falls gesetzt)
> gelöscht.

Die Veroderung bzw. Verundung erfordern 3 ASM-Befehle und jeweils 3 
Takte. Damit also 1 Takt mehr als die einfache Zuweisung (erste 
Variante) und somit also auch mehr Zeit!
Ich weiß, dass mir dies in meinem Fall nichts bringt, da ich damit nicht 
das erreiche, was ich vorhatte. Ich werde nun also in 3 Takten die 
Veroderung durchführen und die gewünschten Bits setzen, dann x Takte 
warten, bis das TCR2BUB Bit aus ASSR wieder 0 ist und im Anschluss noch 
einmal 3 Takte verwenden, um über die Verundung die gewünschten Bits zu 
löschen. Macht 6 + x Takte.
Es hätte ja sein können, dass es eine (mir unbekannte) C-Anweisung gibt, 
der ich sagen kann lösche die Bits t, u und setze die Bits v, w aus 
Register k. Meinetwegen dürfte diese ja auch 4, 5, 6 oder 7 Takte 
benötigen. So wäre ich dann aber garantiert in den 4-7 Takten fertig. 
Das Warten auf TCR2BUB könnte ich mir komplett sparen, da ich danach 
nicht noch einmal auf TCCR2B zugreife (bzw. erst sehr viel später, wenn 
der Wert aus dem temporären Register garantiert schon in das 
Zielregister geschrieben wurde). Ich würde mir so also die x Takte 
sparen.
So habe ich allerdings immer eine zusätzliche Verzögerung, selbst wenn 
der Wert aus dem temporären Register zufällig schon übernommen wurde. 
Das kommt halt daher, dass ich noch sowas wie
1
while(ASSR & (1<<TCR2BUB));
 einbauen muss. Auf Assembler-Ebene also wieder IN, ANDI, BRNE (oder so 
ähnlich) mit vermutlich um die 5 Takten, das ganze dann noch 
multiplizert mit der Anzahl der Schleifendurchläufe. So ganz genau lässt 
sich das ja auch nicht sagen, da die Branches unterschiedlich lange 
brauchen.

So viel also zu meiner Veranlassung hier nachzufragen. Ein klares "Nein, 
geht nicht." hätte mir schon gereicht. :D

von Patrick S. (psar04)


Lesenswert?

Karl M. schrieb:
> Hallo,
> wobei der Schreiber hier eine Fehler gemacht hat.
> Löschen immer noch mit dem
> <reg> &= <reg> ~<bit-mask>

Naja eigentlich
1
<reg> &= ~<bit-mask>
, das was du schreibst ist ja aufgelöst
1
<reg> = <reg> & <reg> ~<bit-mask>
.

von Peter D. (peda)


Lesenswert?

Patrick S. schrieb:
> TCCR2B |= ((1<<CS22|(1<<CS20));
> TCCR2B &= ~((1<<WGM22)|(1<<CS21));

Wo ist das Problem?
1
  TCCR2B = (TCCR2B & ~((1<<WGM22)|(1<<CS21))) | ((1<<CS22|(1<<CS20));

von Patrick S. (psar04)


Lesenswert?

chris schrieb:
> Ging mir nur um das WIE. Der TO muss die Transferleistung selber bringen
> falls der Hinweis überhaupt nützlich war

Wenn ich ehrlich bin, war der Hinweis nicht sooo nützlich. Ich kenne 
zwar auch die Assembler-Befehle, aber davon auszugehen und dann einfach 
Assembler schreiben, obwohl ich C-Code gesucht habe... Naja, ich glaube 
die Problematik, auf die ich hinaus wollte, war auch nicht so ganz klar. 
;)

von Patrick S. (psar04)


Lesenswert?

Peter D. schrieb:
> Wo ist das Problem?
>
1
>   TCCR2B = (TCCR2B & ~((1<<WGM22)|(1<<CS21))) | ((1<<CS22|(1<<CS20));
2
>
Danke, ich glaube sowas habe ich gesucht. Anscheinend hat mich jetzt 
doch noch wer verstanden. :)

: Bearbeitet durch User
von chris (Gast)


Lesenswert?

Patrick S. schrieb:
> Ich weiß, dass mir dies in meinem Fall nichts bringt, da ich damit nicht
> das erreiche, was ich vorhatte. Ich werde nun also in 3 Takten die
> Veroderung durchführen und die gewünschten Bits setzen, dann x Takte
> warten, bis das TCR2BUB Bit aus ASSR wieder 0 ist und im Anschluss noch
> einmal 3 Takte verwenden, um über die Verundung die gewünschten Bits zu
> löschen. Macht 6 + x Takte.

Nein geht doch einfacher mit 4 Takten

in   REGISTER , TCCR2B                             ; ins REGISTER laden
and  REGISTER , (1<<CS22|1<<CS20|0<<WGM22|0<<CS21) ; einzelen Bits 
löschen
or   REGISTER , (y<<CS22|y<<CS20|y<<WGM22|y<<CS21) ; REGISTER verodern
out  TCCR2B   , REGISTER                           ; Wert ins TCCR2B

Patrick S. schrieb:
> Wenn ich ehrlich bin, war der Hinweis nicht sooo nützlich. Ich kenne
> zwar auch die Assembler-Befehle, aber davon auszugehen und dann einfach
> Assembler schreiben, obwohl ich C-Code gesucht habe... Naja, ich glaube
> die Problematik, auf die ich hinaus wollte, war auch nicht so ganz klar.

Um Wissen zu erlangen gibt es nie einen direkten Weg.
Ich kann kein C deshalb ASM sry. Könnte ich es hättest du schon ein 
Nein/Ja geht/nicht bekommen ;)

von Patrick S. (psar04)


Lesenswert?

chris schrieb:
> Nein geht doch einfacher mit 4 Takten
>
> in   REGISTER , TCCR2B                             ; ins REGISTER laden
> and  REGISTER , (1<<CS22|1<<CS20|0<<WGM22|0<<CS21) ; einzelen Bits
> löschen
> or   REGISTER , (y<<CS22|y<<CS20|y<<WGM22|y<<CS21) ; REGISTER verodern
> out  TCCR2B   , REGISTER                           ; Wert ins TCCR2B

Im wesentlichen müsste das ja der C-Code von peda sein, übersetzt in 
Assembler. y<<CS22 habe ich so aber wiederum noch nicht gesehen. Kannst 
du mir sagen, was das bedeutet oder ist das ein Tippfehler?
AND und OR müssten auch ANDI bzw. ORI sein, wenn ich das richtig im Kopf 
habe und bis auf WGM22 bzw. CS21 müssen alle anderen Bits auf 1 gesetzt 
werden, um seiteneffektfrei zu arbeiten. Alternativ mit NOT arbeiten.

Ich hätte peda's Code vermutlich so übersetzt, ohne den getestet zu 
haben:
1
IN REGISTER, TCCR2B
2
ANDI REGISTER, not (1<<WGM22|1<<CS21)
3
ORI REGISTER, (1<<CS22|1<<CS20)
4
OUT TCCR2B, REGISTER

von chris (Gast)


Lesenswert?

Patrick S. schrieb:
> Im wesentlichen müsste das ja der C-Code von peda sein, übersetzt in
> Assembler.

keine Ahnung wessen Code das ist aber mit Überlegung wo man was wie 
braucht kommt man doch selber drauf

Patrick S. schrieb:
> y<<CS22 habe ich so aber wiederum noch nicht gesehen. Kannst
> du mir sagen, was das bedeutet oder ist das ein Tippfehler?

Das y ist ein PLatzhalter je nachdem was du brauchst 0/1.

jep stimmt mit dem ANDI/ORI, da es Konstante mit Register verknüpft, das 
ist mein Fehler. 0.o

Patrick S. schrieb:
> bis auf WGM22 bzw. CS21 müssen alle anderen Bits auf 1 gesetzt
> werden,

Jep stimmt aber nur beim ANDI. Das ORI sagt wieder welche Bits gesetzt 
werden sollen dh es müssen nur die eingetragen werden die eine 1 
bekommen sollen.

ACHTUNG das war mir vorher nicht aufgefallen ist, guck mal in das 
DATENBLATT du möchtest/musst zwei verschiedene Register ansprechen, 
TCCR2A und TCCR2B!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Im TCCR2A WGM20/21 ändern und im TCCR2B CS22/21/20 WGM22 ändern

IN   REGISTER, TCCR2B
ANDI REGISTER, (0<<CS22|0<<CS21|0<<CS20|0<<WGM22|1<<FOC2B|1<<FOC2A), nur 
löschen
ORI  REGISTER, (y<<CS22|y<<CS21|y<<CS20|y<<WGM22)
OUT  TCCR2B  , REGISTER

IN   REGISTER, TCCR2A
ANDI REGISTER, 
(0<<WGM20|0<<WGM21|1<<COM2B0|1<<COM2B1|1<<COM2A0|1<<COM2A1), nur löschen
ORI  REGISTER, (y<<WGM20|y<<WGM21)
OUT  TCCR2A  , REGISTER

Und nutze den Simulator wenn du einen hast und probiers durch denn dafür 
is das Ding da. ;)

Um auf deine Takte anzusprechen bei 4Mhz sind es pro Takt 250ns, 500ns 
oder 750ns in der Ausführungszeit da sind diese 8 Befehle n Klacks 
dagegen. Nach 8*250ns = 2µs ist der Drops gelutscht. :))

von W.A. (Gast)


Lesenswert?

Patrick S. schrieb:
> y<<CS22 habe ich so aber wiederum noch nicht gesehen. Kannst
> du mir sagen, was das bedeutet oder ist das ein Tippfehler?

y ist hoffentlich ein Ganzzahl und die wird mit dem Befehl CS22-mal nach 
links geschoben. Was der Autor sich dabei gedacht hat und was er da 
hingeschrieben hat, mögen wohl zwei verschiedene Dinge sein.

Sinnvoll wäre, wenn y einen Clock Select Wert zwischen 0 und 7, enthält
1
y<<CS20
zu verwenden.

von Patrick S. (psar04)


Lesenswert?

chris schrieb:
> ACHTUNG das war mir vorher nicht aufgefallen ist, guck mal in das
> DATENBLATT du möchtest/musst zwei verschiedene Register ansprechen,
> TCCR2A und TCCR2B!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Die Werte im zweiten Register habe ich schon längst gesetzt. Das war ja 
auch nicht das Problem, ich wollte ja eigentlich nur eine Lösung 
möglichst effizient Werte in einem Register zu setzen und andere zu 
löschen.

von Hannez (Gast)


Lesenswert?

Das ist eines der Gründe, warum ich kein C mehr programmiere. Ich weiss 
genau, was registerseitig passieren soll, aber habe keine Ahnung, was C 
aus meinen Syntaxfantasien letztendlich umsetzt und jedes mal in den 
generierten ASM-Code schauen war mir zu blöd.

Als Assemblerprogrammierer nutzt man eigentlich auch nicht andi und ori, 
sondern cbr und sbr für Clear Register Bits und Set Register Bits. Dann 
ist das ganze auch intuitiver zu lesen.

in
cbr
sbr
out

und fertig.

von Hannez (Gast)


Lesenswert?

Und nein, ich habe nichts gegen C. Ich würde Programme für den PC nie in 
ASM schreiben, sondern in C. Aber für Mikrocontroller, die nur ein paar 
Pins rumtoggeln und ab und zu mal ein SPI Display ansteuern war es 
bisher immer die passendere Sprache.

von Patrick S. (psar04)


Lesenswert?

Hannez schrieb:
> Als Assemblerprogrammierer nutzt man eigentlich auch nicht andi und ori,
> sondern cbr und sbr für Clear Register Bits und Set Register Bits. Dann
> ist das ganze auch intuitiver zu lesen.
>
> in
> cbr
> sbr
> out

Guter Tipp, danke. Ich hätte vermutlich auch eher ASM genommen, 
allerdings wollte ich mir die AVR-Programmierung mit C mal genauer 
ansehen und zudem bin ich daran ein Projekt umzusetzen, was vom Umfang 
her etwas größer ist. Bin gerade am RTC-Modul, USART habe ich schon, 
dann noch Display und verschiedene Aktoren ansteuern, Sensoren abfragen, 
Textausgaben, UI und letztendlich soll das ganze noch eine gewisse 
Intelligenz (AI) haben, das war mir für ASM dann doch zu aufwändig. :)

von Heiko Kackmatsch (Gast)


Lesenswert?

1
uint8_t tmp = TCCR2B;
2
tmp |= ((1<<CS22|(1<<CS20));
3
tmp &= ~((1<<WGM22)|(1<<CS21));
4
TCCR2B = tmp;

Um es übersichtlich hinzuschreiben und kein Assembler heranzuziehen, 
kannst du natürlich auch einfach eine temporäre Variable verwenden. gcc 
sollte dann eigentlich automatisch mit Registern arbeiten...

von Peter D. (peda)


Lesenswert?

Hannez schrieb:
> aber habe keine Ahnung, was C
> aus meinen Syntaxfantasien letztendlich umsetzt

Das ist doch ganz einfach:
Wenn Du 2 Zuweisungen zu einem IO-Register hinschreibst, muß der 
Compiler auch 2 Zuweisungen ausführen.
Zugriffe auf IO-Register können nämlich Seiteneffekte haben und daher 
sind IO-Register als volatile deklariert.
Wenn Du aber nur eine Zuweisung hinschreibst, macht der Compiler auch 
nur eine Zuweisung, wer hätte das gedacht.
Auf der rechten Seite einer Zuweisung können beliebig lange Ausdrücke 
stehen, der Parser des Compilers kennt da kein Limit.

https://msdn.microsoft.com/de-de/library/474dd6e2.aspx

von Karl M. (Gast)


Lesenswert?

Hannez schrieb:
> Das ist eines der Gründe, warum ich kein C mehr programmiere. Ich
> weiss
> genau, was registerseitig passieren soll, aber habe keine Ahnung, was C
> aus meinen Syntaxfantasien letztendlich umsetzt und jedes mal in den
> generierten ASM-Code schauen war mir zu blöd.
>
> Als Assemblerprogrammierer nutzt man eigentlich auch nicht andi und ori,
> sondern cbr und sbr für Clear Register Bits und Set Register Bits. Dann
> ist das ganze auch intuitiver zu lesen.
>
> in
> cbr
> sbr
> out
>
> und fertig.

Nun cbr und andi mit not des Arguments sind das gleiche, auch als 
Assembler Kodierung.
Entsprechend gilt dies für sbr und ori..

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter D. schrieb:
> Wenn Du aber nur eine Zuweisung hinschreibst, macht der Compiler auch
> nur eine Zuweisung, wer hätte das gedacht.

 Nicht unbedingt, da es sich um AND und OR in derselben Zuweisung
 handelt.

Peter D. schrieb:
> TCCR2B = (TCCR2B & ~((1<<WGM22)|(1<<CS21))) | ((1<<CS22|(1<<CS20));

 Das ist nur eine Zuweisung in C, aber mindestens 2 in ASM.

von Peter D. (peda)


Lesenswert?

Marc V. schrieb:
> Das ist nur eine Zuweisung in C, aber mindestens 2 in ASM.

Das ist der Vorteil von C, wichtig ist immer nur, was hinten rauskommt.
Ob dabei Zwischenergebnisse temporär in CPU-Registern oder RAM abgelegt 
werden, interessiert den Programmierer nicht und sind auch keine 
Zuweisungen. CPU-Register/RAM sind ja danach wieder frei verfügbar.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Hannez schrieb:
> Als Assemblerprogrammierer nutzt man eigentlich auch nicht andi und ori,
> sondern cbr und sbr für Clear Register Bits und Set Register Bits. Dann
> ist das ganze auch intuitiver zu lesen.
>
> in
> cbr
> sbr
> out
>
> und fertig.

 Nicht immer.
 Nibbles werden immer mit AND ausgeblendet. Um es aber übersichtlicher
 zu machen, kann man vorher LoNibble und HiNibble definieren.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter D. schrieb:
> Ob dabei Zwischenergebnisse temporär in CPU-Registern oder RAM abgelegt
> werden, interessiert den Programmierer nicht und sind auch keine
> Zuweisungen. CPU-Register/RAM sind ja danach wieder frei verfügbar.

 Stimme ich zu, aber der TO wollte wissen ob das irgendwie in einem
 Schritt (ein Befehl) zu machen ist.
 Es geht nicht und daher ist deine Lösung zwar kürzer und eleganter aber
 man muss da schon ganz genau die Klammern zählen.
 Deswegen wären zwei Zeilen übersichtlicher und besser zu verstehen
 - von der Codegröße und Schnelligkeit besteht da kein Unterschied.

Peter D. schrieb:
> Das ist der Vorteil von C, wichtig ist immer nur, was hinten rauskommt.

 Und auch der Nachteil - Unübersichtlichkeit.

von Peter D. (peda)


Lesenswert?

Marc V. schrieb:
> aber der TO wollte wissen ob das irgendwie in einem
>  Schritt (ein Befehl) zu machen ist.

Nö, er wollte wissen, ob man den Seiteneffekt Synchronisierung nur 
einmal abwarten muß und das kann man bei nur einer Zuweisung.

Marc V. schrieb:
> aber
>  man muss da schon ganz genau die Klammern zählen.

Nö, das macht der Editor (z.B. Notepad++) für Dich. Einfach auf eine 
Klammer gehen und er zeigt die dazu gehörende schließende oder 
umgekehrt.
Ich bevorzuge allerdings die Vorrangregeln:
1
  TCCR2B = TCCR2B & ~(1<<WGM22 | 1<<CS21) | 1<<CS22 | 1<<CS20;

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter D. schrieb:
> Marc V. schrieb:
>> aber der TO wollte wissen ob das irgendwie in einem
>>  Schritt (ein Befehl) zu machen ist.
>
> Nö, er wollte wissen, ob man den Seiteneffekt Synchronisierung nur
> einmal abwarten muß und das kann man bei nur einer Zuweisung.

 Threadname sagt es aber anders:
 "AVR/C: Bits in Register in einem Schritt löschen und andere setzen"

Peter D. schrieb:
> Ich bevorzuge allerdings die Vorrangregeln:
  TCCR2B = TCCR2B & ~(1<<WGM22 | 1<<CS21) | 1<<CS22 | 1<<CS20;

 So ist es OK.

: Bearbeitet durch User
von Patrick S. (psar04)


Lesenswert?

Marc V. schrieb:
> Peter D. schrieb:
>> Marc V. schrieb:
>>> aber der TO wollte wissen ob das irgendwie in einem
>>>  Schritt (ein Befehl) zu machen ist.
>>
>> Nö, er wollte wissen, ob man den Seiteneffekt Synchronisierung nur
>> einmal abwarten muß und das kann man bei nur einer Zuweisung.
>
>  Threadname sagt es aber anders:
>  "AVR/C: Bits in Register in einem Schritt löschen und andere setzen"

Ihr habt beide irgendwie Recht. Mir ging es darum die entsprechenden 
Bits in einem Schritt auf die richtigen Werte zu (über)schreiben, um die 
Synchronisierung (ASSR-Register prüfen) zu sparen. Vielleicht war das 
nicht ganz klar formuliert, aber ich wollte halt nur einen 
Schreibvorgang auf das TCCR2B Register durchführen.

von Oliver S. (oliverso)


Lesenswert?

Patrick S. schrieb:
> aber ich wollte halt nur einen
> Schreibvorgang auf das TCCR2B Register durchführen.

Dann mach das doch einfach. Die FOC-Bits wirst du an mit Sicherheit 
grenzender Wahrscheinlichkeit nicht benutzen, und von alleine ändern die 
sich auch nicht.

Und damit ist
1
TCCR2B = (1<<CS22) | (1<<CS20);

die Lösung deines Problems.

Oliver

von Patrick S. (psar04)


Lesenswert?

Oliver S. schrieb:
> Und damit istTCCR2B = (1<<CS22) | (1<<CS20);
> die Lösung deines Problems.

Nein! Es kann nämlich sein, dass WGM22 bzw CS21 zuvor auf 1 gesetzt 
waren. Aus diesem Grund mache ich das wie oben geschrieben und damit ist 
die Sache erledigt.

von Oliver S. (oliverso)


Lesenswert?

Patrick S. schrieb:
> Nein! Es kann nämlich sein, dass WGM22 bzw CS21 zuvor auf 1 gesetzt
> waren. Aus diesem Grund mache ich das wie oben geschrieben und damit ist
> die Sache erledigt.

Na ja, du kannst machen, was du willst. Sinnvoll ist es in diesem Fall 
nicht.

Patrick S. schrieb:
> ich möchte gerne auf einem ATmega 328p im Register TCCR2B die Bits CS22
> und CS20 setzen und die Bits CS21 und WGM22 löschen.

Oliver

von Patrick S. (psar04)


Lesenswert?

Oliver S. schrieb:
> Na ja, du kannst machen, was du willst. Sinnvoll ist es in diesem Fall
> nicht.

Selbstverständlich ist das sinnvoll. CS20 = CS21 = CS22 = 1 haben 
natürlich eine ganz andere Bedeutung als CS20 = CS22 = 1, CS21 = 0
Analog für die WGM Bits.

von Oliver S. (oliverso)


Lesenswert?

Natürlich.

Oliver S. schrieb:
> TCCR2B = (1<<CS22) | (1<<CS20);

Das ist eine einfache Zuweisung, danach sind alle Bits in dem Register 
so, wie du sie habe willst. CS22 und CS20 sind 1, alle andern Bits in 
dem Register sind 0.  Die FOC-Bits werden dabei zwar mit 0 
überschrieben, das stört aber nicht.

Oliver

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Oliver S. schrieb:
> Das ist eine einfache Zuweisung, danach sind alle Bits in dem Register
> so, wie du sie habe willst. CS22 und CS20 sind 1, alle andern Bits in
> dem Register sind 0.  Die FOC-Bits werden dabei zwar mit 0
> überschrieben, das stört aber nicht.

 Das habe ich auch so gedacht, als ich angefangen habe. Es ist nicht
 nur eine schlechte Angewohnheit, es ist sogar eine furchtbare.
 Anzunehmen, dass ein bestimmter Register einen bestimmten Wert hat
 oder das Überschreiben gewisser bits "nicht stört" ist ganz einfach
 dumm, ich kenne kein anderes Wort dafür.

von Draco (Gast)


Lesenswert?

Marc V. schrieb:
> Das ist nur eine Zuweisung in C, aber mindestens 2 in ASM.

Dann macht man es halt über eine temporäre Variable um sicherzugehen:
1
byte newRegister = (TCCR2B & ~((1<<WGM22)|(1<<CS21))) | ((1<<CS22|(1<<CS20));
2
TCCR2B = newRegister;

Das bringt zwar ein wenig Overheat mit sich (ne Variable und max zwei 
Zuweisungen) Aber TCCR2B wird definitiv nur einmal beschrieben.

von Thomas E. (picalic)


Lesenswert?

Draco schrieb:
> ein wenig Overheat

Mit guter Kühlung klappt das schon... ;)

von Rolf M. (rmagnus)


Lesenswert?

Marc V. schrieb:
> Peter D. schrieb:
>> TCCR2B = (TCCR2B & ~((1<<WGM22)|(1<<CS21))) | ((1<<CS22|(1<<CS20));
>
>  Das ist nur eine Zuweisung in C, aber mindestens 2 in ASM.

TCCR2B muss in dieser Zeile genau einmal gelesen und einmal geschrieben 
werden.

von Oliver S. (oliverso)


Lesenswert?

Marc V. schrieb:
>  Das habe ich auch so gedacht, als ich angefangen habe. Es ist nicht
>  nur eine schlechte Angewohnheit, es ist sogar eine furchtbare.
>  Anzunehmen, dass ein bestimmter Register einen bestimmten Wert hat
>  oder das Überschreiben gewisser bits "nicht stört" ist ganz einfach
>  dumm, ich kenne kein anderes Wort dafür.

Nun ja, ich bezeichne es als dumm, nicht ins Datenblatt zu schauen, und 
eine "one size fürs all" Lösung zu verwesen, die unnötig ist. Gerade bei 
diesen Timerkonfigurationsregistern ist es sehr sinnvoll, GENAU das 
hineinzuschreiben, was hinein soll, und sonst gar nichts.

Das Register setzt den Takt und die Betriebsart des Timers. Da gibt es 
keine "vorher" gesetzten Bits. Da gibt es nur genau einen einzigen Wert, 
der da in einem Rutsch hineingeschrieben wird. Und weil das so ist, ist 
es guter Programmierstil, das auch genauso ins Programm zu schreiben.

Die FOC-Bits sind extra dafür gemacht, folgenlos mit 0 überschreiben zu 
werden.

Es gibt andere Register, da will man einzelne Bits setzen. Die 
Fragestellung war aber spezifisch für TCCR2B beim Mega328p, und dafür 
ist die schnellste, sicherste und einfachste Lösung, den gewünschten 
Wert dort einfach hineinzuschreiben.

Oliver

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Rolf M. schrieb:
> TCCR2B muss in dieser Zeile genau einmal gelesen und einmal geschrieben
> werden.

 Wie geht das denn ?
 Auf einmal AND 2 bits, OR 2 bits und die übrigen 4 bits unverändert -
 das geht nie und nimmer in ASM.
 Was in dieser Zeile steht, ist uninteressant - deswegen gibt es auch
 höhere Programmiersprachen - wie diese Zeile aber übersetzt wird...

von Rolf M. (rmagnus)


Lesenswert?

Marc V. schrieb:
> Rolf M. schrieb:
>> TCCR2B muss in dieser Zeile genau einmal gelesen und einmal geschrieben
>> werden.
>
>  Wie geht das denn ?

Ich sehe da kein Problem.

>  Auf einmal AND 2 bits, OR 2 bits und die übrigen 4 bits unverändert -
>  das geht nie und nimmer in ASM.

Ich hab nicht gesagt, dass er alles in einem Schritt berechnet, 
lediglich, dass TCCR2B genau einmal gelesen und einmal geschrieben wird.

>  Was in dieser Zeile steht, ist uninteressant - deswegen gibt es auch
>  höhere Programmiersprachen - wie diese Zeile aber übersetzt wird...

Das gilt aber nicht für Variablen, die volatile sind, was auf alle 
I/O-Register zutrifft. Bei denen müssen die Zugriffe physikalisch so 
stattfinden, wie sie im Code stehen.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Rolf M. schrieb:
> Ich hab nicht gesagt, dass er alles in einem Schritt berechnet,
> lediglich, dass TCCR2B genau einmal gelesen und einmal geschrieben wird.

 LOL.
 Und zwei Befehle dazwischen.

 Auch bei folgendem Unfug wird TCCR2B genau einmal gelesen und einmal
 geschrieben:
1
 TCCR2B = ((TCCR2B & (TCCR2B << 4)) % 7) * 4;
 Wieviele Schritte dazwischen sind, ist eine andere Frage.

von Rolf M. (rmagnus)


Lesenswert?

Marc V. schrieb:
> Rolf M. schrieb:
>> Ich hab nicht gesagt, dass er alles in einem Schritt berechnet,
>> lediglich, dass TCCR2B genau einmal gelesen und einmal geschrieben wird.
>
>  LOL.
>  Und zwei Befehle dazwischen.

Was ist daran "LOL"? Natürlich kann er das nicht in einem Schritt 
berechnen. Das hat aber doch mit den Zugriffen auf das Register erstmal 
nichts zu tun.

>  Auch bei folgendem Unfug wird TCCR2B genau einmal gelesen und einmal
>  geschrieben: TCCR2B = ((TCCR2B & (TCCR2B << 4)) % 7) * 4;

Nein. Es wird zweimal gelesen, da du hingeschrieben hast, dass es 
zweimal gelesen werden soll.

>  Wieviele Schritte dazwischen sind, ist eine andere Frage.

Richtig.

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.