Hallo, kann man bei einem Atmega168 einen PWM-Ausgang (z.B. OC0A) deaktivieren, indem man den besagten Pin einfach auf Eingang schaltet? Der Hintergrund ist folgender: es werden benutzt OC0A und OC0B. OC0B muss in jedem Fall den höchsten Wert erreichen können (d.h. der höchste Wert muss ein 100%iges Tastverhältnis haben). OC0A gibt so allerdings schon beim Wert 0 eine minimale PWM-Flanke aus, die gegebenenfalls stört. Deshalb soll OC0A für ein 0%iges Tastverhältnis irgendwie deaktiviert werden, während OC0B aber weiterlaufen muss.
Setz doch COM0A0 und COM0A1 im TCCR0A auf 0. Das trennt den Ausgangspin vom Timer ab.
15.9 Register description 15.9.1 TCCR0A – Timer/counter control register A Bits 7:6 – COM0A1:0: Compare match output A mode These bits control the Output Compare pin (OC0A) behavior. If one or both of the COM0A1:0 bits are set, the OC0A output overrides the normal port functionality of the I/O pin it is connected to. However, note that the Data Direction Register (DDR) bit corresponding to the OC0A pin must be set in order to enable the output driver. Table 15-2. Compare output mode, non-PWM mode. COM0A1 COM0A0 Description 0 0 Normal port operation, OC0A disconnected 0 1 Toggle OC0A on compare match 1 0 Clear OC0A on compare match 1 1 Set OC0A on compare match Auszug aus dem Datenblatt =>
1 | TCCR0A &= (1<<COM0A1)|(1<<COM0A0) |
Hallo, betreibe den Pin im 'Inverting Mode':
1 | Table 14-4. Compare Output Mode, Fast PWM Mode(1) |
2 | *COM0A1 COM0A0 Description* |
3 | 0 0 Normal port operation, OC0A disconnected. |
4 | 0 1 Reserved |
5 | 1 0 Clear OC0A on compare match, set OC0A at BOTTOM (non-inverting mode) |
6 | 1 1 Set OC0A on compare match, clear OC0A at BOTTOM (inverting mode) |
Im 'non-inverting mode' wird der Pin kurz auf 1 gesetzt und dann quasi gleich wieder auf 0. lg Mat
den Ausgang auf 0 setzen (PORTD &= ~(1<<PD6)) und übers Timerregister dem Timer den Zugriff auf den Pin wegnehmen -> im Register TCCR0A die Bits COM0A1 und COM0A0 löschen
Gerd frog: >kann man bei einem Atmega168 einen PWM-Ausgang (z.B. OC0A) deaktivieren, >indem man den besagten Pin einfach auf Eingang schaltet? Ja, das kann man machen und es funktioniert auch. MfG Paul
Paul Baumann schrieb: >>indem man den besagten Pin einfach auf Eingang schaltet? > > Ja, das kann man machen und es funktioniert auch. schaltet dann nicht der PullUp ständig?
Eduard Scheske schrieb: > Auszug aus dem Datenblatt =>TCCR0A &= (1<<COM0A1)|(1<<COM0A0) Du meinst wohl das:
1 | TCCR0A &= ~(1<<COM0A1)|(1<<COM0A0) |
Peter II schrieb: > Paul Baumann schrieb: >>>indem man den besagten Pin einfach auf Eingang schaltet? >> >> Ja, das kann man machen und es funktioniert auch. > > schaltet dann nicht der PullUp ständig? Soweit ich noch weis, muss man für den Pull-Up den Pin zuerst als Eingang haben, und dann auf das Ausgangsregister schreiben. Die "Zweitfunktion" geht doch nicht über das besagte Ausgangsregister (bin momentan noch zu sehr bei den STMs), oder?
:
Bearbeitet durch User
Danke für die vielen Antworten! Paul Baumann schrieb: > Gerd frog: >>kann man bei einem Atmega168 einen PWM-Ausgang (z.B. OC0A) deaktivieren, >>indem man den besagten Pin einfach auf Eingang schaltet? > > Ja, das kann man machen und es funktioniert auch. Das wäre jetzt erst mal das Mittel der Wahl. Peter II schrieb: >>>indem man den besagten Pin einfach auf Eingang schaltet? >> >> Ja, das kann man machen und es funktioniert auch. > > schaltet dann nicht der PullUp ständig? Wenn man die Pullups nicht extra einschaltet, sollte sich der auf Eingang geschaltete Pin bequem mit einem Pulldown-R auf GND ziehen lassen. Hauptsache, der PWM-Ausgang arbeitet dann nicht intern gegen den auf Eingang geschalteten Pin, sondern ist wirklich intern abgeklemmt.
Patrick B. schrieb: > Du meinst wohl das:TCCR0A &= ~(1<<COM0A1)|(1<<COM0A0) Wer sagt den, dass man immer 1 verwenden muss ? TCCR0A &= (0<<COM0A1)|(1<<COM0A0), geht auch und ist übersichtlicher. NOT ist oben leicht zu übersehen.
Patrick schrob: >Soweit ich noch weis, muss man für den Pull-Up den Pin zuerst als >Eingang haben, und dann auf das Ausgangsregister schreiben. Ich habe hier als Beispiel einen Attiny85. Der Ausgang OC0A kommt bei diesem aus dem Pin PB.0 Wenn ich jetzt im Programm sage: DDRB.0=0 dann habe ich diesen Pin auf Eingang geschaltet und damit kommt das Signal vom Timer nicht mehr "aus dem Pin" heraus, macht aber intern unverdrossen weiter. Um den Timer0 nun wieder mit der Außenwelt zu verbinden, schalte ich den Pin im Programm nur wieder auf Ausgang: DDRB.0=1 Den Ziehwiderstand lasse ich in Ruhe, weil ich nur einen Ausgang brauche und keinen Taster etc. dort dran hängt. MfG Paul
Wie das in "C" geschrieben wird, müßt ihr selber nachgucken, damit will ich mich nicht befassen. MfG Paul
Marc Vesely schrieb: > TCCR0A &= (0<<COM0A1)|(1<<COM0A0), geht auch und ist übersichtlicher. Falsch. Dein erster geklammerter Ausdruck schiebt eine 0 nach links. Was kommt da raus? Wieder 0. Also: Falscher Effekt, es werden alle Bits außer COM0A0 resetted. Das ist aber nicht das gewünschte. Aber auch das hier:
1 | > TCCR0A &= ~(1<<COM0A1)|(1<<COM0A0) |
ist Murks. Hier wird nur das COM0A1-Bit invertiert. Korrekt muss es heißen - und das ist auch die Lösung, um beide Bits zu löschen:
1 | TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)) |
Der kleine, aber feine Unterschied liegt in den Klammern. Warum? Das "~" bindet viel stärker als der Operator "|". Leute, lest erstmal ein C-Buch, bevor Ihr solchen Murks verbreitet.
:
Bearbeitet durch Moderator
Paul Baumann schrieb: > dann habe ich diesen Pin auf Eingang geschaltet und damit kommt das > Signal vom Timer nicht mehr "aus dem Pin" heraus, macht aber intern > unverdrossen weiter. WIe hast du das getestet? Mit einer LED am Pin oder sonst irgendwas, was ein wenig Strom braucht? Dann wundert mich das nicht weiter. Wenn du nur den Pin auf Eingang schaltest, dann PWM-t (wie nennt man das, wenn eine PWM den Pin bedient?) der Timer munter den Pullup Widerstand. Das hilft dir nichts. Du musst schon den Pin vom Timer abklemmen. Die COM Flags machen das.
:
Bearbeitet durch User
Danke für die Antworten! Frank M. schrieb: > TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)) -> Normal Port Operation, OC0A disconnected. Optimal!!! :O) Ich frage jetzt noch mal zur Sicherheit nach, die Schreibweise zum Löschen von COM0A1 und COM0A0 ist korrekt?
1 | TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)) |
GerdBreuer schrieb: > Danke für die Antworten! > > Frank M. schrieb: >> TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)) > > -> Normal Port Operation, OC0A disconnected. > > Optimal!!! :O) > > Ich frage jetzt noch mal zur Sicherheit nach, die Schreibweise zum > Löschen von COM0A1 und COM0A0 ist korrekt?TCCR0A &= > ~((1<<COM0A1)|(1<<COM0A0)) Richtig :-)
Danke für die Hilfe!!! Ich bin wirklich neidisch auf euer Können, Respekt!!!!!!
Karl Heinz fragte neugierig:
>WIe hast du das getestet?
Ich habe das mit der Schaltung und dem Programm im Anhang getestet.
Der Vollständigkeit halber:
Diese Mimik dient dazu, ein Fernsehgerät, welches beim
"harten Einschalten" in den Standby-Zustand geht, vom Sat-Empfänger
mit einschalten zu lassen. Dazu speist der Sat-Empfänger aus seiner
12 Volt Schiene das kleine Gerätchen, das sich seitlich neben dem
Fernseher
liegend befindet.
Hinweis: Der Fernseher hat auf seiner Scart-Buchse keinen Eingang für
eine Schaltspannung, das hätte die Sache einfach(er) gemacht.
MfG Paul
Paul Baumann schrieb: > Karl Heinz fragte neugierig: >>WIe hast du das getestet? > > Ich habe das mit der Schaltung und dem Programm im Anhang getestet. Ist aber trotzdem falsch. Das funktioniert hier 'zufällig', weil aus dem PNP kein Basisstrom fliessen kann. Weder in der Pin Stellung 'Pullup ein' noch in der Pin Stellung 'Pullup aus'. Bzw. das bischen Strom, welches bei einem auf Eingang geschaltetem Pin in den Pin fliessen kann, reicht nicht um den Transistor nennenswert zu schalten.
:
Bearbeitet durch User
Karl-Heinz schrub:
>Ist aber trotzdem falsch.
Das ist mir ziemlich gleichgültig, solange es funktioniert.
MfG Paul
Paul Baumann schrieb: > Karl-Heinz schrub: >>Ist aber trotzdem falsch. > > Das ist mir ziemlich gleichgültig, solange es funktioniert. Mir ist es aber nicht gleichgültig, wenn du anderen Leuten Unsinn erzählst. Nicht alle bauen ihre Hardware so, dass ein PNP geschaltet wird.
:
Bearbeitet durch User
Karl Heinz schrieb: >Das funktioniert hier 'zufällig', weil aus dem PNP kein Basisstrom >fliessen kann. Nein, das funktioniert nicht zufällig so, sondern weil ich es genau so haben wollte und es auch so gebaut habe. Paul
Paul Baumann schrieb: > Karl Heinz schrieb: >>Das funktioniert hier 'zufällig', weil aus dem PNP kein Basisstrom >>fliessen kann. > > Nein, das funktioniert nicht zufällig so, sondern weil ich es genau so > haben wollte und es auch so gebaut habe. > Schön, dann nimm aber auch zur Kenntnis, das das in genau deinem Fall so funtkioniert und keine allgemeine Lösung ist.
Karl Heinz schrieb: >Mir ist es aber nicht gleichgültig, wenn du anderen Leuten Unsinn >erzählst. Jetzt bleib aber mal schön gelöst! Auch wenn Du Kraft Deines Amtes den Beitrag gleich verschwinden lassen wirst: Es soll auch Sachen geben, die Du noch nicht gesehen hast, die aber nichtsdestotrotz funktionieren. Paul
Paul Baumann schrieb: > Karl Heinz schrieb: >>Mir ist es aber nicht gleichgültig, wenn du anderen Leuten Unsinn >>erzählst. > > Jetzt bleib aber mal schön gelöst! > > Auch wenn Du Kraft Deines Amtes den Beitrag gleich verschwinden lassen > wirst: Es soll auch Sachen geben, die Du noch nicht gesehen hast, die > aber > nichtsdestotrotz funktionieren. Nochmal: Das funktioniert in genau deinem speziellen Fall. Hier geht as aber nicht um den speziellen Fall, den der Herr Baumann gebaut hat. Hier ging es um eine allgemeine Frage und eine einwandfreie korrekte Lösung dazu. Wenn du das nicht verstehst, dann tut es mir leid. Korrekt wird deine Aussage dadurch immer noch nicht. Es funktioniert eben nicht in der Allgemeinheit. Steuere einen FET leistungslos damit an, und du fällst mit der Pullup-PWM auf die Schnauze.
:
Bearbeitet durch User
Frank M. schrieb: >> TCCR0A &= (0<<COM0A1)|(1<<COM0A0), geht auch und ist übersichtlicher. > > Falsch. Dein erster geklammerter Ausdruck schiebt eine 0 nach links. Was > kommt da raus? Wieder 0. Also: Falscher Effekt, es werden alle Bits > außer COM0A0 resetted. Das ist aber nicht das gewünschte. Was da rauskommt oder was da gewünscht wird, ist irrelevant. Ich habe nur das, was er geschrieben hat, anders geschrieben - meiner Meinung nach übersichtlicher. Ob damit Timer disconnected, connected oder in die Luft gesprengt wird - interessiert (in diesem Zusamenhang) überhaupt nicht. Frank M. schrieb: > Korrekt muss es heißen - und das ist auch die Lösung, um beide Bits zu > löschen: > TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)) > > Der kleine, aber feine Unterschied liegt in den Klammern. Warum? Das "~" Der kleine, aber feine Unterschied liegt in der Fähigkeit, sich aufs Wesentliche zu konzentrieren und zu versuchen, übersichtlichen Code zu schreiben. Warum nicht: TCCR0A &= (0<<COM0A1)|(0<<COM0A0) schreiben ? Etwas auf Logisch 1 zu setzen und dann mit Negation wieder auf Logisch 0 - wo ist da die Logik ? NOT wird für andere Zwecke verwendet (Toggle, vielleicht ? ), aber so wie du das hier großspurig vorgeführt hast - bestimmt nicht.
Marc Vesely schrieb: > NOT wird für andere Zwecke verwendet (Toggle, vielleicht ? ), aber > so wie du das hier großspurig vorgeführt hast - bestimmt nicht. Doch. Genau so wird das geschrieben, wenn man schon beide Bits anführt (was Sinn macht, weil man dann eine Fehlerquelle bei Änderungen an der PWM weniger hat). > Warum nicht: > TCCR0A &= (0<<COM0A1)|(0<<COM0A0) schreiben ? Weil das noch falscher ist. > Der kleine, aber feine Unterschied liegt in der Fähigkeit, sich aufs Wesentliche zu konzentrieren Das Wesentliche wäre gewesen, sich darauf zu konzentrieren, dass das Statement das du "korrigiert" hast, schon mal grundsätzlich falsch war. Eine andere Schreibweise ändert daran nichts. Der Fehler lag in vergessenen Klammern, aber das hat Frank schon angeführt.
:
Bearbeitet durch User
Marc Vesely schrieb: > Etwas auf Logisch 1 zu setzen und dann mit Negation wieder auf > Logisch 0 - wo ist da die Logik ? Es wird nicht logisch negiert, sondern binär.
1 | (0<<COM0A1)|(0<<COM0A0) |
2 | => 00000000 | 00000000 |
3 | => 00000000 |
4 | |
5 | ~((1<<COM0A1)|(1<<COM0A0)) |
6 | => ~(10000000 | 01000000) |
7 | => ~ 11000000 |
8 | => 00111111 |
Karl Heinz schrieb: > Doch. Genau so wird das geschrieben, wenn man schon beide Bits anführt > (was Sinn macht, weil man dann eine Fehlerquelle bei Änderungen an der > PWM weniger hat). >> Warum nicht: >> TCCR0A &= (0<<COM0A1)|(0<<COM0A0) schreiben ? > > Weil das noch falscher ist. Warum ? Weil ich sofort sehe, dass ich die beiden bits aufs Null gesetzt habe ? Ich gebe es auf.
Marc Vesely schrieb: > Karl Heinz schrieb: >> Doch. Genau so wird das geschrieben, wenn man schon beide Bits anführt >> (was Sinn macht, weil man dann eine Fehlerquelle bei Änderungen an der >> PWM weniger hat). > >>> Warum nicht: >>> TCCR0A &= (0<<COM0A1)|(0<<COM0A0) schreiben ? >> >> Weil das noch falscher ist. > > Warum ? > Weil ich sofort sehe, dass ich die beiden bits aufs Null gesetzt habe ? Nö. Das setzt keine Bits auf 0. Das ändert im TCCR0A Register überhaupt nichts. Man könnte es auch als eine 'No operation'-Operation bezeichnen. > > Ich gebe es auf. Ist auch besser so. Bitmanipulationen scheinen nicht deine Stärke zu sein.
:
Bearbeitet durch User
Karl Heinz schrieb: > Nö. Das setzt keine Bits auf 0. Das ändert im TCCR0A Register überhaupt > nichts doch, aber es setzt das gesamte Register auf 0. also nur ne andere Schreibweise für TCCR0A = 0;
Marc Vesely schrieb: > Karl Heinz schrieb: >> Doch. Genau so wird das geschrieben, wenn man schon beide Bits anführt >> (was Sinn macht, weil man dann eine Fehlerquelle bei Änderungen an der >> PWM weniger hat). > >>> Warum nicht: >>> TCCR0A &= (0<<COM0A1)|(0<<COM0A0) schreiben ? >> >> Weil das noch falscher ist. > > Warum ? > Weil ich sofort sehe, dass ich die beiden bits aufs Null gesetzt habe ? > > Ich gebe es auf. Was passiert, wenn in TCCR0A schon Bits gesetzt sind? Spiel das Beispiel mal durch, dann fällt es dir wie Schuppen aus den Haaren :-)
chris schrieb: > Karl Heinz schrieb: >> Nö. Das setzt keine Bits auf 0. Das ändert im TCCR0A Register überhaupt >> nichts > > doch, aber es setzt das gesamte Register auf 0. Auch nicht.
Karl Heinz schrieb: > Nö. Das setzt keine Bits auf 0. Das ändert im TCCR0A Register überhaupt > nichts. Ähm, es setzt alle Bits auf 0. ;-)
Stefan Ernst schrieb: > Es wird nicht logisch negiert, sondern binär. Wo habe ich geschrieben, dass es logisch negiert wird ?
Karl Heinz schrieb: > Auch nicht. doch :) da steht doch: TCCR0A &= 0; 1 & 0 = 0 0 & 0 = 0 --> alles wird zu 0
Stefan Ernst schrieb: > Karl Heinz schrieb: >> Nö. Das setzt keine Bits auf 0. Das ändert im TCCR0A Register überhaupt >> nichts. > > Ähm, es setzt alle Bits auf 0. ;-) Jetzt hab ich Tomaten auf den Augen gehabt. :-) Ja klar. Aber das ist ja nicht das, was man will.
chris schrieb: > Karl Heinz schrieb: >> Auch nicht. > > doch :) Entschuldige chris. Ich hatte Tomaten auf den Augen.
Karl Heinz schrieb: > Nö. Das setzt keine Bits auf 0. Das ändert im TCCR0A Register überhaupt > nichts. Karl Heinz schrieb: > Bitmanipulationen scheinen nicht deine Stärke zu sein. Sure. Zwei Nullen reingeschoben, nichts geändert ? TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)) ist richtig und funktioniert, aber: TCCR0A &= (0<<COM0A1)|(0<<COM0A0) ist falsch und geht nicht ? Es geht nicht um die Schreibweise, es geht darum, dass Register TCCR0A Werte mit AND zugewiesen werden. So und nicht anders.
Marc Vesely schrieb: > Stefan Ernst schrieb: >> Es wird nicht logisch negiert, sondern binär. > > Wo habe ich geschrieben, dass es logisch negiert wird ? Nur wenn man annimmt, dass du fälschlicherweise von einem logischen NOT ausgegangen bist, haben deine Aussagen wenigstens etwas Sinn. Du kannst dich so viel drehen und wenden wie du willst, Tatsache bleibt, dass dein Vorschlag lediglich nicht funktionierender Unsinn ist.
1 | TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)) |
Setzt zwei Bits in TCCR0A auf 0 und lässt die übrigen 6 wie sie sind.
1 | TCCR0A &= (0<<COM0A1)|(0<<COM0A0) |
Setzt alle 8 Bits in TCCR0A auf 0.
Marc Vesely schrieb: > Sure. > Zwei Nullen reingeschoben, nichts geändert ? > > TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)) ist richtig und funktioniert, genau > aber: > TCCR0A &= (0<<COM0A1)|(0<<COM0A0) ist falsch und geht nicht ? > Da hättest du genausogut auch
1 | TCCR0A = 0; |
schreiben können. Ist genau der gleiche Effekt. Nur ist das eben nicht die Lösung zur Problemstellung: Die beiden COM Bits in TCCR0A löschen und (sinnvollerweise) alle anderen Bits nicht zu verändern. Wie war das nochmal mit leicht verständlichem, übersichtlichem Code? Wenn du das komplette Register auf 0 setzen willst, dann schreib das auch so und verschleire es nicht durch Bitoperationen. Bei
1 | TCCR0A = 0; |
weiß man wenigstens, woran man ist.
:
Bearbeitet durch User
Karl Heinz schrieb: > auch so und verschleire es nicht durch Bitoperationen. > Bei >
1 | > TCCR0A = 0; |
2 | >
|
> weiß man wenigstens, woran man ist.
Wenn man allerdings das Eröffnungsposting liest, dann merkt man, dass er
sowohl OCR0A als auch OCR0B in Gebrauch hat. Setzt man einfach generell
die Bits auf 0, dann artet das in eine Abfrageorgie aus, weil man ja
dann nach dem löschen der COM Bits für A (bzw. B) wieder die Bits setzen
muss, die man tatsächlich benötigt (und man muss beten, dass das
kurzfristige 0 Setzen der WGM Bits keine Auswirkungen hat)
Löscht man hingegen nur die beiden tatsächlich zuständigen COM Bits bei
Bedarf, ist der Rest trivial.
:
Bearbeitet durch User
Karl Heinz schrieb: > Ist aber trotzdem falsch. > > Das funktioniert hier 'zufällig', weil aus dem PNP kein Basisstrom > fliessen kann. Weder in der Pin Stellung 'Pullup ein' noch in der Pin > Stellung 'Pullup aus'. Einspruch: Nach meinem Verständnis ist es doch genau das, was Paul Baumann wollte: Den Pin vom Timer0 trennen, indem er ihn auf "Eingang" stellt. Egal ob mit oder ohne Pullup ist der PNP immer gesperrt. Und das ist auch nicht zufällig (bis auf die Vernachlässigung der Restströme vom Port und Kollektor-Basis). Wenn er ihn dann wieder auf "Ausgang" schaltet, folgt er wieder dem Timer. Gruß Dietrich
Dietrich L. schrieb: > Karl Heinz schrieb: >> Ist aber trotzdem falsch. >> >> Das funktioniert hier 'zufällig', weil aus dem PNP kein Basisstrom >> fliessen kann. Weder in der Pin Stellung 'Pullup ein' noch in der Pin >> Stellung 'Pullup aus'. > > Einspruch: > Nach meinem Verständnis ist es doch genau das, was Paul Baumann wollte: > Den Pin vom Timer0 trennen, indem er ihn auf "Eingang" stellt. Er trennt aber nicht den Pin vom Timer. Er stellt den Pin so um, dass der vom Timer indirekt getoggelt wird, in dem er den Pullup zu oder wegschaltet. Der Pin toggelt zwischen mittel-ohmig (gegen Vcc) und tristate und ist nicht dauerhaft auf 0. Je nach Aussenbeschaltung kann das in der konkreten Anwendung funktionieren oder auch nicht.
:
Bearbeitet durch User
Dietrich schrob: >Egal ob >mit oder ohne Pullup ist der PNP immer gesperrt. Und das ist auch nicht >zufällig (bis auf die Vernachlässigung der Restströme vom Port und >Kollektor-Basis). >Wenn er ihn dann wieder auf "Ausgang" schaltet, folgt er wieder dem >Timer. Ja, genau so ist es. Das "Zuschalten" des Timers auf den Ausgang ist nicht zufällig, es ist exakt. Das muß es auch sein, weil das hier erzeugte RC5-Signal sonst vom freundlichen Fernseher nicht estimiert wird. MfG Paul
Karl Heinz schrieb: > Je nach Aussenbeschaltung kann das in der konkreten Anwendung > funktionieren oder auch nicht. Ja, OK. Aber bei Pauls Schaltung geht es. Allerdings ist das "richtige" Abschalten sicherlich universeller und sollte deshalb als Lösung bevorzugt werden. Gruß Dietrich
Karl Heinz schrieb: > Da hättest du genausogut auch TCCR0A = 0; > schreiben können. Ist genau der gleiche Effekt. Ja. Wenn ich eine Zuweisung: TCCR0A &= (0<<COM0A1)|(0<<COM0A0) schreibe, sollte der compiler TCCR0A einlesen, danach bits COM0A0 und COM0A1 auf Null setzen, danach TCCR0A zuruckschreiben. Stattdessen: TCCR0A AND ((0<<COM0A1)|(0<<COM0A0)=0) = wieder 0. Resultat ist Null und das ist Falsch. Wenn ich TCCR0A = (0<<COM0A1)|(0<<COM0A0) schreibe, sollte der compiler TCCR0A auf Null setzen und das ist Richtig, weil das eine neue Zuweisung ist. Ich dachte, da es sich hier um C fur microcontroller handelt, sollte dieser zumindest so viel Intelligenz(?) haben, um zu erkennen, dass es sich hier um bitpositionen handelt und dass alles was nicht explizit angeführt ist, vom alten Wert übernommen und NICHT in dieser Operation benutzt werden soll. OK, mit Asche bestreut.
Marc Vesely schrieb: > Wenn ich eine Zuweisung: > TCCR0A &= (0<<COM0A1)|(0<<COM0A0) schreibe, sollte der compiler TCCR0A > einlesen, danach bits COM0A0 und COM0A1 auf Null setzen, > danach TCCR0A zuruckschreiben. FALSCH. Wo hast Du das gelernt? 0<<x schiebt eine 0 x-mal nach links. Das Ergebnis ist 0. Also bleibt da: TCCR0A &= 0 | 0; Also: TCCR0A &= 0; Wenn man etwas mit AND 0 verknüpft, kommt da immer 0 raus! > Stattdessen: > TCCR0A AND ((0<<COM0A1)|(0<<COM0A0)=0) = wieder 0. > Resultat ist Null und das ist Falsch. Der Compiler macht alles richtig. Aber Dein C-Buch, in dem Du das gelernt hast, ist falsch. Es ist absoluter Unsinn, eine 0 zu schieben. Das Ergebnis ist IMMER 0. > Wenn ich TCCR0A = (0<<COM0A1)|(0<<COM0A0) schreibe, sollte der > compiler TCCR0A auf Null setzen und das ist Richtig, weil das eine > neue Zuweisung ist. Denkfehler. Es ist egal, ob Du TCCR0A = 0; oder TCCR0A &= 0; schreibst. Das Resultat ist das Gleiche: Es wird das KOMPLETTE Register auf 0 gesetzt. > Ich dachte, da es sich hier um C fur microcontroller handelt, > sollte dieser zumindest so viel Intelligenz(?) haben, um zu > erkennen, dass es sich hier um bitpositionen handelt und dass alles > was nicht explizit angeführt ist, vom alten Wert übernommen > und NICHT in dieser Operation benutzt werden soll. Sorry, der Compiler macht, was Du ihm sagst. Und bei Bitmanipulationen wie den obigen verhält sich jeder C-Compiler gleich, egal, ob das ein Großrechner, ein PC oder ein µC ist.
Frank M. schrieb: > Sorry, der Compiler macht, was Du ihm sagst. Und bei Bitmanipulationen > wie den obigen verhält sich jeder C-Compiler gleich, egal, ob das ein > Großrechner, ein PC oder ein µC ist. Und ich möchte hinzufügen: Das ist auch gut so. Einen Compiler, der eigenmächtig meine hingeschriebene Logik verändert (selbst wenn sie falsch ist), den möchte ich nicht benutzen. Es gilt immer noch die Arbeitsteilung: ich bin für Algorithmen und die Logik zuständig. Der Compiler ist dafür zuständig, die von mir geschriebenen Operationen möglichst effizient auf der zur Verfügung stehenden Hardware abzubilden, ohne das im Sinn zu verändern, was ich hingeschrieben habe. Wenn ich schreibe
1 | if( x == 5 && x == 8 ) |
2 | ....
|
dann ist das zwar logisch gesehen fehlerhaft (weil es nun mal keine Zahl gibt, die gleichzeitig sowohl 5 als auch 8 sein könnte), aber das darf ein Compiler nicht korrigieren, selbst wenn er es könnte. Er darf mich warnen aber abgesehen davon gilt: Der Programmierer ist der Boss.
:
Bearbeitet durch User
@Marc Vesely: Also manche Leute sind schlecht belehrbar. Wer lesen (und verstehen) kann, ist klar im Vorteil. http://www.mikrocontroller.net/articles/Bitmanipulation#Standard_C_2
Man, bin ich froh, dass hier so viele gebildete Experten sind, die geduldig in der Ecke sitzen und auf einen Tipp- oder Denkfehler von anderen warten. Und dann hilfsreich mit unnützen Bemerkungen einspringen. Wenn jemand schreibt: var_x = (1<<4), dann kan das dem Compiler egal sein, wenn er aber schreibt: TCCR0A = (0<<COM0A1)|(0<<COM0A0), dann soll der Compiler wie oben beschrieben vorgehen. Wer's versteht, wird's kapieren...
Marc Vesely schrieb: > wenn er aber schreibt: > TCCR0A = (0<<COM0A1)|(0<<COM0A0), dann soll der Compiler Sollte sein: TCCR0A &= (0<<COM0A1)|(0<<COM0A0)
> Wenn jemand schreibt: > var_x = (1<<4), dann kan das dem Compiler egal sein, > wenn er aber schreibt: > TCCR0A = (0<<COM0A1)|(0<<COM0A0), dann soll der Compiler > wie oben beschrieben vorgehen. > > Wer's versteht, wird's kapieren... Wieso? Das ist doch ganz einfach. 0 << 0 = 0 0 << 1 = 0 0 << 2 = 0 . . . 0 << 7 = 0 Eine geschobene 0 ist immer 0.
Marc Vesely schrieb: > Wenn jemand schreibt: > var_x = (1<<4), dann kan das dem Compiler egal sein, > wenn er aber schreibt: > TCCR0A = (0<<COM0A1)|(0<<COM0A0), dann soll der Compiler > wie oben beschrieben vorgehen. > > Wer's versteht, wird's kapieren... Nein. Du hast nichts kapiert. Du erfindest gerade eine neue Sprache. Die hat aber nichts mit C zu tun. Nachtrag: # cat x.c #include <stdio.h> #include <stdint.h> int main () { uint8_t x; x = 0xFF; // alle bits gesetzt x &= (0<<3) | (0<<4); printf ("0x%02x\n", x); return 0; } # cc x.c -o x # ./x 0x00 Da kann man sich wenden, wie man will. 0 bleibt 0.
:
Bearbeitet durch Moderator
Und ich versteh nicht, warum du es nicht einfach testet mit einem Port und 8 LEDs. Selbst 12-jährige verstehen Bitmanipulation. Wenn du eine 0 um n Stellen verschiebst sind doch die anderen Stellen auch Nullen.
holger schrieb: > Eine geschobene 0 ist immer 0. Der Erste, der es nicht versteht. Frank M. schrieb: > Nein. Du hast nichts kapiert. Du erfindest gerade eine neue Sprache. Die > hat aber nichts mit C zu tun. Der Zweite, der es nicht versteht. (Aber so tut, als ob). Mathias O. schrieb: > Und ich versteh nicht, warum du es nicht einfach testet mit einem Port > und 8 LEDs. Selbst 12-jährige verstehen Bitmanipulation. Wenn du eine 0 > um n Stellen verschiebst sind doch die anderen Stellen auch Nullen. Der Dritte, der es nicht versteht.
Dann zeig das doch bitte mal an einem Beispiel in ausgeschriebener Binärschreibweise, mit immer 8 Bit.
>> Eine geschobene 0 ist immer 0. > > Der Erste, der es nicht versteht. Du bist der einzige der es nicht versteht. Aber vieleicht kann man dir noch helfen;) > TCCR0A = (0<<COM0A1)|(0<<COM0A0), dann soll der Compiler COM0A1 ist nur ein define in einer Header Datei. Es ist nur eine Zahl z.B. #define COM0A0 2 //2 kann jetzt auch falsch sein. #define COM0A1 3 //3 kann jetzt auch falsch sein. Das ist nur die Bitposition im Register. Jetzt musst du nur noch einsetzen: (0<<COM0A1) = 0 (0<<COM0A0) = 0 TCCR0A = (0)|(0); 0 | 0 = 0 TCCR0A = 0; Voila. Was DU bräuchtest wäre sowas wie: TCCR0A.COM0A1 = 0; Aber das ist ein anderes Thema;)
Marc Vesely schrieb: > Der Erste, der es nicht versteht. > Der Zweite, der es nicht versteht. (Aber so tut, als ob). > Der Dritte, der es nicht versteht. Ein Geisterfahrer? Nein, hunderte!
Frank M. schrieb: > Nein. Du hast nichts kapiert. Du erfindest gerade eine neue Sprache. Die > hat aber nichts mit C zu tun. Und Lektionen aus binärer Logik brauche ich wirklich nicht - es ging darum was der Compiler tun sollte und was der tatsächlich tut. Okay, ich versuch's ein letztes Mal. Diese Zuweisungen (die wiederrum AVR-spezifisch sind, also nichts mit C als Sprache zu tun haben), werden in etwa so ubersetzt: C: // TCCR0A wird 0 TCCR0A = (0<<COM0A1)|(0<<COM0A0) ASM: ldi r16, 0<<COM0A1 | 0<<COM0A0 out TCCR0A, r16 C: // Es werden nur COM0A0/A1 gesetzt, alle anderen bits auf Null TCCR0A = (1<<COM0A1)|(1<<COM0A0) ASM: ldi r16, 1<<COM0A1 | 1<<COM0A0 out TCCR0A, r16 C: // Es werden COM0A0/A1 gesetzt, alle anderen bits bleiben TCCR0A |= (1<<COM0A1)|(1<<COM0A0) ASM: in r16, TCCR0A ldi r17, 1<<COM0A1 | 1<<COM0A0 or r16, r17 out TCCR0A, r16 ----------------------------------------------------------------- Trotz gegenteiligen Experten Meinungen, wird hier nichts gescheites getan. Wenn COM0A0/A1 gesetzt waren, bleiben die gesetzt, wenn COM0A0/A1 zurückgesetzt waren, bleiben die zurückgesetzt. C: TCCR0A &= (1<<COM0A1)|(1<<COM0A0) ASM: in r16, TCCR0A ldi r17, 1<<COM0A1 | 1<<COM0A0 and r16, r17 out TCCR0A, r16 ----------------------------------------------------------------- C: // Es werden COM0A0/A1 zurückgesetzt, alle anderen bits bleiben TCCR0A &= ~(1<<COM0A1)|(1<<COM0A0) ASM: in r16, TCCR0A ldi r17, 1<<COM0A1 | 1<<COM0A0 com r17 and r16, r17 out TCCR0A, r16 Wo ist dann das Problem, diese Anweisung zu ubersetzen: C: // Es werden COM0A0/A1 zurückgesetzt, alle anderen bits bleiben TCCR0A &= (0<<COM0A1)|(0<<COM0A0) ASM: in r16, TCCR0A cbr r16, 1<<COM0A1 | 1<<COM0A0 out TCCR0A, r16 Weil es kürzer ist ? Wie c-hater schrieb: Naja, in Sprachen, die nicht den räudigen Bastard eine Macroassemblers darstellen, ... Wozu das Ganze, wenn ich sowieso fast auf der Assembler-Ebene programmieren muss ?
Marc Vesely schrieb: > Okay, ich versuch's ein letztes Mal. Schön. Dann gibt's ja noch Hoffnung für den Rest von uns.
Marc Vesely schrieb: > wenn er aber schreibt: > TCCR0A = (0<<COM0A1)|(0<<COM0A0), dann soll der Compiler > wie oben beschrieben vorgehen. Nein, das soll er nicht. Denn die Operatoren '=', '<<' und '|' haben eine vorgegebene Bedeutung. Egal wie du es wendest. Mit der vorgegebenen Bedeutung ergibt sich nun mal nicht die Operation, die du so gerne hättest. > Wer's versteht, wird's kapieren... Der einzige, der hier nicht kapiert wie Programmiersprachen funktionieren und das diese Operation in keinster Weise an irgendwelche Register und/oder Bits in diesem Register geknüpft ist, sondern für beliebige Bits in beliebigen Bytes gilt, bist wohl du. Lern mit den binären Operationen &, | und ~ klar zu kommen, dann hast du mehr davon als darüber zu jammern, dass die Kombination der Operationen die dir vorschwebt nun mal nicht das ergibt, was du gerne hättest. Du kannst noch so laut jammern, dass 5 * 0 deiner Meinung nach 8 ergeben sollte. Die Mathematik, so wie der Rest der Welt sie betreibt, funktioniert nun mal nicht so. > ... > Weil es kürzer ist ? > ... Du hältst Compiler-Bauer wirklich für so dämlich? Constant-Folding ist die trivialste Optimierung, die es im Compilerbau gibt. Wenn ein Compiler in
1 | TCCR0A &= ~(1<<COM0A1)|(1<<COM0A0) |
den konstanten Ausdruck nicht vorberechnen und zu einer einzigen Zahlenkonstante zusammenfassen kann, dann soll der Compilerbauer sich sein Lehrgeld zurückgeben lassen. Denn das war dann offensichlich hinausgeschmissenes Geld. PS: DIe Operationen ANDI bzw. ORI sind auf dem AVR schon erfunden. Dein heiss geliebtes CBR wird vom Assembler genau zu einem ANDI übersetzt, bei dem die angegebene Konstante bitinvertiert wird. Das du CBR schreiben kannst, ist ein Service des Assemblers, der ein
1 | cbr register, maske |
zu
1 | andi register, ~maske |
umsetzt, ehe er dann den Opcode für ANDI ausspuckt.
1 | in r17, TCCR0A |
2 | andi r17, ~( ( 1<<COM0A1 ) | ( 1<<COM0A0 ) ) |
3 | out TCCR0A, r17 |
und
1 | in r17, TCCR0A |
2 | cbr r17, 1<<COM0A1 | 1<<COM0A0 |
3 | out TCCR0A, r17 |
ergeben daher Bit für Bit den identischen Code. Assembler kannst du also auch nicht.
:
Bearbeitet durch User
Oh, hier geht es ja lustig zu.... Ohne irgendjemandem auf den Schlips treten zu wollen, hier ein Beispiel, wie man in Bascom Bits in Registern setzen kann: 'Timer 0 zurecht machen für 36KHz Tccr0a.com0a0 = 1 'Toggle Oc0a bei Compare Match Tccr0a.wgm01 = 1 'Mode 2 (CTC) Tccr0b.cs00 = 1 'Vorteiler=1 Ocr0a = 111 '8MHz Takt, interner Oszillator, Vorteiler 1 '8MHz/36000=222 (wegen Toggle = 111) Mir erscheint das übersichtlich und weniger fehlerträchtig als in anderen Sprachen. MfG Paul
Marc Vesely schrieb: > Diese Zuweisungen (die wiederrum AVR-spezifisch sind, also nichts mit C > als Sprache zu tun haben), werden in etwa so ubersetzt: Du bist im Irrtum. Bis auf den Namen des Registers ist da überhaupt nichts AVR-spezifisches. Auf einer anderen Plattform könnte ich das Register durch eine Variable simulieren, z.B. so: volatile uint8_t TCCR0A; (Dass diese Variable hier volatile sein muss, ist ein anderes Thema, das lassen wir jetzt mal beiseite) Die Konstantzen COM0A1 bzw. COM0A0 sind einfach nur zwei Zahlen (findest Du in der µC-spezifischen include-Datei Deines Entwicklungspakets). Zum Beispiel wäre das: #define COM0A1 5 #define COM0A0 4 Der Preprocessor ersetzt die Konstanten in Deinem Source: TCCR0A &= (1<<5)|(1<<4); Das ersetzt der Compiler intern: TCCR0A &= 32 | 16; Das vereinfacht der Compiler im nächsten Schritt zu: TCCR0A &= 48; Oder bitweise gesehen: TCCR0A &= 0b00110000; Da steht einfach nichts anderes als Variable &= KONSTANTER_WERT; Es bleibt NICHTS, ABER AUCH GAR NICHTS von den Shifts übrig. Solange um eine Konstante geschoben wird, rechnet der Compiler diese Ausdrücke selber aus und ersetzt sie durch das Resultat! Und das MUSS ein C-Compiler auf jeder Plattform (ob Großrechner oder µC) immer GLEICH machen! Sonst wäre es nicht C, sondern eine andere Sprache. Der C-Compiler für den AVR muss das genauso ausrechnen wie jeder andere C-Compiler auf dieser Erde. Jetzt ersetze bitte nochmal im Kopf die obigen Einsen durch Nullen. Dann kommt da auf jedem korrekt funktionierendem C-Compiler der Welt raus: TCCR0A &= 0; Vereinfacht: TCCR0A = 0; // batsch, register komplett zurückgesetzt. Und das muss jeder Compiler der Welt so machen. Sonst kann man sich auf nichts mehr verlassen. Denn: Die 0 oder 1 vor dem Shift-Operator könnte auch eine Variable sein TCCROA &= (var1<<COM0A1)|(var2<<COM0A0) , deren Wert erst zur Laufzeit bekannt ist. Dann muss im Falle von var=1 oder var=0 exakt derselbe Wert rauskommen - wie bei den Konstanten. > C: // Es werden COM0A0/A1 zurückgesetzt, alle anderen bits bleiben > TCCR0A &= ~(1<<COM0A1)|(1<<COM0A0) Nochmal: Du missachtest hier die Rangfolge der C-Operatoren. Das "~" bindet stärker als das "|". Somit negierst Du nur den ersten Teil des Ausdrucks. Und das ist hyperfalsch. Korrekt ist - ich wiederhole mich für die Mitmeissler hier: TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0));
:
Bearbeitet durch Moderator
Paul Baumann schrieb: > Ohne irgendjemandem auf den Schlips treten zu wollen, hier ein Beispiel, > wie man in Bascom Bits in Registern setzen kann: > > 'Timer 0 zurecht machen für 36KHz > Tccr0a.com0a0 = 1 'Toggle Oc0a bei Compare Match > Tccr0a.wgm01 = 1 'Mode 2 (CTC) > [...] Du wirst lachen: Das hat Bascom der Sprache C abgeschaut. Es handelt sich hier um Bitfelder. In vielen µC-Entwicklungssystemen werden genau so Bits in Registern gesetzt. Beim AVR wurde auf die Definition der nötigen Bitfelder verzichtet. PeDa hat schon gezeigt, dass man (wenn man die Definitionen der Bitfelder selbst vornimmt) durchaus auch beim avr-gcc schreiben könnte: TCCR0A.com0a0 = 1; Warum auf die Definition der Bitfelder speziell beim AVR verzichtet wurde, lässt sich nur drüber streiten. Ich weiß aber, dass der frühere avr-gcc von 2010 diese Anweisung schlecht optimiert hat, so dass man mit TCCR0A |= (1<<COM0A0); // äquivalent zu TCCR0A.com0a0 = 1; besser gefahren ist. Vielleicht hat man deshalb auf die Definition der Bitfelder verzichtet. Bei anderen µC Entwicklungssystemen sind sie aber gebräuchlich. Mittlerweile übersetzt der avr-gcc beide Statements aber absolut identisch.
Und hier der Beweis, dass es auch beim AVR auch mit Bitfeldern funktionieren würde, was Paul so sehr an Bascom schätzt:
1 | #include <stdint.h> |
2 | #include <avr/io.h> |
3 | |
4 | /* Definition der Bits für PORTB: */
|
5 | |
6 | struct bits { |
7 | uint8_t b0:1; |
8 | uint8_t b1:1; |
9 | uint8_t b2:1; |
10 | uint8_t b3:1; |
11 | uint8_t b4:1; |
12 | uint8_t b5:1; |
13 | uint8_t b6:1; |
14 | uint8_t b7:1; |
15 | } __attribute__((__packed__)); |
16 | |
17 | #define PORT_B (*(volatile struct bits*)&PORTB)
|
18 | |
19 | /* ENDE Definition */
|
20 | |
21 | int main () |
22 | {
|
23 | PORTB |= (1 << PB1); |
24 | |
25 | PORT_B.b1 = 1; |
26 | }
|
Übersetzt wird das für den ATmega88:
1 | int main () |
2 | { |
3 | PORTB |= (1 << PB1); |
4 | 46: 29 9a sbi 0x05, 1 ; 5 |
5 | |
6 | PORT_B.b1 = 1; |
7 | 48: 29 9a sbi 0x05, 1 ; 5 |
8 | } |
9 | 4a: 80 e0 ldi r24, 0x00 ; 0 |
10 | 4c: 90 e0 ldi r25, 0x00 ; 0 |
11 | 4e: 08 95 ret |
Wie man sieht, werden sowohl PORTB |= (1 << PB1); als auch PORT_B.b1 = 1; gleich übersetzt, nämlich: sbi 0x05, 1 Wer hat nun Lust & Laune, für alle AVR-µCs sämtliche Bitfelder für alle vorkommenden Register in entsprechenden Include-Dateien zu definieren? ;-) P.S. Man sollte aber beachten, dass man mit der "klassischen" Schreibweise einen klaren Vorteil hat: Man kann damit mehrere Bits zu derselben Zeit in einem Register setzen bzw. löschen. Das kann man bei der Bitfeld-Schreibweise nicht.
:
Bearbeitet durch Moderator
Paul Baumann schrieb: > Mir erscheint das übersichtlich und weniger fehlerträchtig als in > anderen > Sprachen. Kein Einwand. Wie schon gezeigt, kann man sich das durchaus auch in C so zurecht legen, dass man auf die Bits per Name in einer STruktur zugreifen kann. Und wie du auch richtig sagst, würde das einen beträchtlichen Vorteil in Punkto Fehlervermeidung bedeuten. Der einzige Nachteil (mit Einschränkungen) ist, das man auf die Art nur auf Bits nacheinander zugreifen kann. Mit den UND und ODER Operationen kann ich auch mehrere Bits bei einem einzigen Zugriff setzen bzw. löschen, was bei Zugriff über die Bitnamen so nicht geht. Um beim Beispiel zu bleiben. Würde ich schreiben
1 | TCCR0A.COM0A1 = 0; |
2 | TCCR0A.COM0A0 = 0; |
dann hat man einen kurzen Zwischenzustand, in dem ein mögliches COM0A1 schon gelöscht wurde, das COM0A0 aber noch auf 1 ist. Das hat aber für den Timer wiederrum eine Bedeutung wie er den OC-Ausgang zu bedienen hat und wenn es sich blöd ausgeht, dann schlägt just in dieser kurzen Zeitspanne der Compare Match zu und der Timer wertet die COM Bits auf eine Art und Weise aus, die nicht beabsichtigt war.
:
Bearbeitet durch User
Karl Heinz schrieb: > Würde ich schreiben >
1 | > TCCR0A.COM0A1 = 0; |
2 | > TCCR0A.COM0A0 = 0; |
3 | >
|
> > dann hat man einen kurzen Zwischenzustand, in dem ein mögliches COM0A1 > schon gelöscht wurde, das COM0A0 aber noch auf 1 ist. Da hast Du vollkommen recht. In diesem Fall müsste man ein Bitfeld definieren, das über 2 Bits geht, also COM0A:2. Dann kannst Du schreiben: TCCR0A.COM0A = 0; Hier würden dann beide Bits gleichzeitig gelöscht werden. Bei der Definition der Bitfelder müsste man schon überlegen, welche Bits man sinnvoll zusammenfasst. Wieder eine Komplexitätsstufe mehr.....
Frank M. schrieb: > In diesem Fall müsste man ein Bitfeld definieren, das über 2 Bits geht, > also COM0A:2. > > Dann kannst Du schreiben: > > TCCR0A.COM0A = 0; Definiert man anstelle der 0 dann noch ein paar schöne benannte Konstante, dann würde das sogar richtig komfortabel werden :-) Das einzige Problem: Wer setzt sich hin und schreibt für alle Prozessoren die entsprechenden Header Files :-) Die jetzigen werden ja per Tool aus den XML Prozessor Beschreibungen generiert (zumindest wurden sie das zu Zeiten des AVR-Studios mal).
Frank M. schrieb: > In diesem Fall müsste man ein Bitfeld definieren, das über 2 Bits geht, > also COM0A:2. > > Dann kannst Du schreiben: > > TCCR0A.COM0A = 0; Definiert man anstelle der 0 dann noch ein paar schöne benannte Konstante, dann würde das sogar richtig komfortabel werden :-) Das einzige Problem: Wer setzt sich hin und schreibt für alle Prozessoren die entsprechenden Header Files :-) Die jetzigen werden ja per Tool aus den XML Prozessor Beschreibungen generiert (zumindest wurden sie das zu Zeiten des AVR-Studios mal).
Karl Heinz schrieb: > Das einzige Problem: Wer setzt sich hin und schreibt für alle > Prozessoren die entsprechenden Header Files :-) Genau darüber denke ich gerade nach. :-) Vielleicht sollte man hier auf µC.net dafür ein Gemeinschaftsprojekt ins Leben rufen? Wenn viele mitmachen, sollte auch so eine Fleißarbeit möglich sein. Denn ich fände es auch klasse, wenn man diese Bitfelder hätte. Wo findet man diese XML-Beschreibungsdateien? Sind diese soweit fehlerfrei und wurden/werden gepflegt? Oder wurden bei Bugs einfach die µC-abhängigen Header-Dateien korrigiert?
:
Bearbeitet durch Moderator
Frank M. schrieb: > Wo findet man diese XML-Beschreibungsdateien? Such in deiner Installation vom Atmel Studio bzw. AVR Studio nach einem Ordner "Partdescriptionfiles". Bei mir ist der (auf dieser Maschine) auf C:\Program Files\Atmel\AVR Tools\Partdescriptionfiles > Sind diese soweit > fehlerfrei und wurden/werden gepflegt? Ja, die werden meines Wissens gepflegt. Die dienen als Grundlage für den Simulator und daraus werden die Include Files für den Assembler und für den gcc generiert. Jörg müsste da mehr darüber wissen.
Karl Heinz schrieb: > Such in deiner Installation vom Atmel Studio bzw. AVR Studio nach einem > Ordner "Partdescriptionfiles". Danke, gefunden. Ich habe mir beispielsweise mal die Datei für den ATmega88 angeschaut. Hier ein Auszug:
1 | <TCCR0A> |
2 | <IO_ADDR>0x24</IO_ADDR> |
3 | <MEM_ADDR>0x44</MEM_ADDR> |
4 | <WGM00_MASK>0x01</WGM00_MASK> |
5 | <WGM01_MASK>0x02</WGM01_MASK> |
6 | <COM0B0_MASK>0x10</COM0B0_MASK> |
7 | <COM0B1_MASK>0x20</COM0B1_MASK> |
8 | <COM0A0_MASK>0x40</COM0A0_MASK> |
9 | <COM0A1_MASK>0x80</COM0A1_MASK> |
10 | </TCCR0A> |
Damit lässt sich durchaus was anfangen. Das Dumme ist nur, dass hier die Information, dass COM0A0 und COM0A1 zu COM0A:2 zusammengefasst werden müssten, nicht direket herauslesbar ist. Man müsste die erstellten Header-Dateien nochmal manuell nachbearbeiten. Oder man macht es per Programm nach folgender Regel: Hat die jeweilige Konstante eine Ziffer am Ende und folgen gleichlautende Konstante mit aufsteigender Nummer, dann fasse diese Konstanten zu einem größeren Bitfeld zusammen. Das würde hier dann klappen für WGM0:2 COM0B:2 COM0A:2 Wer kennt ein Gegenbeispiel, wo der Schuss nach hinten losgehen würde?
:
Bearbeitet durch Moderator
Frank M. schrieb: > Wer kennt ein Gegenbeispiel, wo der Schuss nach hinten losgehen würde? Die WGM Bits sind insofern speziell, als sie bei einigen Timern (zb Timer1) über mehrere Register verteilt sind. Genau dort willst du also die Zusammenfassung wieder nicht haben, weil das wieder mehr verwirrt als es nützt. Im Idealfall würde man auch noch die Abhängigkeit vom Register loswerden wollen. Mit ein paar #define könnte man das so hindrehen, dass man einfach nur
1 | COM0A1 = 1; |
schreibt und über die Kombination aus #define und Bitfeld-Struktur findet der Compiler selbst raus, in welchem Register welche Bits zu setzen sind. Aber auch hier wieder: die WGM Bits machen Ärger, weil sie über mehrere Register verteilt sind. Auch der Sonderfall vom URSEL Bit in der UART Konfiguration dürfte sich nur schwer abbilden lassen. Des weiteren gibt es noch die Interrupt Flag Bits, die durch Einschreiben einer 1 gelöscht werden. Allerdings geschieht dies nicht durch eine Oder Verknüpfung, sondern durch Einschreiben einer Maske mit genau diesem 1 Bit. Alles in allem also nicht so einfach, wenn man alles mit Standard-C Mitteln erreichen möchte.
:
Bearbeitet durch User
Frank M. schrieb: >> C: // Es werden COM0A0/A1 zurückgesetzt, alle anderen bits bleiben >> TCCR0A &= ~(1<<COM0A1)|(1<<COM0A0) > > Nochmal: Du missachtest hier die Rangfolge der C-Operatoren. Das "~" Nein. Aber das ich die Klammern vergessen habe, gebe ich zu.
Karl Heinz schrieb: > Im Idealfall würde man auch noch die Abhängigkeit vom Register loswerden > wollen. Mit ein paar #define könnte man das so hindrehen, dass man > einfach nur >
1 | > COM0A1 = 1; |
2 | >
|
> schreibt und über die Kombination aus #define und Bitfeld-Struktur > findet der Compiler selbst raus, in welchem Register welche Bits zu > setzen sind. Ja, natürlich das geht. Gefällt mir. Denn je nach µC muss ich auch immer mal wieder in das Datenblatt schauen, weil ich mich frage: "In welchem verflixten Register steht das Bit(-feld) nochmal?". Und ruckzuck ist es dann passiert. Man verwendet die gewünschte Bit-Konstante mit dem falschen Register. > Aber auch hier wieder: die WGM Bits machen Ärger, weil sie über mehrere > Register verteilt sind. Ja, das ist blöd. Wenn es wenigstens zusammenhängende Register sind, dann könnte man vielleicht noch mit einem uint16_t-Cast direkt 2 Register auf einen Streich erwischen. Boah, was ist das fies! ;-) > Auch der Sonderfall vom URSEL Bit in der UART Konfiguration dürfte sich > nur schwer abbilden lassen. Ja, das ist auch ein Stolperstein. Von diesen gibt es gewiss einige. Trotzdem hat die Idee, solche Bitfelder zu erstellen, schon seinen Charme. > Des weiteren gibt es noch die Interrupt Flag Bits, die durch > Einschreiben einer 1 gelöscht werden. Allerdings geschieht dies nicht > durch eine Oder Verknüpfung, sondern durch Einschreiben einer Maske mit > genau diesem 1 Bit. Da (wie oben gezeigt) ein: REGISTER.flag = 1; zu sbi REGISTER,flag vom avr-gcc gewandelt werden würde, wäre das doch kein Problem? Oder habe ich Dich hier falsch verstanden?
Frank M. schrieb: > Da (wie oben gezeigt) ein: > > REGISTER.flag = 1; > > zu > > sbi REGISTER,flag > > vom avr-gcc gewandelt werden würde, Allerdings nur dann, wenn das Register mittels IN/OUT erreichbar ist, was nicht bei allen Registern auf allen AVR Typen der Fall ist.
Karl Heinz schrieb: > Allerdings nur dann, wenn das Register mittels IN/OUT erreichbar ist, > was nicht bei allen Registern auf allen AVR Typen der Fall ist. Okay, ich sehe schon: der Weg wird lang. Aber auch der beginnt mit dem ersten Schritt. Ich werde mal loslegen und einen Prototyp beginnen, der aus den XML-Dateien neue Header mit Bitfeld-Definitionen erstellt. Sobald der Prototyp steht, werde ich mich dazu melden - vielleicht in einem neuen Thread. Vielleicht stoße ich auf Gegenliebe und einige Leute sind bereit, daran mitzuwirken.
Das Problem ist, diese winzige Abstraktionsstufe die ihr hier einziehen wollt, bringt einfach zu wenig. Weil man will sowieso von den Registern weg abstrahieren und ob ich dann dort mit Bitfeldern, oder sbi oder normaler Zuweisung und Shiften arbeite, interessiert nicht mehr. Es ist nicht sinnvoll durch das ganze Programm durch, Register immer direkt (wie auch immer genau) anzusprechen. Dafür will man ja abstrahieren. Und damit ist dieser Schritt einfach völlig unnötiger Schmuck am Nachthemd. Sinnvolles abstrahieren um weg von den Register, hin zu höheren Funktionen zu kommen, ist viel zielführender. Das geht aber nur immer per Anwendung. Daran scheiterts doch aber bei den meisten. gruß cyblord
:
Bearbeitet durch User
Eijeijei! ;-) Ihr scheint wohl Gefallen an einer übersichtlicheren Möglichkeit zum Setzen der Bits in den Registern zu finden? Karl Heinz schrub: >..dann hat man einen kurzen Zwischenzustand, in dem ein mögliches COM0A1 >schon gelöscht wurde, das COM0A0 aber noch auf 1 ist. Ja, das ist ein Argument. Es gibt aber auch die Möglichkeit (in Bascom) mit dem Befehl "Bits" alle Mann im Register auf einmal zu erwischen. MfG Paul
Cyblord erklärte großspurig wie immer: >Das geht aber nur immer >per Anwendung. Daran scheiterts doch aber bei den meisten. Nur bei Dir nicht... Alle Anderen sind (Zitat:Egon Olsen) Stümper und lausige Amateure. ;-) MfG Paul
Karl Heinz schrieb: > PS: DIe Operationen ANDI bzw. ORI sind auf dem AVR schon erfunden. Dein > heiss geliebtes CBR wird vom Assembler genau zu einem ANDI übersetzt, Karl Heinz schrieb: > kannst noch so laut jammern, dass 5 * 0 deiner Meinung nach 8 ergeben > sollte. Die Mathematik, so wie der Rest der Welt sie betreibt, Karl Heinz schrieb: > ergeben daher Bit für Bit den identischen Code. > Assembler kannst du also auch nicht. Sehr objektiv. Naja, als Moderator muss man das sein... Wieso mein heissgelibtes CBR ? Wo habe ich 5 * 0 erwahnt ? ANDI und ORI sind Masken, CBI/CBR sind fur Bitmanipulationen vorgesehen und deswegen hat Atmel (und auch einige andere Leute) gedacht, dass es gut wäre, diese Operationen nochmals als extra Befehl aufzuführen. Damit es übersichtlicher wird. Damit man weiss, dass es um Bitmanipulation geht. Völlig unnütze, sogar beleidegende Bemerkung.
Ach Paul was soll denn nun das Gestänkere? Ich dachte es geht hier um Programmierung. Sachlich bleiben, versuchs mal. Auch wenn du davon nichts verstehst. Ein Schüler in der Schule fängt halt an zu stören wenn er beim Thema nicht mehr mitkommt. So ist es bei dir! Wenn du dich angesprochen fühlst, ist das nicht meine Schuld. KHB fühlt sich z.B. sicher nicht angesprochen und fängt an zu krakelen. Komisch gell. Aber korrekte Abstraktion IST ein schwieriges Thema. Zuwenig ist schlecht, zu viel ist schlecht, die Falsche ist schlecht. Und diese Bitfeld-Geschichte ist ja an sich kein Problem, nur eben relativ unnötig. gruß cyblord
:
Bearbeitet durch User
cyblord ---- schrieb: > Aber korrekte Abstraktion IST ein schwieriges Thema. Zuwenig ist > schlecht, zu viel ist schlecht, die Falsche ist schlecht. Prinzipiell eine richtige Erkenntnis. > Und diese > Bitfeld-Geschichte ist ja an sich kein Problem, nur eben relativ > unnötig. EDIT: Wenn Du die Bitfelder benutzt, kannst Du nicht mehr die Bits auf falsche Register anwenden. Der Compiler würde sofort meckern. Ein unschlagbarer Vorteil. Also ich würde es sofort nutzen wollen, wenn ich es denn hätte. Und ich kann mir durchaus vorstellen, dass einige andere auch davon profitieren wollten. P.S. Mittlerweile habe ich ein Programm, dass mir immerhin schon mal sämtliche Register und deren Bits aus den XML-Dateien extrahiert.... bin dran :-)
:
Bearbeitet durch Moderator
Ich habe mit einem prototypischen PHP-Programm mal das ATmega88A.xml interpretiert und die im Anhang zu findende ATmega88_bf.h automatisch erzeugt. Bitte mal anschauen, wenn interessiert. Damit lässt sich nun das folgende Programm übersetzen:
1 | #include <stdint.h> |
2 | #include <avr/io.h> |
3 | |
4 | #include "ATmega88A_bf.h" |
5 | |
6 | int main () |
7 | {
|
8 | PORTB |= (1 << PB1); |
9 | |
10 | PORTB_BF.PORTB1_bf = 1; |
11 | }
|
Beide Statements in main() führen zu demselben Assembler-Befehl. Im Moment werde noch keine zusammenhängenden Bits wie COM0A0 und COM0A1 zusammengefasst. Kommt in der nächsten Version :-) Etwas unglücklich bin ich mit den Suffixes _BF bzw. _bf. Die hängen im Moment noch an den Bezeichnern, um mit den originalen nicht in Konflikt zu geraten. Wie es nun weitergeht: - Zusammenfassung von zusammenhängenden Bits zu einem größeren Bitfeld, z.B. COM0A - Korrekte Kommentare in den neuen Header-Dateien - Weitere Defines, welche das Aufführen des betreffenden Registers erübrigen. Also statt TCCR0A.COM0A einfach nur COM0A. - Erstellung eines Makefiles bzw. Scripts, was sämtliche XML-Dateien durch das PHP-Programm jagt - Erstellen eines io_bf.h, welches je nach µC das richtige ATxxxx_bf.h "includiert". Hat jemand noch Anregungen dazu?
:
Bearbeitet durch Moderator
Ich find das auch sehr interessant! Auch wenn ich mit der momentanen Variante auch gut zurechtkomme, das bessere ist der Feind des Guten! a) hielte ich es für sinnvoll einen eigenen Thread eröffnen? b) bin ich auch unsicher, wie ich denn die "zusammengefassten" bits gerne angreifen würde... lassen wir das "verteilte" WGM mal weg: gerade bei WGM führt eh kein Weg am Datenblatt vorbei, und ich mag auch nicht unbedingt selber Binär => hex wandeln... Wie schwebt euch das denn vor?
1 | TCCR2A_BF.WGM2 = 3 // hmmm... |
2 | TCCR2A_BF.WGM2 = WGM20 + WGM21 // sinnlos, ich weiss |
3 | TCCR2A_BF.WGM2 = 1*WGM20 + 0*WGM21 // hmmm... |
4 | TCCR2a_BF.WGM2 ( WGM20 => 0; WGM21 => 1); // ah ja, falsche sprache... |
Selbst wenn ich mir was wünschen könnte, wüsste ich an der stelle nicht, was :-(
Man sieht. Nicht alles was vereinfachen soll, macht es einfacher. Am Ende braucht es dann davon auch noch ne extra Doku wie solche Fälle gehandhabt werden. Und ein weiterer Header der fehlerfrei sein muss und gepflegt werden muss. Und für neue Controller immer nachgezogen werden muss. gruß cyblord
Michael Reinelt schrieb: > a) hielte ich es für sinnvoll einen eigenen Thread eröffnen? Ja, werde ich mit der nächsten Version machen. Dauert aber noch was, denn ich muss mich jetzt erstmal wieder um den "Alltag" kümmern. Vielleicht morgen... neuer Thread. Ich werde dann auf jeden Fall hier einen Link aufführen. > b) bin ich auch unsicher, wie ich denn die "zusammengefassten" bits > gerne angreifen würde... lassen wir das "verteilte" WGM mal weg: gerade > bei WGM führt eh kein Weg am Datenblatt vorbei, und ich mag auch nicht > unbedingt selber Binär => hex wandeln... Ja, da bin ich auch noch unsicher. > Wie schwebt euch das denn vor? > >
1 | > TCCR2A_BF.WGM2 = 3 // hmmm... |
2 | >
|
Ja, das wäre eine Möglichkeit: TCCR2A_BF.WGM2 = 0; TCCR2A_BF.WGM2 = 1; TCCR2A_BF.WGM2 = 2; TCCR2A_BF.WGM2 = 3; Gefällt mir aber noch nicht so besonders - auch wenn es wenigstens schon mal nicht kryptischer ist als die klassische Schreibweise: TCCR2A |= (1<<WGM20)|(1<<WGM21); Denn damit kann auch keiner was anfangen. Karl Heinz sprach ja eben noch von entsprechenden Preprocessor-Konstanten statt den technisch möglichen Werten 0, 1, 2 oder 3. Man müsste sich also jetzt mal anschauen, was die vier möglichen Werte genau bedeuten und dann vielleicht entsprechende Konstanten definieren. In den XML-Dateien sind dazu auch noch weitere Infos. Soweit habe ich die aber noch nicht ausgewertet. Kommt Zeit, kommt Rat. Je mehr mitmischen, desto größer ist die Chance eines guten Tipps. Gruß, Frank
cyblord ---- schrieb: > Man sieht. Nicht alles was vereinfachen soll, macht es einfacher. Richtig. Aber man kann ja beides parallel verwenden. Da, wo es übersichtlicher sein soll, benutzt man die BF-Variante, anderenfalls die bisherige. > Am > Ende braucht es dann davon auch noch ne extra Doku wie solche Fälle > gehandhabt werden. Vor Doku habe ich mich noch nie gescheut. Die mit hundert bis mehreren tausend Seiten starken fli4l- und eisfair-Dokus haben bewiesen, dass erst eine gute Doku eine Software auch zur guten Software macht. Das gleiche gilt für IRMP. > Und ein weiterer Header der fehlerfrei sein muss und > gepflegt werden muss. Und für neue Controller immer nachgezogen werden > muss. Ja und. Du musst es ja nicht machen. Also kein Grund zum Jammern. Sobald da mehrere engagierte Leute mitmachen, wird das Ding zum Selbstläufer. Ich habe da bereits entsprechende Erfahrungen gesammelt.
Frank M. schrieb: > TCCR2A_BF.WGM2 = 3; > > Gefällt mir aber noch nicht so besonders - auch wenn es wenigstens schon > mal nicht kryptischer ist als die klassische Schreibweise: > > TCCR2A |= (1<<WGM20)|(1<<WGM21); > > Denn damit kann auch keiner was anfangen. Die find ich an der Stelle gar nicht schlecht: ich seh auf einen Blick welche WGM-Bits gesetzt/nicht gesetzt sind, mit der Info ins Datenblatt => zack, ich weiss was ich wissen muss. > Karl Heinz sprach ja eben noch von entsprechenden > Preprocessor-Konstanten statt den technisch möglichen Werten 0, 1, 2 > oder 3. Man müsste sich also jetzt mal anschauen, was die vier möglichen > Werte genau bedeuten und dann vielleicht entsprechende Konstanten > definieren. In den XML-Dateien sind dazu auch noch weitere Infos. Soweit > habe ich die aber noch nicht ausgewertet. Naja, bei WGM könnte man noch auf die "Mode-Nummer" aus dem Datenblatt zurückgreifen. Nehmen wir als Beispiel aber COM2A0/A1: da gibts keine Mode-Nummern, noch dazu haben die vier Möglichkeiten je nach PWM/Non-PWM leicht unterschiedliche Bedeutungen... Generell hielte ich es für sehr wichtig, dass man hier die Benennungen so gestaltet, dass man direkt damit "ins Datenblatt" gehen kann. Nur - das wird schwierig...
Frank M. schrieb: > Richtig. Aber man kann ja beides parallel verwenden. Die Tatsache dass man es nicht verwenden muss, taugt sehr selten als Argument für ein Feature ;-) >> Am >> Ende braucht es dann davon auch noch ne extra Doku wie solche Fälle >> gehandhabt werden. > > Vor Doku habe ich mich noch nie gescheut. Es geht nicht ums erstellen. Sondern der Anwender muss in die Doku schauen. Wo also Komplexität vermeintlich reduziert werden soll, wird Neue geschaffen. >> Und ein weiterer Header der fehlerfrei sein muss und >> gepflegt werden muss. Und für neue Controller immer nachgezogen werden >> muss. > > Ja und. Du musst es ja nicht machen. Darum gehts, wie gesagt, nicht. Du solltest dir auch überlegen ob du nicht ein einheitliches Präfix für alle Bitfelder und evt. später die Bits selbst verwenden willst. Du hast zwar im Moment für die Bitfelder ein _BF als Postfix, aber für sowas sind in C eigentlich Präfixe üblich.
:
Bearbeitet durch User
Frank M. schrieb: > Hat jemand noch Anregungen dazu? Probiere auch mal 'm88A.inc" - da sind auch die alten Pinbezeichnungen drin, auch die neuen #PRAGMA. Und eine neue Struct mit Fields wie: SnglReg = True/False ScndReg = uint8_t Shadowed = True/False wirst du wahrscheinlich auch brauchen.
Michael Reinelt schrieb: >> TCCR2A |= (1<<WGM20)|(1<<WGM21); >> >> Denn damit kann auch keiner was anfangen. > > Die find ich an der Stelle gar nicht schlecht: ich seh auf einen Blick > welche WGM-Bits gesetzt/nicht gesetzt sind, mit der Info ins Datenblatt > => zack, ich weiss was ich wissen muss. Ja, genau, ins Datenblatt musst Du hier auch schauen. Aber nehmen wir mal COM0A1 und COM0A0: Auszug aus dem Datenblatt: COM0A1 COM0A0 Description 0 0 Normal port operation, OC0A disconnected. 0 1 Toggle OC0A on Compare Match 1 0 Clear OC0A on Compare Match 1 1 Set OC0A on Compare Match Ein TCCR0A_BF.COM0A = 0b01; // 0b01 = 0 1 würde Dir nach einem Blick ins Datenblatt auch direkt signalisieren, dass der Fall "0 1 : Toggle OC0A on Compare Match" gemeint ist. Wenn dann noch zusätzlich in ATxxx_bf.h definiert wird:
1 | #define COM0A_NORMAL_PORT_OPERATION 0b00
|
2 | #define COM0A_TOGGLE_0C0A_ON_COMPARE_MATCH 0b01
|
3 | #define COM0A_CLEAR_0C0A_ON_COMPARE_MATCH 0b10
|
4 | #define COM0A_SET_0C0A_ON_COMPARE_MATCH 0b11
|
kann man auch TCCR0A_BF.COM0A = COM0A_TOGGLE_0C0A_ON_COMPARE_MATCH; schreiben. Dann erübrigt sich sogar der Blick ins Datenblatt - jedenfalls für den Leser ;-)
:
Bearbeitet durch Moderator
cyblord ---- schrieb: > Du solltest dir auch überlegen ob du nicht ein einheitliches Präfix für > alle Bitfelder und evt. später die Bits selbst verwenden willst. Du hast > zwar im Moment für die Bitfelder ein _BF als Postfix, aber für sowas > sind in C eigentlich Präfixe üblich. Ich schrieb ja oben bereits, dass ich mit _BF ziemlich unglücklich bin. Präfixe wären vielleicht sinnvoller, sind aber auch noch nicht unbedingt das Gelbe vom Ei. Man käme jedenfalls auch nicht in Konflikte, wenn man alles kleinschreiben würde, also: tccr0a.com0a = 0b01; Aber das lässt sich wohl sehr schlecht von eigenen Variablen unterscheiden. Ja, Präfixe wären wahrscheinlich noch das Beste von allen Optionen...
Frank M. schrieb: > Dann erübrigt sich sogar der Blick ins Datenblatt - jedenfalls für den > Leser ;-) Der erübrigt sich nie :-) weil: Fast-PWM:
1 | COM0A1 COM0A0 Description |
2 | 0 1 WGM02 = 0: Normal Port Operation, OC0A Disconnected. |
3 | WGM02 = 1: Toggle OC0A on Compare Match. |
Michael Reinelt schrieb: > Der erübrigt sich nie :-) weil: > > Fast-PWM: >
1 | > COM0A1 COM0A0 Description |
2 | > 0 1 WGM02 = 0: Normal Port Operation, OC0A Disconnected. |
3 | > WGM02 = 1: Toggle OC0A on Compare Match. |
4 | > |
Aua. Ja, Du hast recht. Das geht so nicht. Also doch die 0bxx-Schreibweise?
Frank M. schrieb: > Aua. Ja, Du hast recht. Das geht so nicht. Also doch die > 0bxx-Schreibweise? Wart'mer mal andere Kommentare und Ideen ab...
Marc Vesely schrieb: > Probiere auch mal 'm88A.inc" - da sind auch die alten > Pinbezeichnungen drin, auch die neuen #PRAGMA. > Und eine neue Struct mit Fields wie: Ich finde nur ein m88Adef.inc. ^^^ Da lese ich in den ersten beiden Zeilen:
1 | ;***** THIS IS A MACHINE GENERATED FILE - DO NOT EDIT ******************** |
2 | ;***** Created: 2010-02-25 11:46 ******* Source: ATmega88A.xml *********** |
Diese Datei wurde also aus der XML-Datei automatisch erzeugt - bringt also nicht mehr an Informationen. Ich muss aber zugegeben, dass ich hier auf dem PC, wo ich gerade nachschauen kann, nur alte Dateien aus dem Jahre 2010 drauf habe.
Ich weiß nicht, ob sich das in C von Euch / für Euch so umsetzen läßt: In Bascom gibt es den Befehl "Bits". Der setzt alles, was dahinter steht, auf 1 Beispiel: Tccr2a = Bits(com2b1 , Wgm21 , Wgm20) 'PWM-Mode 3 ein Das heißt: Im Register "Tccr2a" die Bits com2bl, wgm21 und wgm20 werden gesetzt, der Rest der Bits da drin bleibt Null Andersrum geht es auch, da heißt der Befehl "NBits". Das erscheint mir am einfachsten, weil weder geschoben noch ausmaskiert noch sonst irgendwie herumgefuhrwerkt werden muß. --------------------------------------------------------------------- Hinweis: Ich will hier Niemanden von der Sprache "C" weglocken, oder Reklame für Bascom machen -bitte nicht falsch auffassen! MfG Paul
Michael Reinelt schrieb: > Frank M. schrieb: >> Aua. Ja, Du hast recht. Das geht so nicht. Also doch die >> 0bxx-Schreibweise? > > Wart'mer mal andere Kommentare und Ideen ab... Ich will ja hier keinen in seinem Tatendrang behindern. Aber da kam EINER, der die Shift-Schreibweise der Register-Bits nicht kapiert hat, und schon drehen alle wie verrückt am Rad, um die Schreibweise zu ändern. Wo bleibst denn bei diesem Beispiel der Satz: "Kauf dir ein C-Buch!"? Gerade hier wäre er doch angebracht. Alle wissen, wie es funktioniert, einer kann oder will es nicht begreifen und plötzlich wollen alle das verändern, was eigentlich gar keine Probleme macht. Nichts für ungut. Ich wundere mich nur :-)
Paul Baumann schrieb: > In Bascom gibt es den Befehl "Bits". Der setzt alles, was dahinter > steht, > auf 1 > > Beispiel: > Tccr2a = Bits(com2b1 , Wgm21 , Wgm20) 'PWM-Mode 3 ein Das geht in C mit: TCCR2A = (1<<COM2B1)|(1<<WGM21)|(1<<WGM20); Wahrscheinlich ist das hier in diesem konkreten Fall auch die bessere Lösung. Alternative wäre eine Funktion, z.B. Timer2PWMMode3() o.ä. Aber das wäre dann schon eine Art von neuer Lib, welche die Hardware-Register noch weiter abstrahiert. Aber vielleicht ist "ein Schritt nach dem nächsten" doch die bessere Vorgehensweise...
Ich fasse mal die letzen 50 Beiträge zusammen und gebe noch meinen Senf dazu: Es ist doch absolut egal, wie man die Register schreibt. Dem einen passen die Bitfelder besser (wie es bei vielen PICs der Fall ist, diese bieten meisstens sogar beides), dem anderen die Maskierung (wie AVR), oder noch die elegantere weise über komplete Defines der "Funktionen" wie es z.B. bei STM der Fall ist. Vieleicht würde ein Blick über den AVR Tellerrand nicht schaden, ansonsten halt alles selber umschreiben oder sich mit dem gegebenen Paket abfinden. Oder man schreibt sich die entsprechenden header-Dateien selber (mir wäre das absolut zu viel Aufwand) Hauptsache man weiss was man macht. Patrick B. schrieb: > Du meinst wohl das:TCCR0A &= ~(1<<COM0A1)|(1<<COM0A0) Frank M. schrieb: >> Aber auch das hier: >>> TCCR0A &= ~(1<<COM0A1)|(1<<COM0A0) > Leute, lest erstmal ein C-Buch, bevor Ihr solchen Murks verbreitet. Ubs, copy & paste Fehler, aber zum Glück gibts ja noch nette Leute, die einem Fehler verzeihen. Ausserdem wirds langsam ziemlich OT.
:
Bearbeitet durch User
hw schrieb: > Ich will ja hier keinen in seinem Tatendrang behindern. Aber da kam > EINER, der die Shift-Schreibweise der Register-Bits nicht kapiert hat, > und schon drehen alle wie verrückt am Rad, um die Schreibweise zu > ändern. Nein, nicht ändern, sondern eher "erweitern". :-) > Wo bleibst denn bei diesem Beispiel der Satz: "Kauf dir ein > C-Buch!"? Kein Problem. In einem guten C-Buch sind auch Bitfelder erklärt. > Gerade hier wäre er doch angebracht. Alle wissen, wie es > funktioniert, einer kann oder will es nicht begreifen und plötzlich > wollen alle das verändern, was eigentlich gar keine Probleme macht. Von "Verändern" kann keine Rede sein. Und ja, es macht unter gewissen Umständen schon Probleme, z.B. ein Schreiben von Bits (wie COM2A0) in falsche Register, z.B. TCCR0A. Das kann Dir bei der Bitfeld-Schreibweise nicht passieren. Da meckert bereits der Compiler.
Frank M. schrieb: > hw schrieb: >> Ich will ja hier keinen in seinem Tatendrang behindern. Aber da kam >> EINER, der die Shift-Schreibweise der Register-Bits nicht kapiert hat, >> und schon drehen alle wie verrückt am Rad, um die Schreibweise zu >> ändern. > > Nein, nicht ändern, sondern eher "erweitern". :-) > >> Wo bleibst denn bei diesem Beispiel der Satz: "Kauf dir ein >> C-Buch!"? > > Kein Problem. In einem guten C-Buch sind auch Bitfelder erklärt. > >> Gerade hier wäre er doch angebracht. Alle wissen, wie es >> funktioniert, einer kann oder will es nicht begreifen und plötzlich >> wollen alle das verändern, was eigentlich gar keine Probleme macht. > > Von "Verändern" kann keine Rede sein. Und ja, es macht unter gewissen > Umständen schon Probleme, z.B. ein Schreiben von Bits (wie COM2A0) in > falsche Register, z.B. TCCR0A. Das kann Dir bei der Bitfeld-Schreibweise > nicht passieren. Da meckert bereits der Compiler. Ja, ok. Ich habe mich unpräzise ausgedrückt :-) Erweitern wäre besser gewesen, weil ja an der bestehenden Schreibweise nichts verändert wird. Trotzdem finde ich es bemerkenswert, daß bis jetzt immer, wenn Mißverständnisse mit der "bisherigen" Schreibweise auftraten, der berühmte Satz zitiert wurde. Was ich ja auch richtig finde, nur der Tonfall dabei manchmal nicht, aber das ist eine andere Sache. Aber plötzlich kapiert wieder jemand nicht die Schreibweise und alle wollen jetzt aktiv werden. Das finde ich nur bemerkenswert. Im übrigen haben mir die Bitfelder in keinster Weise gefehlt (also die "neue angestrebte Schreibweise" meine ich. Wenn ich ein Projekt beginne, lege ich alles nötige mit Hilfe des Datenblattes einmal an. Und das auch nur, wenn ich einen µC verwende, den ich bisher noch nicht in den Fingern hatte. Wenn's ein "alter Bekannter" ist, werden die Initialisierungen von einem anderen Projekt mit dem gleichen µC kopiert. Damit habe ich nur ein einziges Mal die Arbeit, mir die Bits aus dem Datenblatt rauszuschreiben. Und das ist die erste Verwendung eines µC. Dann nie wieder. Insofern kann das normalerweise gar nicht passieren, daß beispielsweise ein WGM-Bit einem anderen Register zugeordnet wird. Aber das kann ja auch jeder machen, wie er will. Und ich sagte ja schon, ich will niemanden in seinem Tatendrang bremsen. Wenn was baruchbares rauskommt, ist es doch in Ordnung. Stimmts?
hw schrieb: > Insofern kann das normalerweise gar nicht passieren, > daß beispielsweise ein WGM-Bit einem anderen Register zugeordnet wird. Ich verstehe schon, was Du meinst. Aber gefährlich kann Deine Vorgehensweise schon sein. Es gibt durchaus Fälle bei der AVR-Familie, wo ein durchaus geläufiges und im Leben schon tausendfach genutztes Bit namens XXXX plötzlich mal in ein anderes Register wandert, wenn man den µC wechselt. Da läuft man schnell Gefahr, so einen Fehler durch Copy&Paste aus dem wohlbekannten Code zu machen. > Aber das kann ja auch jeder machen, wie er will. Und ich sagte ja schon, > ich will niemanden in seinem Tatendrang bremsen. Wenn was baruchbares > rauskommt, ist es doch in Ordnung. Stimmts? Stimmt. Mich "plagt" da gerade bei den AVRs noch ein kleines Zipperlein, was mich zum Beispiel bei der "portablen, µC-unspezifischen" Implementierung von PWMs arg stört. Für IRSND, das Sende-Pendant von IRMP habe ich folgende Fallunterscheidungen im Code:
1 | if defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny84__) // ATtiny44/84 uses OC0A = PB2 or OC0B = PA7 |
2 | # if IRSND_OCx == IRSND_OC0A // OC0A
|
3 | # define IRSND_PORT_LETTER B
|
4 | # define IRSND_BIT_NUMBER 2
|
5 | # elif IRSND_OCx == IRSND_OC0B // OC0B
|
6 | # define IRSND_PORT_LETTER A
|
7 | # define IRSND_BIT_NUMBER 7
|
8 | # else
|
9 | # error Wrong value for IRSND_OCx, choose IRSND_OC0A or IRSND_OC0B in irsndconfig.h
|
10 | # endif // IRSND_OCx
|
11 | #elif defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__) // ATtiny45/85 uses OC0A = PB0 or OC0B = PB1
|
12 | # if IRSND_OCx == IRSND_OC0A // OC0A
|
13 | # define IRSND_PORT_LETTER B
|
14 | # define IRSND_BIT_NUMBER 0
|
15 | # elif IRSND_OCx == IRSND_OC0B // OC0B
|
16 | # define IRSND_PORT_LETTER B
|
17 | # define IRSND_BIT_NUMBER 1
|
18 | # else
|
19 | # error Wrong value for IRSND_OCx, choose IRSND_OC0A or IRSND_OC0B in irsndconfig.h
|
20 | # endif // IRSND_OCx
|
21 | #elif defined (__AVR_ATtiny87__) || defined (__AVR_ATtiny167__) // ATtiny87/167 uses OC0A = PA2
|
22 | |
23 | ....
|
24 | |
25 | #if defined(ATMEL_AVR)
|
26 | # define _CONCAT(a,b) a##b
|
27 | # define CONCAT(a,b) _CONCAT(a,b)
|
28 | # define IRSND_PORT CONCAT(PORT, IRSND_PORT_LETTER)
|
29 | # define IRSND_DDR CONCAT(DDR, IRSND_PORT_LETTER)
|
30 | # define IRSND_BIT IRSND_BIT_NUMBER
|
31 | #endif
|
Sieht das nicht furchtbar aus? Je nachdem, was der Anwender für einen µC-spezifischen PWM-Pin in der irsndconfig.h ausgewählt hat (OC0A, OC1A, OC0B usw. usw.), versucht dieses Monstrum herauszufinden, an welchem PIN dieser PWM-Ausgang denn nun steckt, damit man den PIN schon mal auf Ausgang stellen kann - was für eine PWM absolut notwendig ist. Und das wird da oben für so ziemlich jeden ATmega oder ATtiny gemacht, auf dem eine Anwendung von IRSND sinnvoll wäre.... Daher Monstrum. Das obige ist nur ein Auszug. Dort, wo "...." steht, geht das über mehr als 100 Zeilen so weiter :-( Wie ich jetzt gesehen habe, stecken solche Infos durchaus in den XML-Dateien drin. Somit hätte man mit den entsprechenden Defines eine ganz andere Möglichkeit, jeden erdenklichen PWM-Pin auf einem X-beliebigen AVR-µC portabel anzusteuern, ohne dass man dafür seinen Code neu schreiben muss oder eine Preprocessor-Orgie durchführt.
:
Bearbeitet durch Moderator
Paul Baumann schrieb: > Tccr2a = Bits(com2b1 , Wgm21 , Wgm20) 'PWM-Mode 3 ein Das gefällt mir zum Beispiel gar nicht. ich möchte jedes Bit "sehen", ob es 0 oder 1 wird. Deshalb bin ich auch von der "_BV()" Schriebweise ganz abgekommen. Ich bevorzuge das
1 | 0<<WBM20 | 1<<WGM21 |
Weiters ist mir wichtig dass ich entweder das ganze Register oder nur gezielt Bits darin setzen kann (=> maskieren mit |= bzw &= ) Ganz schön fände ich natürlich auch nach wie vor die Möglichkeit, "Einzeiler" zu schreiben, d.h. in einer Zeile mehrere (auch unterschiedliche) Bits gleichzeitig zu setzen. Das wird natürlich mit der "neuen" Schreibweise TCCR2A_BF.WGM2 = 3 schwierig, wenn ich parallel zu WGM noch ein paar andere bits beeinflussen will. Für mich bleiben zwei Hauptargumente übrig: a) die "umständliche" Schreibweise speziell mit &= ~(xxx | yyy) zu vereinfachen (es ist mir nciht einmal passiert dass mir da z.B. ein || statt | reingerutsch ist, und den code kannst du 1000 Mal ansehen und den Tippfehler trotzdem übersehen) b) zu verhindern dass man falsche bits in falschen Registern setzt (bzw. dem Compiler eine Möglichkeit zu geben eine Warnung auszuspucken) d) idealerweise noch die "verteilten" Bits zusammenfangen (TCCR1A,B,C) Wenns nur in C sowas gäbe: TCCR1 (WGM20 => 0, WGM21=>1, WGM22=>0, COM1A1 => 1)
Michael schrub: >Weiters ist mir wichtig dass ich entweder das ganze Register oder nur >gezielt Bits darin setzen kann Das kann der o.g. Befehl doch. >Ganz schön fände ich natürlich auch nach wie vor die Möglichkeit, >"Einzeiler" zu schreiben, d.h. in einer Zeile mehrere (auch >unterschiedliche) Bits gleichzeitig zu setzen. Das ist doch der Sinn davon, deshalb gab ich das ja als Anregung. Ob sich das so realisieren läßt, kann ich nicht sagen. Wenn man in Bascom ein "falsches" Bit in einem Register erwischt, dann sagt der freundliche Kompiler: Kein solches Bit in diesem Register! Hier (in C) müßte man so einen Fehler wohl, wenn ich es richtig verstanden habe, "von Hand" abfangen. MfG Paul
Paul Baumann schrieb: > Michael schrub: >>Weiters ist mir wichtig dass ich entweder das ganze Register oder nur >>gezielt Bits darin setzen kann > > Das kann der o.g. Befehl doch. ich korrigiere: "setzen und löschen" Ob das in Bascom geht, kann ich leider nicht beurteilen (BAScom klingt so nach BASic)
Michael Reinelt schrieb: > ich möchte jedes Bit "sehen", ob es 0 oder 1 wird. > Deshalb bin ich auch von der "_BV()" Schriebweise ganz abgekommen. > Ich bevorzuge das 0<<WBM20 | 1<<WGM21 NEEEEEIIIN !!! Eine Woche Urlaub in Mongolien machen, Laptop zuhause lassen.
Michael schrabte: >Ob das in Bascom geht, kann ich leider nicht beurteilen (BAScom klingt >so nach BASic) Das habe ich weiter oben geschrieben: Mit "NBits" geht es andersrum d.h. ein gesetztes Bit wird damit wieder auf 0 gebracht. Normalerweise ist das aber nicht nötig, weil "von Natur aus" alle Bits Null sind und ich nur die "behandeln" muß, die ich setzen will. MfG Paul
Paul Baumann schrieb: > Normalerweise ist das aber nicht nötig, weil "von Natur aus" alle Bits > Null sind und ich nur die "behandeln" muß, die ich setzen will. Das verstehe ich jetzt nicht. Du willst Bits setzen, mußt aber niemals eins rücksetzen? Man braucht doch beides, je nachdem, was man erreichen will. Im Beispiel dieses Threads, wie willst du den Pin vom Timer trennen, wenn du niemals ein Bit auf 0 setzen willst?
Marc Vesely schrieb: > Michael Reinelt schrieb: >> ich möchte jedes Bit "sehen", ob es 0 oder 1 wird. >> Deshalb bin ich auch von der "_BV()" Schriebweise ganz abgekommen. >> Ich bevorzuge das 0<<WBM20 | 1<<WGM21 > > NEEEEEIIIN !!! > Eine Woche Urlaub in Mongolien machen, Laptop zuhause lassen. ähhhh... was genau wolltest du mir sagen? (Frage ernst gemeint)
npn schrieb: > Das verstehe ich jetzt nicht. Du willst Bits setzen, mußt aber niemals > eins rücksetzen? Man braucht doch beides, je nachdem, was man erreichen > will. Hat er doch geschrieben: bits(..) setzt Bits, nbits(...) löscht Bits.
Michael Reinelt schrieb: > Marc Vesely schrieb: >> Michael Reinelt schrieb: >>> ich möchte jedes Bit "sehen", ob es 0 oder 1 wird. >>> Deshalb bin ich auch von der "_BV()" Schriebweise ganz abgekommen. >>> Ich bevorzuge das 0<<WBM20 | 1<<WGM21 >> >> NEEEEEIIIN !!! >> Eine Woche Urlaub in Mongolien machen, Laptop zuhause lassen. > > ähhhh... was genau wolltest du mir sagen? (Frage ernst gemeint) Er hat gesehen, dass Du nun auch 0en durch die Gegend schiebst ;-)
Frank M. schrieb: > Michael Reinelt schrieb: >> Marc Vesely schrieb: >>> Michael Reinelt schrieb: >>>> ich möchte jedes Bit "sehen", ob es 0 oder 1 wird. >>>> Deshalb bin ich auch von der "_BV()" Schriebweise ganz abgekommen. >>>> Ich bevorzuge das 0<<WBM20 | 1<<WGM21 >>> >>> NEEEEEIIIN !!! >>> Eine Woche Urlaub in Mongolien machen, Laptop zuhause lassen. >> >> ähhhh... was genau wolltest du mir sagen? (Frage ernst gemeint) > > Er hat gesehen, dass Du nun auch 0en durch die Gegend schiebst ;-) Ja Aber marc hat doch das Schieben von 0en propagiert? (vielleicht ist es heute auch einfach zu schwül für solche Sachen...)
Michael Reinelt schrieb: > ähhhh... was genau wolltest du mir sagen? (Frage ernst gemeint) Das ich genau das zu sagen versucht habe (Sehen ob bit gesetzt oder zurückgesetzt ist) und wurde von möchtegern Experten in C die nicht zwischen Zahl und bit unterscheiden können, nur so angespuckt.
Paul Baumann schrieb: > Das habe ich weiter oben geschrieben: Mit "NBits" geht es andersrum d.h. > ein gesetztes Bit wird damit wieder auf 0 gebracht. Ja aber wie mach ich das als Einzeiler? also in einem Staement z.B. Bit 2 und 3 setzen, bit 5 löschen?
Marc Vesely schrieb: > Das ich genau das zu sagen versucht habe (Sehen ob bit gesetzt oder > zurückgesetzt ist) und wurde von möchtegern Experten in C die nicht > zwischen Zahl und bit unterscheiden können, nur so angespuckt. Ok, verstehe. Das "anspucken" lag vielleicht an diversen vergessenen Klammern, Tilden und sonstigen Störgeräuschen? :-)
haha, also ich finde den Thread unterhaltsam - wie manche aneinander vorbei reden, manche stur etwas behaupten was nicht stimmt, ev. aber was anderes sagen wollen, andere mit einer Geduld die ich nie hätte es zu erklären versuchen und andere die ganz was anderes diskutieren als die Frage vom TO :) Schöne Grüße an alle
npn schrieb: > Setz doch COM0A0 und COM0A1 im TCCR0A auf 0. Das trennt den > Ausgangspin vom Timer ab. Dabei ist doch die Frage schon mit der ersten Antwort beantwortet gewesen. Der Rest des Threads drehte sich nur noch um das WIE. Und daß ein einziger nicht begriffen hat, daß es nichts bringt, wenn man Nullen durch die Gegend schiebt [offtopic](sieht man in Berlin...)[/offtopic].
hw schrieb: > Und daß > ein einziger nicht begriffen hat, daß es nichts bringt, wenn man Nullen > durch die Gegend schiebt Zugegeben. Das Thema wurde jetzt auch mit genügend Beispielen versehen :) Ist aber auch ein beliebter Anfängerfehler. Auch einer den man nicht gleich merkt. Wenns egal ist, da die anderen Bits im Register eh 0 sind. Irgendwann fällts einem dann mal auf die Füße und man denkt, das hat doch immer so geklappt... Seit ich mich mit den PICs beschäftige nutze ich auch oft das direkte setzen von Bits. Wenn nur eins gesetzt oder gelöscht werden muss, oder beim Rücksetzen von Int-Flags. Gut finde ich auch die Vorschlagsfunktion von MPLAB. Aber das ist wohl mehr ne IDE-Geschichte. Einen großen Vorteil sehen ich auchdarin, dass man merkt, wenn man Bits in einem Register verändern will, zu dem es garnicht gehört.
:
Bearbeitet durch User
Michael Reinelt schrieb: > Ok, verstehe. Das "anspucken" lag vielleicht an diversen vergessenen > Klammern, Tilden und sonstigen Störgeräuschen? :-) Nein. An nicht unterscheiden können zwischen Zahl und bit. Wenn ich Null (als Zahl) 6 mal nach links schiebe, bleibt das immer noch eine Null. (0<<6) = 0 Wenn ich bitzustand (0 oder 1) definieren will, dann sollte der Compiler diese Anweisung: TCCR0A = (1<<6) als 'setze das bit Nr.6 auf Log.1' interpretieren, dementsprechend sollte: TCCR0A = (0<<6) = 'setze das bit Nr.6 auf Null' heissen. Dank der enormen Zahl der wohlmeinenden C-Experten habe ich endlich begriffen, dass der ATMEL-Compiler das nicht kann.
Marc Vesely schrieb: > Dank der enormen Zahl der wohlmeinenden C-Experten habe ich endlich > begriffen, dass der ATMEL-Compiler das nicht kann. Habs grad ausprobiert. Der XC8 von Microchip kanns auch nicht. Bei welchem Compiler geht das denn?
Hi > Wenn ich bitzustand (0 oder 1) definieren will, dann sollte der > Compiler diese Anweisung: > TCCR0A = (1<<6) als 'setze das bit Nr.6 auf Log.1' interpretieren, > dementsprechend sollte: > TCCR0A = (0<<6) = 'setze das bit Nr.6 auf Null' heissen. > Dank der enormen Zahl der wohlmeinenden C-Experten habe ich endlich > begriffen, dass der ATMEL-Compiler das nicht kann. Welche C-Compiler kennst du denn, die das können? MfG Spess
Bad Urban schrieb: > Habs grad ausprobiert. Der XC8 von Microchip kanns auch nicht. Bei > welchem Compiler geht das denn? Ehrliche Antwort ? Hab keine Ahnung, ich mach das mit'm Macro
Marc Vesely schrieb: > Ehrliche Antwort ? > > Hab keine Ahnung, ich mach das mit'm Macro Na, dann... Das Thema hat mich irgendwie an die frühe Lehrzeit erinnert. Da konnte man beim Shiften Nullen oder Einsen nachschieben. Ich glaub da wurde der Inhalt des Carry-Bits übernommen. ist aber schon lange her...
> Dank der enormen Zahl der wohlmeinenden C-Experten habe ich endlich > begriffen, dass der ATMEL-Compiler das nicht kann. Schön. Das hast Du jetzt begriffen und Deinen letzten Versuch gehabt. Zur Sicherheit noch ein kleines:
1 | .post[data-user-id='56220'] { display: none; !important; } |
ins UserContent.css, denn irgendwelche konstruktiven Beiträge sind von Dir ohnehin nicht zu erwarten, und ein schönes Leben noch.
Michael frog: >Ja aber wie mach ich das als Einzeiler? also in einem Staement z.B. Bit >2 und 3 setzen, bit 5 löschen? So: Tccr0a.com0a0 = 0 : Tccr0a.wgm01 = 1 : Tccr0b.cs00 = 1 Hinweis: Das ist nur als Beispiel gedacht; ob das sinnvoll ist, habe ich nicht geguckt. MfG Paul
Bad Urban schrieb: > Marc Vesely schrieb: >> Dank der enormen Zahl der wohlmeinenden C-Experten habe ich endlich >> begriffen, dass der ATMEL-Compiler das nicht kann. > > Habs grad ausprobiert. Der XC8 von Microchip kanns auch nicht. Bei > welchem Compiler geht das denn? Ich denke mal, bei keinem, der sich "C-Compiler" nennt. Weil sowas entgegen der Logik ist.
Bitflüsterer schrieb: > ins UserContent.css, denn irgendwelche konstruktiven Beiträge sind von > Dir ohnehin nicht zu erwarten, und > > ein schönes Leben noch. 1 down, 3 more to go.
Habs mir gedacht. Aber seit ich mit den PICs arbeite nutze ich wirklich öfter die Darstellung: INTCONbits.GIE = 1; Von daher hätts ja sein können... Auch wenn ich nicht ganz dran geglaubt hab. Das würde ja voraussetzen, dass der Compiler davon ausgeht, dass alle Bits erstmal 1 sind.
Marc Vesely schrieb: > Dank der enormen Zahl der wohlmeinenden C-Experten habe ich endlich > begriffen, dass der ATMEL-Compiler das nicht kann. Nochmal zum Ins-Gehirn-Meißeln: Das kann nicht nur der ATMEL-Compiler nicht, sondern auch kein anderer C-Compiler auf der ganzen Welt Du hast ganz klare Defizite im Verständnis, was die Sprache C angeht. P.S. Nur um Deinen Bildungsgrad etwas aufzustocken: Dein "ATMEL"-Compiler ist gar nicht von ATMEL. Also nenne ihn nicht so.
:
Bearbeitet durch Moderator
Frank M. schrieb: > P.S. > Nur um Deinen Bildungsgrad etwas aufzustocken: Dein "ATMEL"-Compiler ist > gar nicht von ATMEL. Also nenne ihn nicht so. Ach, das gehört zur Bildung ? Und wo habe ich gesagt das der von ATMEL wäre ?
Ich habe nun einen neuen Thread begonnen: Beitrag "AVR-Register als Bitfields" Ich hoffe, ich habe alles nennenswerte zusammengefasst.
Diesen Moderator muß man ganz einfach lieben. So was von liebenswürdig und objektiv... Aber daß es OT war, gebe ich zu...
Karl Heinz schrieb: > Wenn du nur den Pin auf Eingang schaltest, dann PWM-t (wie nennt man > das, wenn eine PWM den Pin bedient?) der Timer munter den Pullup > Widerstand. Nein, das tut er nicht, das ist eine Legende, die hier aus unerfindlichen Gründen immer wieder verbreitet wird, die aber trotzdem unwahr ist. Nein, tatsächlich werden die Pullups mit Ausnahme einiger weniger Pins (TWI, USI) ausschließlich durch Schreibzugriff auf das Port-Register gesteuert. Die OC-Timer-Ausgänge (überhaupt alle alternate port functions) schreiben aber generell überhaupt nicht auf das Port-Register, sondern "daran vorbei". Eine ausführliche Prinzipskizze der Pin-Logik, die das zeigt, findet man in jedem AVR-Datenblatt unter der Überschrift "Alternate Port Functions". Übrigens: Wäre es tatsächlich so, wie du behauptest, dann hätte ich sicher schon hunderte FETs in diversen Schaltwandler-Anwendungen gegrillt. Die Schalter dort könnten auch mit dem bissel Strom, was die Pullups liefern locker in den Wärmetod getrieben werden. Was man nur zu leicht bemerkt, wenn man sie in diesen Anwendungen tatsächlich mal versehentlich aktiviert...
TV Techniker schrieb: >Die meisten TV-Geräte reagieren automatisch am PIN 8 >der SCARTBUCHSE(N) auf Power ON aus dem STDBY des angeschlossen >SAT-Receivers, sofern der über Schart am Pin 12 das Schaltsignal auch >liefert! Aber das tun die MEISTEN Receiver - egal, WELCHER Hersteller >das ist! Der Receiver liefert eine Schaltspannung, bloß der Fernseher wertet sie nicht aus! Ich zitiere mich noch einmal: >Hinweis: Der Fernseher hat auf seiner Scart-Buchse keinen Eingang für > eine Schaltspannung, das hätte die Sache einfach(er) gemacht. Also: Bevor Du hier Parolen ausgibst -lies und verstehe erst, was der Andere schreibt! Du hast das Problem nicht verstanden. >Hätte ich ja viel vor, immer gleich irgendwelche Programmier-ICs erst >auszuknobeln, zu programmieren - Fehlerweise wegschmeisen, neu >programmieren ect - es geht VIEL einfacher. Das ist MIR sowas von Brust, was Du vor hast oder auch nicht. Ab dafür Paul
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.