Hier entzaubere ich (wenn ich es denn wirklich richtig verstanden habe) die CodeZeile
pinWrite(DATA, (val & (1 << i)));
aus dem TI Shiftregister Beispielquellcode.
Die Bemühungen Hardwarenah mit C und Assemblerbefehlen zu Programmieren stellen sich als Tortour heraus. Ich habe nun einige Versuche mit dem TI 430 Launchpad gemacht und dabei aus den guten Beispielen auf den TI Seiten funktionierende Aufbauten in Gang gebracht. Viele Zeilen des Codes verstehe ich nur teils oder gar nicht. Ich versuche nun Anhand von Recherche den Programmablauf zu verstehen.
Der Code den ich meine ist hier zu finden:
http://processors.wiki.ti.com/index.php/MSP430_Launchpad_Shift_Register (externer Link)
Damit wird ein Shiftregister angesteuert. Ein Shiftregister funktioniert so, daß durch drei erforderliche Leitungen eine Zahl an das Register übergeben wird die die jeweiligen Pins des Shiftregisters HIGH oder LOW schaltet. Dabei wird bei einem 8-Bit Shiftregister eine Zahl zwischen 0 und 255 übergeben. Das geschieht Binär (Die Zahl wird binär aus acht Stellen dargestellt welche 0 oder 1 sein können).
In dem Codebeispiel gibt es folgenden Absatz:
for (i = 0; i < 8; i++) { pinWrite(DATA, (val & (1 << i))); pulseClock(); }
Dies nun Zeile für Zeile erklärt:
for (i = 0; i < 8; i++) {
Es ist der Beginn einer for Schleife welche für die Variable i von Null beginnend den Wert bei jedem Durchlauf um Eins erhöht (i++ = erhöhe i um Eins) solange i kleiner als Acht ist.
for Schleifen prüfen die nach dem for in runden Klammern gesetzten Bedingungen. Sind diese noch innerhalb der Vorgaben die dort gemacht wurden, wird der Code innerhalb der geschweiften Klammern ausgeführt.
Nun kommt die für mich kryptische Zeile:
pinWrite(DATA, (val & (1 << i)));
Die Zeile führt die Funktion pinWrite() durch welche im Programm auch definiert ist und später von mir erläutert wird. Sie gibt dabei die Werte DATA (Ist im Programmkopf als Port 1.0 definiert) und val & ( 1 << i ) (für mich als Laie vollkommen unverständlich) an die Funktion weiter.
val ist der Wert der in der Funktion shiftOut() mitgegeben wurde. Er bestimmt letztendlich welche Ports 1 und welche 0 sein sollen.
Zur Erinnerung, der Wert liegt bei einem 8-Bit Register zwischen 0 und 255, und wird Binär acht Stellen umfassen.
Ein Beispiel dazu verdeutlicht das ganze. Man stelle sich dazu die Folge von acht Zahlen als die Ports vor. o bedeutet der Port ist aus (also LED aus z.B.) und x bedeutet der Port ist an . So kann man leicht die gewünschten Ports aktivieren indem man die Summe der Bits bildet die leuchten sollen. Es kann dabei sein, dass die Reihenfolge exakt umgekehrt (links<>rechts) ist, je nachdem wie rum das Register arbeitet.
Bit8 | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Summe | |
Wert | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 255 |
x | o | o | o | o | o | o | o | 128 | |
x | o | x | o | o | o | o | o | 160 | |
o | o | o | o | o | x | o | x | 5 |
Als nächstes findet man das Zeichen & welches ein Operator ist der sich UND nennt. Dieser macht folgendes. Er vergleicht den Wert davor und danach und gibt eine 0 aus wenn die Werte beide 0 sind oder einer davon 1. Er gibt eine 1 aus wenn beide 1 sind.
Klingt erstmal seltsam, erschliesst sich aber wenn man es bildlich darstellt. Das mache ich aber erst gleich nachdem ich das (1 << i) erklärt habe.
Das << steht für bitweises Verschieben. Wobei es in Klammern steht damit dies gemacht wird bevor der & Operator es mit val vergleicht. i ist dabei die Variable aus dem Schleifenkopf. Sie wird also mit 0 beginnen und schließlich mit 7 enden, Also genau Acht mal, da es acht Ports sind die wir schalten wollen.
Das Bitschieben lässt sich am besten Binär verstehen. Hier eine kleine Tabelle dazu:
Bit8 | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Summe | |
Wert | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 255 |
o | o | o | o | o | o | o | x | 1 | |
o | o | o | o | o | o | x | o | 2 | |
o | o | o | o | o | x | o | 0 | 4 | |
o | o | o | o | x | o | o | 0 | 8 | |
o | o | o | x | o | o | o | 0 | 16 | |
o | o | x | o | o | o | o | 0 | 32 | |
o | x | o | o | o | o | o | 0 | 64 | |
x | o | o | o | o | o | o | 0 | 128 |
Bit8 | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Summe | |
Wert | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 255 |
Gewünschte Leuchtreihenfolge | x | x | o | o | o | o | x | x | 195 |
Schleifendurchlauf | |||||||||
1 | o | o | o | o | o | o | o | x | 1 |
2 | o | o | o | o | o | o | x | o | 2 |
3 | o | o | o | o | o | x | o | 0 | 4 |
4 | o | o | o | o | x | o | o | 0 | 8 |
5 | o | o | o | x | o | o | o | 0 | 16 |
6 | o | o | x | o | o | o | o | 0 | 32 |
7 | o | x | o | o | o | o | o | 0 | 64 |
8 | x | o | o | o | o | o | o | 0 | 128 |
pulseClock();
Das startet die Funktion pulseClock(); die die Information des aktuellen Schleifendurchlaufs (also ob 0 oder 1) an das Register durchgibt.
Das erkläre ich sobald ich es verstanden habe.
1 Pingback