Navigation
Disco!

Den Sourcecode für unsere Mini-Disco gibt es hier. Im Hauptprogramm fällt bei der Pinkonfiguration in Zeile 24 auf, dass P1.2 nicht als GPIO, sondern als Timer_A benutzt wird. Dies ist nötig, um einfach und komfortabel eine PWM erzeugen zu können. Natürlich könnte man auch mit einem "normalen" I/O-Pin eine Rechteckspannung erzeugen, dies wäre aber relativ rechenaufwendig. Der Timer erledigt dies quasi im Hintergrund vollautomatisch. Details hierzu gibt's gleich ...

Ebenfalls neu ist Zeile 28, da wir ja mittlerweile 3 Ports des A/D-Wandlers benutzen (das Poti, der NTC und das Mikrofon). Alle weiteren Initialisierungen (Systemtakt, USART, A/D-Wandler, LCD) sollten mittlerweile bekannt sein. Die eigentlichen Mikrofon-Routinen werden in Zeile 69 in einer Endlosschleife aufgerufen.

Schauen wir uns die Funktion doMicroStuff() doch mal näher an: Wir sehen, dass als erstes eine A/D-Wandlung gestartet wird und das Ergebnis von P6.2 (dort hängt ja die Mikrofonschaltung dran) vom Register ADC12MEM2 in eine Hilfsvariable micro_double geschrieben wird. (Kurze Anmerkung zwischendurch: Aus Bequemlichkeit habe ich die anderen beiden belegten Ports am A/D-Wandler nicht aus dem Sourcecode heraus genommen. Wie man in der Konfiguration des A/D-Wandlers in den Zeilen 57 bis 62 sieht, konvertiert der MSP430 fortlaufend alle drei Ports (P6.0 bis P6.2). Das ist natürlich völlig überflüssig, soll uns hier aber nicht weiter stören. Die Konvertierung eines Kanals dauert nur wenige µs, sodass die für die beiden anderen Kanäle verschwendete Zeit für die Lichtorgel völlig irrelevant ist.)

Die Zeilen 91 bis 99 sollten selbsterklärend sein; zu Debug-Zwecken könnt ihr die auskommentierten Zeilen auch wieder einbauen, um die Werte des A/D-Wandlers auf dem LCD auszugeben oder per USART an einen PC zu schicken. Dies wird z.B. sicherlich nötig sein, um den Zahlenwert 2630 an euer Mikrofon anzupassen -- es wäre nämlich reiner Zufall, wenn eure Schaltung genau dieselben Spannungsabfälle erzeugt wie meine.

In Zeile 100 wird schließlich die Funktion doLEDStuff() aufgerufen, und zwar mit micro_int als Parameter. Durch die bis hier erfolgten Umrechnungen ist auf jeden Fall sichergestellt, dass micro_int in den Wertebereich zwischen 0 und 511 fällt. Der Trick hierbei ist nun, dass man quasi einen auf 511 normierten Duty-Cycle als Parameter übergibt: Ist micro_int beispielsweise 128, so wird eine PWM mit einem Duty-Cycle von 128/511=25% erzeugt, bei micro_int = 384 ist der Duty-Cycle 384/511=75% usw.

Konkret funktioniert die Funktion doLEDStuff() wie folgt: In das Register CCR0 wird die Periodendauer des zu erzeugenden Rechtecksignales geschrieben, hier 511. Bei einem Systemtakt von 8 MHz entspricht dies ca. 64 µs. In CCR1 landet die On-Zeit des Signals (siehe Beispielrechnungen oben). Die Anweisung TACTL = TASSEL_2 + MC_1; legt die Timer-Clock sowie den Zählmodus fest. Wir wählen hier den Up-Mode, was besagt, dass der Timer einfach immer weiter von 0 bis 512 zählt und dann wieder von vorne anfängt.

Der Befehl CCTL1 = OUTMOD_7; definiert den zu benutzenden Timer-Modus. Wie man dem schon mehrfach zitierten User Guide zum MSP430 im Abschnitt 11-13 entnehmen kann, benutzen wir hier also den reset/set-Mode. Dies bedeutet, dass der Port P1.2 auf high gelegt wird, sobald der Timer den Wert 512 erreicht (und ja dann wieder bei Null anfängt). Erreicht der Timer den in CCR1 abgelegten Wert (den wir ja als Parameter übergeben haben), wird P1.2 low. Somit erzeugen wir höchst komfortabel eine PWM: Da der Timer ja völlig autonom arbeitet, können wir ungestört unser Hauptprogramm weiter abarbeiten -- der Timer wird bis in alle Ewigkeit von 0 bis 512 zählen und parallel jedesmal, wenn er einen bestimmten Wert (CCR1) überschreitet, P1.2 toggeln.

Da das alles sehr theoretisch klingt, habe ich mal versucht, ein Beispiel mit einem Duty-Cycle von 75% (384/512) grafisch darzustellen:


Man erkennt, dass die LED an Port P1.2 solange mit 3,3 Volt versorgt wird, solange der Timer noch nicht bei 384 angekommen ist. Sobald er 384 erreicht, geht P1.2 auf low und es liegt keine Spannung mehr an der LED. Wenn der Timer nach ca. 64 Mikrosekunden 512 erreicht, beginnt das Spiel von vorne. Das alles geschieht so schnell, dass das Auge kein Flackern, sondern eine konstante Helligkeit der LED wahrnimmt. Man sollte noch beachten, dass sich die subjektiv empfundene Helligkeit nicht wirklich linear, sondern schon eher quadratisch mit dem Duty-Cycle ändert. Bei doppelt so großem Duty-Cycle empfindet das Auge die LED also auf jeden Fall mehr als doppelt so hell.

Tja, jetzt haben wir also mit viel technischer Spielerei das erreicht, was wir auch in Analogtechnik viel einfacher hätten realisieren können. :-) Aber durch diese Schaltung ist es jetzt ohne weiteres möglich, kompliziertere Szenarien zu entwerfen. So wäre z.B. eine Lauflichtsteuerung mit mehreren LEDs denkbar, wobei der "Umschaltzeitpunkt" zur nächsten LED von der Musik abhängt. D.h., immer wenn micro_int (also der an P1.2 anliegende Pegel) größer ist als x (wobei x in meinem Aufbau als ca. 40 gewählt werden könnte), soll zur nächsten LED geschaltet werden. Solch eine Steuerung ist analog schon quasi nicht mehr realisierbar.

Ein weiteres Manko ist natürlich die Dimension unserer Lichtorgel: Eine LED erhellt eine Tanzfläche nicht so richtig hell ... ;-) Um hier Abhilfe zu schaffen, schauen wir uns im nächsten Kapitel mal an, wie man mit dem MSP430 und ein paar Triacs und Optokopplern ganz komfortabel Verbraucher mit 230 Volt (z.B. eine Lampe) schalten und dimmen kann. So werden wir uns einen kompletten Lichtcomputer bauen, wie er nicht wesentlich anders in jeder Disco benutzt wird. Nur, dass er da viele Hundert Euro kostet ...