ich arbeite gerade die Arikel durch..1a die dinger..:)
aber ich habe eine frage auf bestimmte code zeile:
outp ((1 << RXEN) | (1 << TXEN), UCR);
ich weiss was die zeile macht aber ich versteh die einzelnen zeichen
net... ich kenne << nur als bit shiftoperand und nicht als zeichen um
ein bit zu setzen. und dann noch der | das ist für mich eine veroderung
und macht in meinen augen keinen sinn. wäre super wenn mir einer von
euch helfen könnte.
> ich kenne << nur als bit shiftoperand
So wird das hier auch gebraucht.
> und dann noch der | das ist für mich eine veroderung
auch das stimmt so.
(1 << RXEN) schiebt die "1" um genau so viele Positionen nach links, wie
der Wert in der Konstanten RXEN besagt. RXEN wurde die Zahl 4
zugewiesen, damit wird aus einer "1" durch 4x schieben das Bitmuster
00010000.
(1 << TXEN) ergibt 00001000. Die bieden Klammern verODERt wird zu
00011000 und das wird dem Register UCR zugewiesen.
Schmittchen.
Ich könnte sowas natürlich auch mit 2 Hilfsvariablen und 5 Zeilen Code
lösen, aber so viel Platz haben wir ja eigentlich gar nicht in unseren
Controllern oder ;-)
BYTE maske1, maske2;
maske1 = 1 << RXEN;
maske2 = 1 << TXEN;
outp (maske1 | maske2, UCR);
Das Verständnis der Bitschiebebefehle und der Bitoperatoren gehört zum
Basiswissen bei der C-Programmierung. Kann bei Bedarf alles im Teil 1
des Tutorials nachgelesen werden.
Gruss
Christian
> aber so viel Platz haben wir ja eigentlich gar nicht in unseren Controllern oder
;-)
Ich sehe zwar den Smiley, trotzdem noch eine Ergänzung:
Die Schreibweise im 1.Posting belegt nur 1 Zeile im Editor, und nur eine
Zeile im Maschinencode (out UCR, 0x18). Die 0x18 kann der Compiler
(Präprozessor) schon erzeugen und muß nicht jedesmal zur Laufzeit
errechnet werden.
In Christians Beispiel werden im Normalfall 4 Zeilen Maschinencode
daraus. (2x Zuweisung, 1x OR, 1x OUT ; das shift löst der Compiler
selbst auf).
Theoretische Überlegung:
Eigentlich könnte der Compiler auch Chrisitans Code in eine einzige
Maschinencodezeile optimieren (out UCR, 0x18). Wenn zuvor sichergestellt
ist, dass kein Interrupt dazwischen kommen kann, dann kann ich mir keine
Programmkonstellation/zustand vorstellen, bei dem die Zeilen nicht durch
out UCR, 0x18 ersetzt werden können!? Ich vermute aber, daß das dem
Compiler bzw. den Compilerprogrammierern zu weit geht und es nicht so
gemacht wird.
Schmittchen.
@Schmittchen
Wenn Du Variablen verwendest, denkt der Compiler, daß Du Dir dabei was
gedacht hast und optimiert sie nicht so einfach weg.
Sonst hättest Du ja #define genommen:
#define maske1 (1 << RXEN)
#define maske2 (1 << TXEN)
outp (maske1 | maske2, UCR);
So sinds dann wieder nur 2 Zeilen Assembler.
Peter
> Wenn Du Variablen verwendest, denkt der Compiler, daß Du Dir dabei was gedacht
hast
Ja klar, aber in dem speziellen Falle könnte er sie wegoptimieren,
ohne die Funktion des Programmes zu verändern. (Ich geb ja zu, daß das
ein sehr spezieller, konstruierter und weithergeholter Fall ist -
genauso wie zu fordern, daß der Compiler aus deinem Code nur 1 Zeile
machen soll.).
Schmittchen.
@Schmittchen
"genauso wie zu fordern, daß der Compiler aus deinem Code nur 1 Zeile
machen soll"
Ist doch unmöglich !
Um einen Wert in ein I/O-Register zu schreiben, brauchst Du mindestens 2
Instruktionen:
ldi r16, 1<<RXEN^1<<TXEN
out UCR, r16
Direkt irgendwas im I/O zu machen geht nur beim 8051 (MOV, INC, DEC,
DJNZ, ANL, ORL, XRL). Deshalb ist ja Code auf dem 8051 typischer Weise
kleiner als auf dem AVR.
Peter
> Um einen Wert in ein I/O-Register zu schreiben, brauchst Du mindestens 2
Instruktionen:
Stimmt! Für mich war das eine Instruktion, aber das kann der AVR ja
leider nicht. Also stimmen meine Angaben oben auch nicht ganz.
Aber manchmal geht der Compiler ja auch zu weit... siehe Beispiele leere
Warteschleife wegoptimieren (kann der Compiler ja nicht wissen) oder die
volatile-Geschichte. In beiden Fällen muß man den Compiler explizit
darauf "hinweisen".
Schmittchen.
> Aber manchmal geht der Compiler ja auch zu weit... siehe Beispiele leere
Warteschleife wegoptimieren ...
Nee, das ist schon richtig, das unnützer Code wegoptimiert wird. Wenn
das nicht gemacht würde, müsste man auch die Kommentare übernehen und
nicht wegoptimieren!
Wenn Optimierung eingeschaltet ist, sollte eine leere Warteschleife
immer wegoptimiert werden.
Eine Warteschleife sollte niemals wegoptimiert werden, wenn der
Compilerbauer mitgedacht hat.
Optimieren heißt doch nur sinnlosen Code zu entfernen aber eine
Warteschleife ist doch eindeutig als sinnvoll zum Warten zu erkennen.
Wenn ein Compilerbauer also leere Schleifen wegoptimiert, hat er
entweder keine praktische Programmiererfahrung oder er will den Nutzer
ärgern.
@Jonas,
stimmt, die meisten 8051 laufen mit 1 MIPS (Quarz = 12MHz), weil das
oftmals mehr als ausreichend ist. Aber für die
Geschwindigkeitsfetischisten gibts auch 8051-er mit max 50 MIPS (bzw.
100 MIPS als Samples), z.B von Cygnal.
Peter
Diese Aussage kann ich so nicht stehen lassen.
Bedenkt bitte, dass der C-Compiler nicht ausschliesslich zum
Programmieren von Mikrocontrollern entwickelt wurde und bei "normalen"
Anwendungen soll schliesslich nicht gewartet, sondern möglichst zügig
gearbeitet werden.
Insofern ist es aus Sicht des Compilers völlig in Ordnung, für ihn
sinnlose (weil leere) Loops wegzuoptimieren.
Christian
>Eine Warteschleife sollte niemals wegoptimiert>werden, wenn der Compilerbauer mitgedacht hat.
Ja, aber eine leere Schleife ist doch keine Warteschleife, ausser man
sagt das dem Compiler explizit. Ansonsten könnte der Compiler ja nichts
optimieren!
Beim MSPGCC sieht eine ganz einfache Warteschleife deshalb so aus:
for(i=0;i<1234;i++) _asm_ __volatile__("; loop");
Das die Schleife ohne volatile wegoptimiert ist doch auch das was man
haben möchte, denn nach einigen tausend Zeilen Code kann ein Mensch
wegoptimierbaren Code kaum erkennen, so das der Compiler das übernehmen
muss.