Hallo! Habe eine kurze Frage zum Beschreiben von Registern. Das gesamte Register zu beschreiben (0b01010101) oder einzelne Bits des Registers zu setzen bzw. löschen ist ja kein Problem. Wie kann man aber auf einfachste Weise mehrere Flags auf einmal bearbeiten, ohne das gesamte Register zu beschreiben. Z.B.: R = 0b11001010; Es sollen jetzt die letzten 4 Werte auf 1100 gesetzt werden. Dabei sollen die 4 ersten Werte nicht beschrieben werden. Am soll dann gelten: R == 0b11001100; Wie löst ihr dieses Problem? :) gruß NN
NN schrieb: > oder einzelne Bits des Registers zu > setzen bzw. löschen ist ja kein Problem. Der Vorteil der |= bzw &= Schreibweise besteht darin, dass das was mit einem Bit geht auch mit mehreren Bits in einem Aufwasch geht. > Es sollen jetzt die letzten 4 Werte auf 1100 gesetzt werden. Dabei > sollen die 4 ersten Werte nicht beschrieben werden. Beschreiben wirst du sie müssen. Aber wenn du wieder dasselbe draufschreibst, was eh schon dort steht, dann ändert sich ja nichts. > Am soll dann gelten: > > R == 0b11001100; > > > Wie löst ihr dieses Problem? :) Erst mal die beswussten 4 Bits sicher auf 0 setzen R = ( R & 0b11110000 ) und dann das gewünschte Muster einodern R = ( R & 0b11110000 ) | 0b00001100; Wenn dir klar geworden ist, dass du eine Und-Operation (&) wie ein 'Sieb' benutzen kannst, durch das nur die von dir genehmigten Bits durchkommen und alle anderen auf 0 gesetzt werden, während eine Oder-Operation (|) wie ein Stempel benutzt wird, der bestimmte Bits auf jeden Fall auf 1 setzt, dann ist deine gewünschte Operation einfach nur eine Kombination aus beidem.
NN schrieb: > Es sollen jetzt die letzten 4 Werte auf 1100 gesetzt werden. Dabei > sollen die 4 ersten Werte nicht beschrieben werden. Wenn du das wörtlich nimmst, ist das bei AVR nicht möglich. Die vorderen 4 Bits werden trotzdem beschrieben, allerdings mit ihrem ursprünglichen Wert. Genauer, mit dem Wert, den sie ein paar Takte vorher hatten. Falls sich der Wert der vorderen Bits zwischenzeitlich geändert hat, geht diese Änderung verloren. Diese Erbsenzählerei ist für dich wahrscheinlich gar nicht wichtig – außer du arbeitest mit Interrupt-Routinen, die die besagten vorderen Bits jederzeit ändern können. Falls dem so sein sollte, helfen dir die Assembler-Befehle SBR und CBR, das heißt, die zu ändernden Bits müssen einzeln "angefasst" werden. Falls du C verwendest, kannst du in der Regel davon ausgehen, dass die Operatoren |= und &= in SBR und CBR übersetzt werden, wenn du damit immer nur ein Bit manipulierst. Eine absolute Garantie dafür gibt es allerdings nicht, insbesondre dann, wenn du die Optimierung des Compilers aktiviert hast.
Stop! ^^ Ich muss es anders formulieren: Nehmen wir mal den Timer/Counter2 register. Ich beschreibe das Register bei der Initialisierung:
1 | TCCR2 = ((1<<WGM21) | (0<<WGM20)) | ((0<<COM21) | (1<<COM20)) | ((0<<CS22) | (0<<CS21) | (0<<CS20)); |
(Das shiften der Nuller bringt ja gar nix. Hab ich jetzt nur der Lesbarkeit halber eingefügt). Jetzt starte ich den Timer mit:
1 | TCCR2 |= ((1<<CS22) | (0<<CS21) | (0<<CS20)); |
Das geht gut, weil da vorher Nuller drin standen. Irgendwo in nen IRS möchte ich den Timer nochmals modifizieren. Z.B:
1 | TCCR2 |= ((0<<CS22) | (1<<CS21) | (0<<CS20)); |
Das geht nun total schief.... Die einzige Möglichkeit, die ich sehe wäre:
1 | TCCR2 &= ~((1<<CS22) | (1<<CS21) | (1<<CS20)); //flags erstmal auf 0 setzen |
2 | TCCR2 |= ((0<<CS22) | (1<<CS21) | (0<<CS20)); //dann beschreiben |
Sowas möchte ich vermeiden, weil da keiner mehr durchblickt:
1 | TCCR2 &= 0b11110000; |
Oder habt ihr bessere Vorschläge? ^^
NN schrieb: > Das geht nun total schief.... logisch > Die einzige Möglichkeit, die ich sehe wäre: > >
1 | > TCCR2 &= ~((1<<CS22) | (1<<CS21) | (1<<CS20)); //flags erstmal auf 0 |
2 | > setzen |
3 | > TCCR2 |= ((0<<CS22) | (1<<CS21) | (0<<CS20)); //dann beschreiben |
4 | >
|
Was stört dich daran? > > Sowas möchte ich vermeiden, weil da keiner mehr durchblickt: >
1 | > TCCR2 &= 0b11110000; |
2 | >
|
Das war sowieso vorausgesetzt, aber du hast nun mal diese Schreibweise in deinem Eröffnungsposting gewählt.
NN schrieb: > Das geht nun total schief.... Weil, wie du richtig erkannt hast, NN schrieb: > (Das shiften der Nuller bringt ja gar nix. Hab ich jetzt nur der > Lesbarkeit halber eingefügt). NN schrieb: > Die einzige Möglichkeit, die ich sehe wäre: > TCCR2 &= ~((1<<CS22) | (1<<CS21) | (1<<CS20)); //flags erstmal auf 0 setzen > TCCR2 |= ((0<<CS22) | (1<<CS21) | (0<<CS20)); //dann beschreiben So ist es. Alternativ leg dir zwei Variablen mit den beiden verschiedenen Registerinhalten an, die du dann komplett ins jeweilge Register schreibst. Etwa so:
1 | uint8_t TimerSetup_Takt_langsam = ((1<<WGM21) | (0<<WGM20)) | ((0<<COM21) | (1<<COM20)) | ((1<<CS22) | (0<<CS21) | (0<<CS20)); |
2 | uint8_t TimerSetup_Takt_schnell = ((1<<WGM21) | (0<<WGM20)) | ((0<<COM21) | (1<<COM20)) | ((0<<CS22) | (1<<CS21) | (0<<CS20)); |
3 | |
4 | TCCR2 = TimerSetup_Takt_langsam; |
5 | ...
|
6 | TCCR2 = TimerSetup_Takt_schnell; |
Oliver
Karl Heinz Buchegger schrieb: >> TCCR2 &= ~((1<<CS22) | (1<<CS21) | (1<<CS20)); //flags erstmal auf 0 >> setzen >> TCCR2 |= ((0<<CS22) | (1<<CS21) | (0<<CS20)); //dann beschreiben >> > Was stört dich daran? Nun ja. Erstens wollte ich wissen, ob das die einzige Möglichkeit ist oder ob ich vll grad irgendwo im Wald stehe. ^^ Zweitens nervt mich dieses auf 0 setzen... Hätte gern im Code selbst nen "Einzeiler". Etwa so:
1 | #define TCCR2_(x) TCCR2 &= ~((1<<CS22) | (1<<CS21) | (1<<CS20)); TCCR2 |= x;
|
2 | |
3 | TCCR2_(((0<<CS22) | (1<<CS21) | (0<<CS20))); |
Allerdings geht das so nicht, wegen dem vorderen Teil im define: TCCR2 &= ~((1<<CS22) | (1<<CS21) | (1<<CS20)) Das müsste auch irgendwie dynamisch an das jeweilige Flag angepasst werden. Sonst bräucht ich ja für jedes Flag nen define .... Das scheint mir aber nicht möglich. grmf ^^
NN schrieb: > Karl Heinz Buchegger schrieb: >>> TCCR2 &= ~((1<<CS22) | (1<<CS21) | (1<<CS20)); //flags erstmal auf 0 >>> setzen >>> TCCR2 |= ((0<<CS22) | (1<<CS21) | (0<<CS20)); //dann beschreiben >>> >> Was stört dich daran? > > Nun ja. Erstens wollte ich wissen, ob das die einzige Möglichkeit ist > oder ob ich vll grad irgendwo im Wald stehe. ^^ Zweitens nervt mich > dieses auf 0 setzen... Hätte gern im Code selbst nen "Einzeiler".
1 | #define TIMER2_CONFIG ((1<<WGM21) | (0<<WGM20)) | ((0<<COM21) | (1<<COM20))
|
2 | |
3 | |
4 | ....
|
5 | |
6 | TCCR2 = TIMER_2_CONFIG | (1<<CS22) | (0<<CS21) | (0<<CS20); |
und später
1 | TCCR2 = TIMER_2_CONFIG | (0<<CS22) | (1<<CS21) | (0<<CS20); |
NN schrieb: >
1 | > #define TCCR2_(x) TCCR2 &= ~((1<<CS22) | (1<<CS21) | (1<<CS20)); |
2 | > TCCR2 |= x; |
3 | >
|
4 | > TCCR2_(((0<<CS22) | (1<<CS21) | (0<<CS20))); |
5 | >
|
> > Allerdings geht das so nicht, wegen dem vorderen Teil im define: > TCCR2 &= ~((1<<CS22) | (1<<CS21) | (1<<CS20)) Ich seh jetzt das Problem nicht Nenn das Makro TCCR2_PRESCALER, sichere es noch gegen Fehlbenutzung ab und alles ist doch in Butter. Ein schönes Makro, mit dem man den Prescaler des Timers 2 wechseln kann. > werden. Sonst bräucht ich ja für jedes Flag nen define .... Übertreib mal nicht. Die 5 mal, die man sowas im Jahr braucht, kann man das auch ausschreiben.
NN schrieb: > Nehmen wir mal den Timer/Counter2 register. Ich beschreibe das Register > bei der Initialisierung: >
1 | > TCCR2 = ((1<<WGM21) | (0<<WGM20)) | ((0<<COM21) | (1<<COM20)) | |
2 | > ((0<<CS22) | (0<<CS21) | (0<<CS20)); |
3 | >
|
Das heißt, der Registerinhalt hat einen Anteil, der immer konstant bleiben soll. Du kannst dir das zu Nutze machen. In C schaut das so aus:
1 | #define TCCR2_CONST (1<<WGM21 | 0<<WGM20 | 0<<COM21 | 1<<COM20)
|
Timer starten dann so:
1 | TCCR2= TCCR2_CONST | 1<<CS22 | 0<<CS21 | 0<<CS20; |
Timer modifizieren:
1 | TCCR2= TCCR2_CONST | 0<<CS22 | 1<<CS21 | 0<<CS20; |
Timer stoppen:
1 | TCCR2= TCCR2_CONST; |
EDIT: Karl Heinz war wieder schneller. :-)
Ok, dann weiß ich nun was geht und was nicht geht. Hat mir weitergeholfen. Vielen Dank für die angenehme Diskussion. :) Gruß NN
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.