AVR/C: Bits in Register in einem Schritt löschen und andere setzen

OP #4528449
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
Gast #4528454
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
OP #4528467
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.
Gast #4528516
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.
OP #4528517
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.
Gast #4528539
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
OP #4528628
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
OP #4528642
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. 
;)
Gast #4528668
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 ;)
OP #4528849
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
Gast #4528893
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. :))
Gast #4528899
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.
OP #4528988
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.
Gast #4529009
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.
Gast #4529014
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.
OP #4529015
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. :)
Gast #4529017
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...
#4529155
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
Gast #4529163
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..
(Firma: Vescomp) #4529174
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.
#4529185
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.
(Firma: Vescomp) #4529196
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.
(Firma: Vescomp) #4529219
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.
#4529269
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;
(Firma: Vescomp) #4529349
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.
OP #4529577
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.
#4529766
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
(Firma: Vescomp) #4530414
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.
Gast #4530424
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.
#4530559
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
(Firma: Vescomp) #4531316
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...
#4531324
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.
(Firma: Vescomp) #4531338
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.
#4531424
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.

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