Ich war gerade dort: Beitrag "Bit folge einlesen"
Und jetzt sind mir da zwei Fragen in den Sinn gekommen.
Angenommen, ich hätte diesen Code:
1
:
2
unsignedlongvar=0xFFFFFF00;
3
:
4
while(var&0x8000000){// solange, bis alle 0xFF durchgeschoben sind
5
IrgendeineWartefunktion();// warten, bis ein Bit eingelesen werden darf...
6
var=var|!!(PINC&1);// PinC 0 in '0' oder '1' wandeln über doppelte Negation
7
var<<1;// bereit für nächstes Bit
8
}
9
:
Da stellt sich mir gleich die Frage:
> while (var&0x8000000);
Was macht der AVR-GCC-Compiler daraus? Der muss m.E. ja nur das MSB des
longs vergleichen, bei den anderen 3 kommt sowieso 0 heraus. Ist der
Compiler so klug?
Und dasselbe nur in grün:
> var = var | !!(PINC&1);
Hier würde das Verodern des LSB ausreichen...
Bin schon mal gespannt auf eure Antworten...
BTW:
Ich probier das gerade an einem Tasking C167-Compiler (16 Bit),
an den WinAVR komme ich leider erst am Wochenende wieder ran :-(
Lothar Miller wrote:
> Da stellt sich mir gleich die Frage:>> while (var&0x8000000);> Was macht der AVR-GCC-Compiler daraus? Der muss m.E. ja nur das MSB des> longs vergleichen, bei den anderen 3 kommt sowieso 0 heraus. Ist der> Compiler so klug?
Das ist keine Frage an ein Forum, sondern eine Frage an den Compiler.
> eine Frage an den Compiler...
Ja, ich habe den wie gesagt gerade nicht zur Hand,
und bis zum Wochenende hab ichs vergessen.
Danke, das wars:
> sbrc r25,3
Die ,3 kommt vom 2. Typo:
falsch: while (var&0x8000000) {
richtig: while (var&0x80000000) {
Dann wäre auch wie gewünscht *sbrc r25,7* herausgekommen.
Dann bleibt nur noch die zweite Frage:
> var = var | !!(PINC&1);
Wie kommt das Bit in die Variable?
Ich werde die Frage dann dem Compiler am Wochenende stellen,
aber wenn jemand gerade einen zur Hand hat....
Der Tasking-C167 macht das übrigens so (obiger Code, P5.0 ist
Eingangspin, ohne Warteschleife, mit Optimierung -Os):
1
JMPR cc_UC,_101
2
_99:
3
MOV R8,P5
4
JB R8.0,_144 // Pin
5
JMPR cc_UC,_145
6
_144:
7
MOV R8,#01h // '1' <<<<<<<<<
8
JMPR cc_UC,_146
9
_145:
10
MOV R8,#00h // '0' <<<<<<<<<
11
_146:
12
MOV R9,#00h <<<<<<<<<
13
OR R6,R8 // verodern Low <<<<<<<<<
14
OR R7,R9 // verodern Hi <<<<<<<<<
15
ADD R6,R6 // shift per Addition
16
ADDC R7,R7 // shift per Carry-Addition
17
_101:
18
JB R7.15,_99 // schon fertig? while()
Die while-Abfrage ist also gleich schnell erledigt (Bit-Abfrage),
das Einlesen des Portpins macht aber recht viel Aufwand.
<<<<<<<<< Statt dieser Befehle (oben)
würde eigentlich ein sbr reichen, 0 ist das Bit ja bereits.
So, quasi:
1
JMPR cc_UC,_101
2
_99:
3
MOV R8,P5
4
JNB R8.0,_144 // Pin
5
SBR R6.0 // '1' <<<<<<<<<
6
_144:
7
ADD R6,R6 // shift per Addition
8
ADDC R7,R7 // shift per Carry-Addition
9
_101:
10
JB R7.15,_99 // schon fertig? while()
Aber immer noch besser ein suboptimaler Compiler, als alles von Hand
hinzuassemblieren ;-)
Stefan Ernst wrote:
> Besseren (bzw. den besten) Code bekommst du mit:> if (PINC & 1) var |= 1;>
1
> 70: 98 99 sbic 0x13, 0 ; 19
2
> 72: 81 60 ori r24, 0x01 ; 1
3
>
>> Wie kommt das Bit in die Variable?>>
1
>> var = var | !!(PINC&1); // PinC 0 in '0' oder '1' wandeln über
2
>>
Zwar hübbsch hinzuschreiben, aber ungeschickt, weil das auf 32-Bit-Ebene
ausgewertet wird. Das ist gut auf Maschinen, wo Sprünge teuer sind und
32-Bit-Operationen nix kosten.
>wo Sprünge teuer sind und 32-Bit-Operationen nix kosten.
Richtig, ich hatte das ursprünglich für den ColdFire (32Bit) gemacht,
da sah das recht elegant aus. Aber schon beim C167 (16) ist diese
Kurzschreibweise fraglich und beim AVR (8) tödlich... :(
Na gut, dann werde ich mir wieder ein paar neue Programmierregeln für
den AVR anlegen müssen.
Danke für eure Zeit.