-Ralf-

RCLine Team

  • »-Ralf-« ist der Autor dieses Themas

Wohnort: Remscheid

Beruf: Prediger

  • Nachricht senden

1

Montag, 28. April 2014, 18:46

Mal ne Frage an C-Programmierer

Ich bin in C noch lange nicht sattelfest, also folgende Frage:

Was machen diese Programmzeilen mit dem Register?

Quellcode

1
2
      TCCR3A |= (1<<WGM31); // phase correct mode
      TCCR3A &= ~(1<<WGM30);


Insbesondere die 2. Zeile verstehe ich gar nicht.
Gruß Ralf (das Grantele)

Funcopter mit Alu-TS
Raptor E550

Laß dir von keinem Fachmann imponieren, der dir erzählt:
Lieber Freund, das mache ich schon zwanzig Jahre so. - Man
kann eine Sache auch zwanzig Jahre falsch machen.
Tucholsky

hsh

RCLine User

Wohnort: Österreich

  • Nachricht senden

2

Montag, 28. April 2014, 20:12

Das ist eine sehr gängige Schreibweise um mit Bitoperationen Registerinhalte einfach lesbar zu setzen (|=) oder zu löschen (&=) [1].
In der ersten Zeile wird das Bit WGM31 in Register TCCR3A gesetzt.
In der zweiten Zeile wird das Bit WGM30 gelöscht.
Die anderen Bits bleiben durch die Maskierung jeweils unverändert.

Die WGMxx Bits konfigurieren bei den AVRs die Betriebsart der PWM Einheit eines Timers. Die genaue Bedeutung findet man im Datenblatt des entsprechenden µC. Das hat mit C allerdings nicht viel zu tun.

[1] http://de.wikipedia.org/wiki/Bitweiser_Operator
mfg Harald

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »hsh« (28. April 2014, 20:24)


-Ralf-

RCLine Team

  • »-Ralf-« ist der Autor dieses Themas

Wohnort: Remscheid

Beruf: Prediger

  • Nachricht senden

3

Montag, 28. April 2014, 20:29

Danke Harald,

was passiert genau in der zweiten Zeile? Nach deiner Beschreibung müßte da zunächst
das Bit WGM30 auf 1 gesetzt werden, dann wird es invertiert (nur das Bit?) und dann ein
bitweises AND auf das ganze Byte angewendet?

Richtig?

Wenn ja, kann man nicht einfach ein

Quellcode

1
2
      TCCR3A |= (1<<WGM31); // phase correct mode
      TCCR3A |= (0<<WGM30);

machen?
Gruß Ralf (das Grantele)

Funcopter mit Alu-TS
Raptor E550

Laß dir von keinem Fachmann imponieren, der dir erzählt:
Lieber Freund, das mache ich schon zwanzig Jahre so. - Man
kann eine Sache auch zwanzig Jahre falsch machen.
Tucholsky

-Ralf-

RCLine Team

  • »-Ralf-« ist der Autor dieses Themas

Wohnort: Remscheid

Beruf: Prediger

  • Nachricht senden

4

Montag, 28. April 2014, 20:37

Ahhh, das OR in Zeile 2 geht natürlich nicht, aber wie ist es mit

TCCR3A &= (0<<WGM30);
Gruß Ralf (das Grantele)

Funcopter mit Alu-TS
Raptor E550

Laß dir von keinem Fachmann imponieren, der dir erzählt:
Lieber Freund, das mache ich schon zwanzig Jahre so. - Man
kann eine Sache auch zwanzig Jahre falsch machen.
Tucholsky

hsh

RCLine User

Wohnort: Österreich

  • Nachricht senden

5

Montag, 28. April 2014, 21:06

Nein, nicht ganz.
Invertiert wird die "Bitmaske". Unter der Annahme WGM30 ist das erste Bit eines 8-Bit Registers wäre
(1<<WGM30) = (1<<0) = 0x01= 0b00000001
~(1<<WGM30) = ~(0b00000001) = 0b11111110

