Forum: Mikrocontroller und Digitale Elektronik PWM-Pin von AVR deaktivieren


von GerdBreuer (Gast)


Lesenswert?

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.

von npn (Gast)


Lesenswert?

Setz doch COM0A0 und COM0A1 im TCCR0A auf 0. Das trennt den Ausgangspin 
vom Timer ab.

von Eduard S. (schneehase)


Lesenswert?

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)

von Mat (Gast)


Lesenswert?

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

von abc (Gast)


Lesenswert?

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

von Paul Baumann (Gast)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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?

von Patrick B. (p51d)


Lesenswert?

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
von GerdBreuer (Gast)


Lesenswert?

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.

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


Lesenswert?

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.

von Paul Baumann (Gast)


Lesenswert?

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

von Paul Baumann (Gast)


Lesenswert?

Wie das in "C" geschrieben wird, müßt ihr selber nachgucken, damit
will ich mich nicht befassen.

MfG Paul

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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
von GerdBreuer (Gast)


Lesenswert?

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))

von npn (Gast)


Lesenswert?

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 :-)

von GerdBreuer (Gast)


Lesenswert?

Danke für die Hilfe!!!

Ich bin wirklich neidisch auf euer Können, Respekt!!!!!!

von Paul Baumann (Gast)


Angehängte Dateien:

Lesenswert?

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

von Würg (Gast)


Lesenswert?

GerdBreuer schrieb:
> Ich bin wirklich neidisch auf euer Können, Respekt!!!!!!

Schleimer

von Karl H. (kbuchegg)


Lesenswert?

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
von Paul Baumann (Gast)


Lesenswert?

Karl-Heinz schrub:
>Ist aber trotzdem falsch.

Das ist mir ziemlich gleichgültig, solange es funktioniert.

MfG Paul

von Karl H. (kbuchegg)


Lesenswert?

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
von Paul Baumann (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Paul Baumann (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von Stefan E. (sternst)


Lesenswert?

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

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


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von chris (Gast)


Lesenswert?

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;

von npn (Gast)


Lesenswert?

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 :-)

von Karl H. (kbuchegg)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

Karl Heinz schrieb:
> Nö. Das setzt keine Bits auf 0. Das ändert im TCCR0A Register überhaupt
> nichts.

Ähm, es setzt alle Bits auf 0. ;-)

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


Lesenswert?

Stefan Ernst schrieb:
> Es wird nicht logisch negiert, sondern binär.

 Wo habe ich geschrieben, dass es logisch negiert wird ?

von chris (Gast)


Lesenswert?

Karl Heinz schrieb:
> Auch nicht.

doch :)
da steht doch:
TCCR0A &= 0;

1 & 0 = 0
0 & 0 = 0

--> alles wird zu 0

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

chris schrieb:
> Karl Heinz schrieb:
>> Auch nicht.
>
> doch :)

Entschuldige chris.
Ich hatte Tomaten auf den Augen.

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


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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
von Dietrich L. (dietrichl)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
von Paul B. (paul_baumann)


Lesenswert?

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

von Dietrich L. (dietrichl)


Lesenswert?

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

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


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von Mathias O. (m-obi)


Lesenswert?

@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

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


Lesenswert?

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...

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


Lesenswert?

Marc Vesely schrieb:
> wenn er aber schreibt:
>    TCCR0A = (0<<COM0A1)|(0<<COM0A0), dann soll der Compiler

 Sollte sein:
  TCCR0A &= (0<<COM0A1)|(0<<COM0A0)

von holger (Gast)


Lesenswert?

> 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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Mathias O. (m-obi)


Lesenswert?

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.

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


Lesenswert?

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.

von Mathias O. (m-obi)


Lesenswert?

Dann zeig das doch bitte mal an einem Beispiel in ausgeschriebener 
Binärschreibweise, mit immer 8 Bit.

von holger (Gast)


Lesenswert?

>> 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;)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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!

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


Lesenswert?

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 ?

von Bitflüsterer (Gast)


Lesenswert?

Marc Vesely schrieb:
>  Okay, ich versuch's ein letztes Mal.

Schön. Dann gibt's ja noch Hoffnung für den Rest von uns.

von Karl H. (kbuchegg)


Lesenswert?

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
von Paul Baumann (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.....

von Karl H. (kbuchegg)


Lesenswert?

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).

von Karl H. (kbuchegg)


Lesenswert?

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).

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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
von Paul Baumann (Gast)


Lesenswert?

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

von Paul Baumann (Gast)


Lesenswert?

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

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


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Frank M. (ukw) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

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
von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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 :-(

von Cyblord -. (cyblord)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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...

von Cyblord -. (cyblord)


Lesenswert?

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
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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...

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Paul Baumann (Gast)


Lesenswert?

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

von hw (Gast)


Lesenswert?

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 :-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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...

von Patrick B. (p51d)


Lesenswert?

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
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von hw (Gast)


Lesenswert?

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?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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)

von Paul Baumann (Gast)


Lesenswert?

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

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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)

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


Lesenswert?

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.

von Paul Baumann (Gast)


Lesenswert?

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

von npn (Gast)


Lesenswert?

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?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 ;-)

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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...)

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


Lesenswert?

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.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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? :-)

von Mat (Gast)


Lesenswert?

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

von hw (Gast)


Lesenswert?

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].

von Bad U. (bad_urban)


Angehängte Dateien:

Lesenswert?

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
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Bad U. (bad_urban)


Lesenswert?

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?

von spess53 (Gast)


Lesenswert?

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

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


Lesenswert?

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

von Bad U. (bad_urban)


Lesenswert?

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...

von Bitflüsterer (Gast)


Lesenswert?

> 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.

von Paul Baumann (Gast)


Lesenswert?

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

von hw (Gast)


Lesenswert?

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.

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


Lesenswert?

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.

von Bad U. (bad_urban)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 ?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich habe nun einen neuen Thread begonnen:

  Beitrag "AVR-Register als Bitfields"

Ich hoffe, ich habe alles nennenswerte zusammengefasst.

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


Lesenswert?

Diesen Moderator muß man ganz einfach lieben. So was von
liebenswürdig und objektiv...
 Aber daß es OT war, gebe ich zu...

von c-hater (Gast)


Lesenswert?

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...

von Paul B. (paul_baumann)


Lesenswert?

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
Noch kein Account? Hier anmelden.