hallo
ich verstehe folgenen C-Coden nicht
while(EECR & (1<<EEWE));
es geht darum das bit EEWE im register EECR zu prüfen, aber wie
funktioneiert das mit dem schiebebefehl und dem UND operator?
kann man das bit nicht direkt abfragen??
In der Schleife wird die um ein paar Stellen nach links verschobene 1
solange mit dem EECR Register UND verknüpft, bis das Ergebnis Null ist.
Also das Bit nicht mehr gesetzt.
Im Prinzip wird das Register bis auf das EEWE Bit gelöscht und bei
dieser Aktion gleich geschaut, ob es dann 0 oder eben was anderes ist.
Bits kann man nicht direkt abfragen. Ein µC kann im innersten Kern nix
andres als addieren, Bits schieben, und dann immer Flags setzen (Zero,
Carry....)
anfänger wrote:
> hallo>> ich verstehe folgenen C-Coden nicht>> while(EECR & (1<<EEWE));>>> es geht darum das bit EEWE im register EECR zu prüfen, aber wie> funktioneiert das mit dem schiebebefehl und dem UND operator?> kann man das bit nicht direkt abfragen??
EEWE ist eine Zahl, die angibt, das wievielte Bit (rechts wird
mit 0 zu zählen angefangen) im Register gemeint ist.
Nehmen wir mal an, EEWE hätte den Wert 3.
Wenn du nun eine 1 nimmst Binär 00000001
und diese 1 genau 3 mal nach
links schiebst
Binär 00001000
dann erhältst du eine Binärzahl, die genau an der Bitposition
3 (von rechts beginnen zu zählen, mit 0 beginnen zu zählen)
eine 1 aufweist.
Das ist die Maske die für die UND Verknüpfung benutzt wird.
Das &, als binäre Operation wirkt bitweise auf seine beiden
Operanden.
Dh. in
EECR & 00001000
wird jedes einzelne Bit von EECR mit dem jeweils korrespondierendem
Bit in der Maske 00001000 UND verknüpft.
Die Logiktabelle für UND sieht so aus
A B A und B
0 0 0
1 0 0
0 1 0
1 1 1
Was auffällt: Wenn B 0 ist, dann ist der Ergebnis auf jeden Fall 0.
Wenn B aber 1 ist, dann ist das Ergebnis identisch zu A.
Angewendet auf die Maske 00001000 bedeutet das, das alle Bits
bei denen in der Maske eine 0 steht im Ergebnis auf jeden Fall
0 sind. Nur dort wo in der Maske eine 1 steht, ist das Ergebnisbit
identisch mit dem Bit vom anderen Partner der UND Operation.
In Summe
EECR & 00001000
setzt im Ergebnis also alle Bits bis auf Bit 3 definiert auf 0.
Ob Bit 3 des Ergebnisses 0 oder 1 ist, hängt davon ab, ob das Bit 3
in EECR 0 oder 1 ist.
> kann man das bit nicht direkt abfragen??
Das ist die C-Schreibweise für eine Bit Abfrage.
Der Compiler erkennt dieses und ersetzt den kompliziert anmutenden
Ausdruck durch die entsprechenden Bit Befehle in Assembler, so es
möglich ist. Aber in C ist die kleinste Einheit nun mal ein konmplettes
Byte.
> Bits kann man nicht direkt abfragen.
nana, so kann man das nicht stehen lassen.
Man kann Bits schon direkt abfragen - das Problem ist, dass C keine
Bit-Datentyp kennt. Deshalb dieses Konstrukt. Jeder halbwegs brauchbare
Compiler wird dieses auf einen Einzelbit-Befehl (sbic/sbis)
zurückführen.
Einige Compiler können dies dennoch, ist dann aber nicht mehr ANSI-C.
CodeVision:
if (EECR.EEWE)....
Naja, Lesbarkeit....dies (1<<EEW) Konstrukt is auch nich auf den Ersten
Blick erkennbar.
Beim mspgcc ist in den Headern immer gleich die 0x20 oder 0x1000 oder
was auch immer in den defines, da kann man dann einfacher (und meiner
Meinung nach verständlicher) schreiben:
while(EECR & EEW);
Die Aussage, dass man Bits nicht direkt abfragen kann, bezog sich auf
Ansi-C.
und um das klar herauszustreichen:
1 << EEWE ist genauso eine 'fertige Maske' wie 0x02. Soll
heissen, das beides zum exakt gleichen Code führt.
Nur, wie F. Kriewitz bereits sagte, wenn beim nächsten µC
aus der selben Prozessorfamilie, EEWE plötzlich nicht mehr
an Bitposition 2 anstelle von 1 liegt, dann brauchst
du bei 1 << EEWE gar nichts tun, der Compiler erledigt das
Aufsetzen der neuen Maske. Während bei einer direkten Angabe
von 0x02 der Programmierer dafür verantwortlich ist, dass
die 0x02 gegen 0x04 ausgetauscht wird. Du ahnst schon worauf
das hinausläuft: Im Zweifelsfall lasse ich den Compiler die
Arbeit machen, denn der vergisst nichts :-)
anfänger wrote:
> Warum nimmt man denn nicht eine "fertige Maske", z.B.>> while(EECR & 0x02);
Man hätte EEWE natürlich als Maske definieren können, so hätte das
wohl jeder C-Programmierer geschrieben:
...
#define EEWE 0x02
...
while (EECR & EEWE) /* wait */;
Aber: all diese Namen sind nicht von C-Programmierern erfunden worden,
sondern von Atmel selbst, und sie sollen auch den
Assemblerprogrammierern von Nutzen sein. Da der AVR nun auch noch
CPU-Befehle hat, in denen nicht mit einer Bitmaske sondern mit einer
Bitnummer gearbeitet wird, sind sämtliche IO-Bits als Bitnummern
deklariert. Für C muss man sie daher in eine Maske umwandeln, indem
man (fiktiv, nur für die Compilierung) eine 1 um die entsprechende
Bitnummer nach links schiebt. Wie Karl Heinz schon anmerkt, ersetzt
der Optimierer das letztlich durch die Maske -- oder aber (im Falle
des AVR) durch die Bitnummer im entsprechenden
SBI/CBI/SBIR/CBIR-Befehl. Letztere muss sich der Optimierer aber aus
der Bitmaske zurück berechnen. ;-)
Mangels eines Datentypen wird ein schwer lesbares Konstrukt in eine
unpassende Anweisung uebersetzt. Falls der Optimierer nun klug genug
ist, ersetzt er dieses Bytecommands durch ein Bitcommand. Seltsamerweise
haben fast alle Controller Singlebit Befehle, und C fand in den
vergangenen 20 Jahre noch nicht zum Singlebit Datentypen. Man koennte
fast meinen C passt nicht zu Controllern und will es auch nicht. ==> in
den Kuebel damit.
Das Leben ist zu kurz und zu muehsam um sich mit C zu plagen.
Na ja, die C-Hasser können sich ja in BASIC, Pascal, FORTRAN, COBOL,
Modula, ADA, Smalltalk, Lisp, Forth, Python oder Java austoben... so
kommt man sich auch nicht ins Gehege... ;) Viel Spaß damit!