Hallo zusammen,
ich habe eine Frage zur folgenden Schreibweise
wann nehme ich z.B.
ADCSRA = (1<<ADPS1) | (1<<ADPS0);
oder diese Schreibweise
ADCSRA |= (1<<ADEN);
wo ist der Unterschied?
Viele Grüße
|
Anzeige
|
Bits in Register setzten (Schreibweise)Hallo zusammen, ich habe eine Frage zur folgenden Schreibweise wann nehme ich z.B. ADCSRA = (1<<ADPS1) | (1<<ADPS0); oder diese Schreibweise ADCSRA |= (1<<ADEN); wo ist der Unterschied? Viele Grüße
Die zweite Zeile heißt eigentlich in langer Schreibweise:
Siehe Bitmanipulation
Gast
#7336179
Schlecht erklärt.
Damit beschreibst du das ganze Register mit den (wohlgemerkt:) 8 Bit die du dir zusammengereimt hast. Du änderst (womöglich, abhängig von der Vorgeschichte) den gesamten Registerinhalt.
Damit liest du das Register, ver-oderst ein Bit in den gelesenen Bit-Satz und schreibst den gesamten Registerinhalt wieder zurück. Damit änderst du effektiv nur die Bits im Register die du mit der Ver-Oderung angesprochen hast.
Gast
#7336192
Die Operatoren werden in jedem C und C++ Grundlagenbuch oder Tutorial beschreiben. Ein solches, sollte man wenigstens ein mal überflogen haben! Und bitte nicht mit eine Airbus
Blöd nur das die bei µC gerne mal unvollständig sind. Denn
kann je nach µC mal ein Read-Modify-Write (z.B. ARM) oder auch nicht (AVR, 8051 je nach Register/Zieladresse) sein. Einige µC kennen nämlich Befehle zum Setzen/Löschen einzelner Bits. Das beschreibt Dir ein Grundlagenbuch eher nicht. Das hat durchaus Relevanz in der Praxis wenn Interrupts im Spiel sind - das Read-Modify-Write ist unterbrechbar.
Gast
#7338050
Drum sind solche Compound Operatoren auch seit C++23(?) auch deprecated, wenn sie sich auf volatile Daten beziehen. Allerdings ist diese Tatsache kein Grund, Ein Grundlagenbuch für überflüssig zu erklären, wie du es mit deinem Beitrag versuchst.
Der Compiler setzt diese Befehle ein! Ob mit, oder ohne Buch.
Gast
#7338125
In der Überschrift sagst Du Register. Was da bei |= passiert ist völlig unklar und abhängig von Prozessor, Register und Compiler. Meist passiert das gleiche als wäre es eine variable. Es kann aber beliebige weitere Effekte haben.
Keine Sekunde. Die Frage war auch nicht nach Atomar oder Read/Modify/Write. Die ERSTE Antwort vom Lothar war korrekt und umfänglich! Da hätte man einfach aufhören können!
Nö.
Gast
#7338336
Du unterstellst, das "Register" keine Rolle spielt. Das kann sein, muss aber nicht.
Das stimmt so nicht. Denn wenn das Bit schon auf 1 war, dann ändert sich durch den |= Befehl gar nichts. Wenn man das Bit tatsächlich ändern also toggeln will, muss man den ^= Befehl nehmen. Wenn da statt änderst das Wort setzt stehen würde, dann wärs korrekt.
Gast
#7338390
Du solltest mal näher erklären und ein Beispiel bringen was bei welchem Register bei einem µC deiner Wahl unvorhergesehenes passieren wird. Ich programmiere nur AVRs und mir ist solches noch nicht begegnet.
Gast
#7338414
Das wär doch wirklich was für inline-assembler, eine zeile "Set Bit in Register" und gut ist. In etwa:
Gast
#7338729
Beide haben den selbe "Konstruktionsfehler", das Zusammenwurschteln einer Konstanten über Präprozessor-shiftoperationen. Die Shiftoperationen finden nicht wirklich auf dem Zielprozessor statt, den interessiert nur die resultierende Konstante; also gleich (Annahme ADEN = 2):
Oder wenn man "Magic-Numbers vermeiden will und dafür eine constant ADEN_MASK definiert.
Oder mit redundzlosen schreibweise für den Fall das ein Register gleichzeitig als Ziel und Quell-register benutzt wird:
Gast
#7338748
Port, zumindest bei alten Pics. Setzen war ob 1 oder 0 bei Output, lesen war nicht der letzte wert sondern der aktuelle Pin Zustand. Bei Toshiba gab es Register, die nicht rücklesbar waren. RMW führte da ins Chaos. Bei Interrupflagtregistern führt das regelmäßig dazu, dass grad auftretende Interrupts gelöscht werden und unerkannt bleiben. So selten, dass meist ein Defekt vermutet wird In einigen der Fälle reicht es, die Bits einzeln zu setzen/löschen, da der Prozessor dafur eigene Befehle hat. In anderen muss man mit Shadowregistern arbeiten (keine Ahnung, ob der Begriff OK ist. Meint gewöhnliche variablen, die den istwert speichern, manipulieren und dann zuweisen)
Gast
#7338769
µC's in FPGA's wären auch so ein Thema, da hat ich mal ein Design, das beim Schreiben auf ein Readonly-register einen Fehlercode auf den Daten-Bus legte, das ein stupider RMW-Programmiere stur als Bitmaske für ein WO-Command-Register verwendete. Führte natürlich zu ungewollten Effekten. War auch alles in der FPGA-Beschreibung dokumentiert, aber manche Programmierer sind sich zu fein darin zu lesen. Die denken sich, kennste einen, kennste alles ...
Gast
#7338888
Ich muß das mal ein bissel auseinandernehmen. Also ich schätze mal, dein Register enthält ein Feld aus 2 Bits, wo irgend ein Wert 0..3 eingetragen werden kann und du hast versucht, das auseinanderzunehmen, damit du (1<<... schreiben kannst. Kannst du machen, aber leserlicher ist es, wenn du (in diesem Falle) (3<<ADPS) schreibst. Vorausgesetzt, daß dein Feld so heißt und du dort eine 3 drin haben willst. Und das Ganze ist insgesamt eine normale Zuweisung: ADCSRA = irgend eine Konstante; Dabei werden eben alle Bits des Registers gesetzt. Solche Schreibweisen wie Ottokar += Emil; oder ähnliche sind eigentlch nur Kurzschreibweisen für Ottokar = Ottokar+Emil; und sind nur auf dem Mist der Faulheit von C Programmierern gewachsen. Man kann sich daran gewöhnen, sollte aber dabei nicht vergessen, was dahintersteckt, nämlich eine Addition (oder andere Operation je nach Zeichen vor dem =) zu dem Inhalt der Zielvariablen. Ganz generell gilt, daß die Schreibweise (1<<Bezeichner) eben deshalb verwendet wird, weil man dabei die Bitnummer im Ausdruck drinhat, was deutlich besser lesbar ist als irgend ein Dezimal- oder Hex-Ausdruck. W.S.
Gast
#7338928
Ist es nicht! (vielleicht für dich, (nur für dich?)) Ich bevorzuge eher diese Schreibweise: ADCSRA = (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); Auch: ADCSRA = _BV(ADPS1) | _BV(ADPS0); // _BV(ADPS2) | Was allerdings aufs gleiche raus kommt... oder eben Masken: constexpr byte adcPrescalerDIV8 {_BV(ADPS1) | _BV(ADPS0)}; // _BV(ADPS2) | ADCSRA = adcPrescalerDIV8;
Gast
#7338936
Nö. Bei dezimal mag das stimmen, aber bei Hex sollte doch klar sein das bei 0x05 das bit ganz rechts und das dritte von rechts gesetzt. Und bei 0xFF ist alles gesetzt. und bei 0x04 nur das dritte. Ansonsten neben dem Datenblatt des Prozessors mal das Hexedezimalsystem lernen. Und wenn es garnicht in den Schädel will, dann einen taschenrechner mit Hex/dec/bin Anzeige verwenden. Auch da finden sich die Hex-Zahlen. Hex ist deutlich besser lesbar als das Rumgeshifte, insbesonders wenn mehr als ein bit besetzt wird.
Dann kommt auch der Compiler nicht auf die dumme idee, das Ganze erst berechnen zu wollen statt gleich das richtige Literal zu verwenden. Und dann vergiss mal in 'C' ein Zeichen vom lustigen Buchstabentanz und hab dann trotzdem einen korrekten syntax, aber andere Berechnungsreihenfolge.
Gast
#7338937
Danke für die Ausführungen! Das Verhalten bei einigen speziellen Registern sind Sonderfälle; da muss man schon wissen, was man tun will. Und sie sind üblicherweise dokumentiert.
Undokumentiert? Bei AVRs gibt es auch ein paar Sonderfälle, die sind aber klar im DB benannt. Und funktionieren mit den oben diskutierten Befehlen mit "REG |= (1<<X)" mit dem WINAVR. Wie da eine Fehlbehandlung aussieht, die ins Chaos führt, wüsste ich jetzt nicht.
Auch dir besten Dank. Aber wie du sagst: es ist dokumentiert und nicht irgend ein seltsamer Nebeneffekt. Da habe ich dann wenig Gnade, eher Schadenfreude ... 😀
Gast
#7338951
Hardwarenaher Programmierer schrieb:
Also, beim oberen Befehl weiß und sehe ich sofort, was gesetzt wird. Und ich würde immer "|=" verwenden, außer wenn die anderen Null sein müssen. Zudem muss ich nicht mühsam die Bits aus dem DB in einen HEX-Wert umzurechnen. Und den Kommentar "Rest: '0' kannst du immer dazu schreiben, der passt oben auch. Beim unteren muss der Kommentar nicht mit dem Hex-Wert übereinstimmen. Du änderst was am Wert und vergisst den Kommentar anzupassen. Zumindest mir würde das passieren.
Ich schätze mal, der berechnet das zur Compilezeit. Wenn ja, wo ist dann der Unterschied und wieso ist es eine dumme Idee? Hardwarenaher Programmierer schrieb:
Das berechnet nicht mal der Compiler sondern schon vorher der Präprozessor, der auch die Makros durch Quelltext ersetzt. Einem hardwarenahen Programmierer sollte das aber bekannt sein.
Gast
#7339052
... zum anfeuern der Viellaberer und Makro Hasser!
Der Präprozessor BERECHNET rein GAR NICHTS, der macht nur Textersetzung! Berechnen tut der Compiler und erkennt, daß es eine Konstante ist, und dementsprechend nicht zur Laufzeit berechnet werden muss.
Gast
#7339063
egal was jetzt genau der Präprozessor, der Compiler oder der Optimizer macht. Am Ende passiert das alles in dem selbem Programm, nämlich dem avr-gcc. Wie das intern modularisiert ist, ist doch eigentlich egal.
Gast
#7339078
Nein, solange manche module/Optimierungen erst angeschaltet werden (-O0,-O2,-Os) müssen. Und vielleicht wollte ja der Programmer diese umständliche Konstantenberechnung zur Laufzeit, weil er so "Stress erzeugt". Manche Sicherheitslücke beruht auf "der CPU Stress machen": https://www.heise.de/hintergrund/Weshalb-Rowhammer-Angriffe-auf-den-Arbeitsspeicher-funktionieren-koennen-4439749.html
Du vergleichst Äpfel mit Birnen. Im ersten Beispiel wird ADCSRA komplett überschrieben, Einsen und Nullen, alle Bits, wobei dabei 2 Bits gesetzt werden, alle anderen werden zurückgesetzt. Im zweiten Beispiel setzt du nur ein Bit und lässt die anderen wie sie sind. Du könntest das erste Beispiel auch so formulieren, dass nur die beiden Bits gesetzt werden: ADCSRA |= (1<<ADPS1) | (1<<ADPS0); lang: ADCSRA = ADCSRA | (1<<ADPS1) | (1<<ADPS0); Oder das zweite Beispiel auch so dass es direkt zugwiesen wird, und das komplette Register beschrieben wird.
Gruß M.
Beitrag #7339156 wurde von einem Moderator gelöscht.
Gast
#7339453
Also, mal ohne dem nachzugehen, von welchem Chip das 'ADPS' herkommt und was es dort bewirkt, so vermutet man ja doch, daß das ein dreibittiges Feld ist, was die Werte 0..7 aufnehmen kann. Und du willst sowas in einzeln hingeschriebene Bits aufdröseln? Dein 'ist es nicht' kann ich nicht nachvollziehen. Was du schreibst, ist unleserlich, denn man müßte gedanklich erst besagte Bits zusammensetzen, um die gewünschte Zahl zu erkennen. W.S.
Gast
#7339499
Der TO fragt quasi nach dem Unterschied von = und |=. Er ist also Anfänger. Nur schränkt er das explizit auf Register ein. Da sollte man schon Mal darauf hinweisen dürfen. Ein Anfänger entdeckt sowas sonst nicht in Doku sondern auf die harte Tour.
Gast
#7339620
Er fragt, das ist der Punkt. Er versucht also sich selbst eine meinung darüber zu bilden, welche (Schreib-)Weise am Besten für ihn passt. Für einen solchen eigeninitiativen Lerner ist es IMHO am besten, viele mögliche Varianten vorzustellen und dem Frager selbst die Entscheidung überlassen. Das verlangt natürlich, das der Antworter bereit und fähig ist, "über seinen eigenen Schatten zu springen" und eben nicht seine jahrzehntelange Routine als das einzig Wahre zu verkaufen.
Gast
#7339632
Ich hab doch genau zum Stil gar nichts gesagt. Ich hab auf mögliche Seiteneffekt bei Registern hingewiesen, weil der TO explizit nach Registern fragt.
Gast
#7339647
Ja zum Stil hätte man wohl eher dieses Zitat zu dem Gekritzel mit dem "Kleiner-als Zeichen" voranstellen sollen:
Und das ist nicht von "A. S.", (falls das irgend wen interessiert).
Uwe K. erwähnt in seinem Post mit keinem Wort irgendein Register. Er fragt auch nicht nach dem Schiebeoperator (1<<xx) und ob das Schieben einer Zahl (z.B. für einen Multiplexer oder Prescaler) nicht auch sinnvoll sein könnte. Diese Ausdrücke links und rechts der Operatoren können für die Frage also durch die Buchstaben a und b ersetzt werden. Uwe K. fragt letztlich also nur nach dem Unterschied zwischen
und
Und das findet sich nun wirklich in jedem C-Anfänger-Buch ziemlich weit vorne.
Gast
#7339661
Doch tut er, vielleicht mal die Suchfunktion benutzen, solange noch der Schlaf in den Augen hockt?!
Nö fragt er nicht, bei ihm stehen rechts zwei operanden und nicht einer. und dann kann man schon fragen: Wo der Unterschied zwischen a = b op c; und a op = c; besteht insbesonders wenn man die Möglichkeit b ≡ a impliziert. Die Frage steht in seinem Topic, nicht in den Beispielen. Und im Topic steht "Bit's in Register setzen"! Also muß man sich hier (Mikrocontroller in C programmieren) schon mit Shift-operatoren u.ä. auseinandersetzen.
Gast
#7339832
Tatsächlich, 81 Treffer. Mitten im Wald, sieht keinen Baum. Blöd auch... Aber ich neige stark zur Vermutung, dass ich trotzdem Recht habe und es nicht um spezielle Eigenheiten beim Schreibvorgang auf ein Register geht.
Gast
#7340730
Deine Neigungen sein Dir unbenommen, auch wenn sie völlig aus der Spur führen. Auch in der Programmierung ist die Schreibweise ist schon sehr speziell aka individuell. Der eine erkennt Bitposition nach kurzen Blick auf die Hexadezimalnotation oder liest den Kommentar am Zeilenende, und der andere quält halt seine Umwelt mit irrealen Sonderzeichenkonstrukten. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|