Bei den Operatoren AND und OR hast du nun einen kleine Denkfehler. Wie du den verlinkten Wahrheitstabellen bzw. der booleschen Algebra [2] entnehmen kannst
ist 1 OR 0 = 1 und 1 AND 0 = 0.
d.h. man kann durch die "verUNDung" mit 0 einzelne Bits löschen (während alle anderen durch x AND 1 ihren alten Status behalten) und durch "verODERn" mit 1 einzelne Bits setzen (während alle anderen durch x OR 0 ihren alten Status behalten).

Der ShiftLeft Operator << mit 0 ist zwar zulässig, macht aber nicht viel Sinn. Du erzeugst damit ein "leeres" Byte mit (0<<x) = 0x00 = 0b00000000
Durch die OR Verknüpfung mit 0 passiert bei der Zuweisung TCCR3A |= (0<<WGM30); daher genau gar nichts.

0000 0000
OR
xxxx xxxx
---------
xxxx xxxx

hingegen erhälst du bei

0000 0010
OR
xxxx xxxx
---------
xxxx xx1x

und bei
1111 1110
AND
xxxx xxxx
---------
xxxx xxx0


[2] http://de.wikipedia.org/wiki/Boolesche_Algebra
mfg Harald

hsh

RCLine User

Wohnort: Österreich

  • Nachricht senden

6

Montag, 28. April 2014, 21:13

Ahhh, das OR in Zeile 2 geht natürlich nicht, aber wie ist es mit
TCCR3A &= (0<<WGM30);
Nein, damit würdest du das ganze Register auf 0x00 setzen. Du möchtest aber nur das Bit an Position WGM30 bearbeiten. Daher kommst du nicht um erstellen einer Bitmaske (je nach Bedarf invertiert oder nicht) herum.
Also Bit setzen durch |= (1<<x)
und Bit löschen durch &= ~(1<<x)
Bit togglen durch ^= (1<<x)
mfg Harald

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »hsh« (28. April 2014, 21:23)


-Ralf-

RCLine Team

  • »-Ralf-« ist der Autor dieses Themas

Wohnort: Remscheid

Beruf: Prediger

  • Nachricht senden

7

Montag, 28. April 2014, 21:27

Ahhh, das OR in Zeile 2 geht natürlich nicht, aber wie ist es mit
TCCR3A &= (0<<WGM30);
Nein, damit würdest du das ganze Register auf 0x00 setzen. Du möchtest aber nur das Bit an Position WGM30 bearbeiten. Daher kommst du nicht um erstellen einer Bitmaske (je nach Bedarf invertiert oder nicht) herum.
Also Bit setzen durch |= (1<<x)
und Bit löschen durch &= ~(1<<x)
Bit togglen durch ^= (1<<x)

Genau das verstehe ich nicht ..... warum mein Vorschlag das ganze Register löschen sollte.
Ich setze doch auch nur das Bit WGM30 auf 0; nichts anders macht die Invertierung mit ~
Gruß Ralf (das Grantele)

Funcopter mit Alu-TS
Raptor E550

Laß dir von keinem Fachmann imponieren, der dir erzählt:
Lieber Freund, das mache ich schon zwanzig Jahre so. - Man
kann eine Sache auch zwanzig Jahre falsch machen.
Tucholsky

hsh

RCLine User

Wohnort: Österreich

  • Nachricht senden

8

Montag, 28. April 2014, 22:08

:) nein, so funktionert das mit dem dem Shiftoperator (<<,>>) nicht.
Ich versuch den Ausdruch noch ein wenig zu zerlegen

TCCR3A &= (0<<WGM30);
TCCR3A = TCCR3A & (0<<WGM30);

