Hallo allerseits,
ich habe hier im Forum vor kurzem folgende Beispiel-Routine für eine
ADC Wandlung am AVR bekommen:
ADCRead:
sbis ADCSRA,ADEN
rjmp ADCEnable
sbic ADCSRA,ADSC
ret
in r16,ADCL
in r17,ADCH
sts ADCVal,r16
sts ADCVal+1,r17
sbi ADCSRA,ADSC
ret
ADCEnable:
ldi r18,0b01<<REFS0|0<<ADLAR|0b00000<<MUX0
out ADMUX,r18
ldi r18,1<<ADEN|1<<ADSC|0b0111<<ADPS0
out ADCSRA,r18
ret
Soweit habe ich alles fleißig analysiert und nachvollzogen. Leider habe
ich allderdings noch nicht ganz kapiert, welche Vorgänge bei folgenden
Zeilen passieren, und warum sie so sinnvoll sind:
"ldi r18,0b01<<REFS0|0<<ADLAR|0b00000<<MUX0"
und
"ldi r18,1<<ADEN|1<<ADSC|0b0111<<ADPS0"
Könnte mir hier jemand im Klartext mitteilen was es mit diesen Zeilen
auf sich hat (z.B. 0b00000<<ASPS0 ??)?
Vielen Dank schon mal.
Gruß
Jan Purrucker
Diese "shift-Schreibweise" ist bei den Programmierern in diesem Forum
aus mir nicht nachvollziehbaren Gründen äußerst beliebt.
Die Konstanten ADEN, ADSC etc. sind numerische Werte, die die Nummer
eines Bits in einem Register angeben.
Mit "1 << ADEN" wird ein Wert erzeugt, der einer 1 in dem
betreffenden Register entspricht.
Mal angenommen, ADEN wäre 4, wird "1 << ADEN" also ersetzt durch "1
<< 4", was also 16 bzw. 0x10 enspricht.
"0b0111 << ADSP0" bedeutet, daß der Wert 7 um eine bestimmte Anzahl
an Bits verschoben wird; angenommen, daß ADSP0 2 wäre, entspräche das
Konstrukt also
"7 << 2", was wiederum 0x1C enspricht.
Was sich der findige Programmierer beim Konstrukt
"0b01<<REFS0|0<<ADLAR|0b00000<<MUX0"
gedacht hat, das mag nur er selbst wissen - das enspricht nämlich
direkt
"0b01<<REFS0"
bzw.
"1 << REFS0"
da "0 << egalwas" immer 0 ist. Und "wasauchimmer | 0" bleibt
"wasauchimmer".
Sieht allerdings ungemein beeindruckend aus.
Warum nicht in der betreffenden Headerdatei statt Bit_nummern_
Bit_werte_ definiert werden können, wie es anderswo üblich ist, habe
ich bislang nicht nachvollziehen können.
Vielleicht kann mir ja jemand mal ein Argument nennen, das das
erklärt.
Ein Konstrukt, das nach der Bitnummernschreibweise so geschrieben würde
(C-Syntax):
#define BIT1 1
#define BIT2 2
wert = (1 << BIT2) | (1 << BIT1);
sähe "bei mir" so aus:
#define BIT1 0x2
#define BIT2 0x4
wert = BIT1 | BIT2;
"Vielleicht kann mir ja jemand mal ein Argument nennen, das das
erklärt."
Lies Dir mal ein x-beliebiges *def.inc durch, da ist das am Anfang
erklärt.
Es gibt beim AVR nämlich Befehle, die mit der Bitnummer arbeiten (0..7)
und manche aber mit dem Wert (0x01..0x80).
Und damit man Symbole für beides verwenden kann, wird immer die
Bitnummer definiert.
Ein 0x80 in eine 7 umzuwandeln ist nämlich nicht so einfach.
Und für C wurde das dann einfach so übernommen.
0b00000 zu schreiben ist aber in der Tat Schwachsinn, entweder 0 oder
den Ausdruck ganz weglassen.
Peter
Peter, danke für die Aufklärung:
"Es gibt beim AVR nämlich Befehle, die mit der Bitnummer
arbeiten (0..7) und manche aber mit dem Wert (0x01..0x80)."
Das ist in der Tat ein Argument.
Ich muss gestehen, den AVR nie in Assembler programmiert zu haben; und
die Prozessoren, bei denen ich das gemacht habe, wiesen diese
Besonderheit nicht auf, da sie - von einer Ausnahme abgesehen, auch
nicht über die Fähigkeit der Bitadressierbarkeit verfügten, wo das ja
wohl nötig ist. Waren halt weitestgehend keine µC.
(Beim MCS51 ist's einfach zu lange her, als daß ich mich um die
Uhrzeit noch daran erinnern könnte, muss aber wohl auch so sein)
Ja, beim 8051 ist das auch so, z.B.:
setb 080h
..
setb 087h
setzen die Bits 0 .. 7 des Registers 080h
orl 080h, #001h
..
orl 080h, #080h
machen genau das gleiche, sind aber ein Byte und ein Zyklus länger,
gehen dafür auch für die Adresse 081h. Bitbefehle gehen nur für die
Register 080h, 088h, 090h usw.
Peter