so. laut Datenblatt ist WGM30 das erste Bit und WGM31 das zweite in Register TCCR3A, also sind die Makros
WGM30 0
WGM31 1
irgendwo definiert.
Wie schon ausgeführt erzeugt eine Shift-Operation mit einer 0 zwar gültigen Code, macht aber wenig Sinn. Wie man nun eine Bitmaske anschreibt ist eigentlich egal. Die Variante mit (1<<x) ist aber gut lesbar und recht gebräuchlich. Nur so als Beispiel:
1<<0 = 0x01 = 0b00000001
1<<1 = 0x02 = 0b00000010
1<<2 = 0x04 = 0b00000100
1<<3 = 0x08 = 0b00001000

so. also was bekommt man, wann man 0b00000000 um ein Stelle nach links verschiebt? richtig. wieder 0
TCCR3A = TCCR3A & (0<<0);
TCCR3A = TCCR3A & (0x00);
TCCR3A = 0x00;

Bei der korrekten Variante schaut es hingegen so aus:
TCCR3A &= ~(1<<WGM30);
TCCR3A = TCCR3A & ~(1<<WGM30);
TCCR3A = TCCR3A & ~(1<<0);
TCCR3A = TCCR3A & ~(0b00000001);
TCCR3A = TCCR3A & 0b11111110;
TCCR3A = 0bxxxxxxx0; egal was vorher in TCCR3A stand, das nicht maskierte Bit ist sicher 0 gesetzt.

Natürlich kann man die Bitmaske auch auch direkt als Zahlenwert anschreiben, allerdings leidet darunter die Lesbarkeit.
Ich hoffe ich konnte dir ein wenig weiter helfen. Sonst fällt mir nur noch ein Verweis auf http://www.mikrocontroller.net/articles/…n#Bitoperatoren oder ein C-Buch deiner Wahl ein :w
mfg Harald

-Ralf-

RCLine Team

  • »-Ralf-« ist der Autor dieses Themas

Wohnort: Remscheid

Beruf: Prediger

  • Nachricht senden

9

Montag, 28. April 2014, 22:47

Danke Harald, für deine Geduld und Mühe ..... ich habs verstanden :ok:
Gruß Ralf (das Grantele)

Funcopter mit Alu-TS
Raptor E550

Laß dir von keinem Fachmann imponieren, der dir erzählt:
Lieber Freund, das mache ich schon zwanzig Jahre so. - Man
kann eine Sache auch zwanzig Jahre falsch machen.
Tucholsky

hsh

RCLine User

Wohnort: Österreich

  • Nachricht senden

10

Dienstag, 29. April 2014, 20:12

bitte, gerne :)
mfg Harald

-Ralf-

RCLine Team

  • »-Ralf-« ist der Autor dieses Themas

Wohnort: Remscheid

Beruf: Prediger

  • Nachricht senden

11

Dienstag, 29. April 2014, 20:32

Mein Denkfehler war die Bitmaske, mit der verglichen wird. Das hatte ich so nicht
auf dem Schirm; bin davon ausgegangen, man könnte direkt ins Bit des Registers
schreiben.
Gruß Ralf (das Grantele)

Funcopter mit Alu-TS
Raptor E550

Laß dir von keinem Fachmann imponieren, der dir erzählt:
Lieber Freund, das mache ich schon zwanzig Jahre so. - Man
kann eine Sache auch zwanzig Jahre falsch machen.
Tucholsky

hsh

RCLine User

Wohnort: Österreich

  • Nachricht senden

12

Dienstag, 29. April 2014, 21:12

Den Direktzugriff könntest du z.B. mit inline Assembler erzwingen. Allerdings sind nicht alle Register der AVR Architektur bitadressierbar. Außerdem kann man in 95% der Fälle dem Compiler die Optimierung überlassen.

Manche Entwicklungsumgebungen (z.B. CodeVisonAVR) unterstützen auch andere Schreibweisen wie z.B. PORTA.1 oder PINB.3
Solche oder ähnliche Erweiterungen kann man sich auch in Form von Makros und Hilfsfunktionen selber definieren. Ich bin allerdings kein großer Freund von solchen Konstruktionen.
mfg Harald