Diese Seite schrieb ich für mich selbst und für alle, die sich ebenfalls für AVR Mikrocontroller interessieren, aber noch keine oder wenig Ahnung haben. Dies ist eine Einführung vom Anfänger für Anfänger, ich habe allerdings schon einige Jahre mit anderen Mikrocontrollern gearbeitet.
Auf den folgenden Seiten lernen Sie, wie man AVR Mikrocontroller benutzt. Anhand eines kleinen elektronischen Spiels lernen Sie in vielen kleinen Schritten, einen AVR Mikrocontroller zu programmieren. Sie lernen auch den Umgang mit dem AVR Assembler, sowie dem Simulator und der Software zum Programmiergerät.
Ein Mikrocontroller ist ein ganzer Computer in einem einzigen Chip. AVR Mikrocontroller beinhalten eine CPU, diverse Ein-/Ausgabe Module, Taktgeber, Watchdog, RAM, Flash-ROM und EEPROM. Es gibt sehr unterschiedliche Größen von AVR, so daß für jeden Anwendungsfall ein passender Chip angeboten wird.
Ich habe mich für AVR Mikrocontroller entschieden, weil man kein teures Programmiergerät braucht, und weil alle nötige Software und Dokumentation kostenlos zur Verfügung gestellt wird. Ich finde bei diesen Chips auch ganz toll, daß man meistens weder einen Quartz noch eine Reset-Schaltung braucht.
Der Kern ist eine RISC-CPU (Reduced Instruction Set Core Central Processing Unit), die für C Compiler optimiert wurde. Natürlich kann man die CPU auch in Assembler oder anderen Sprachen programmieren. Wer schon andere Mikrocontroller kennt, den wird sicher beeindrucken, daß der berühmte Akkumulator durch 32 universell verwendbare Register ersetzt wurde.
Das Flash-ROM enthält den Programmcode. Das EEPROM ist für häufiger veränderliche Daten gedacht, es ist klein, dafür aber mindestens 10x häufiger beschreibbar.
Die Datenblätter der AVR Mikrocontroller, sowie die Entwicklungsumgebung AVR Studio für Windows kann man beim Hersteller Atmel kostenlos downloaden. AVR Studio sieht so aus:
Wer in C/C++ programmieren möchte, benötigt zusätzlich noch WinAVR, was ebenfalls kostenlos ist. AVR Studio bettet den C-Compiler in die grafische Oberfläche ein. AVR Studio beinhaltet einen Editor für den Programmquelltext, einen Simulator/Debugger, einen Assembler und ein Brennprogramm.
Eine Einsteigeranleitung für die Programmierung in Assembler gibt es hier.
Eine Einsteigeranleitung für die Programmierung in C gibt es hier.
Die kleinsten AVR Mikrocontroller haben 8 Pins, davon können 5 Pins für Ein/Ausgabe verwendet werden.
Der ATmega8515 hat 40 Pins, er unterstützt den Anschluß von externer Peripherie mittels 16-bit Adressbus und 8-bit Datenbus.
Andere Varianten haben wiederum analoge Eingänge, unterschiedliche serielle Schnittstellen, oder sind gar imstande ihren eigenen Programmspeicher zu flashen (auch als Firmware-Upgrade bekannt).
Für einen raschen Vergleich habe ich die PIN-Belegungen und die Features in einer Tabelle zusammengefasst. Die Tabelle enthält nicht alle AVR Mikrocontroller, sondern nur diejenigen, die für mich interessant sind. Die Tabelle ist hier im Excel und im Open Document Format hinterlegt.
Mit dem Simulator innerhalb vom AVR Studio kann man Trockenübungen durchführen. Um das Programm in einen "echten" Chip hinein zu bekommen, muss er mit dem PC verbunden werden. Zu diesem Zweck sind AVR Controller mit der sogenannten ISP (in-system programming) Schnittstelle ausgestattet, durch die der Chip sowohl lose als auch direkt in der Schaltung auf der Platine programmiert werden kann. Die ISP Schnittstelle besteht aus vier Signalen: /Reset, SCK, MISO und MOSI. Üblicherweise befinden sich auf den Platinen 6-Pin Pfostenstecker, an die man das Programmiergerät anschließt. Ältere Geräte haben 10-Pin Pfostenstecker:
|
Die VCC Leitung kann verwendet werden, um sehr kleine Schaltungen mit Spannung zu versorgen. Normalerweise hat jedoch jedes Gerät seine eigene Spannungsversorgung.
Normalerweise werden Sie den Chip allerdings innerhalb der Schaltung programmieren. Dazu wird Ihre Schaltung einen ISP Stecker haben. Sie können die drei Leitungen SCK, MISO und MOSI für gewöhnliche Ein-/Ausgabe verwenden. Nur während des Zurücksetzens (also /Reset auf Low), sind diese drei Leitungen im Sinne der ISP Schnittstelle aktiv. Und genau darum kann der Chip im System programmiert werden, zum Beispiel so:
Wegen der Doppelbelegung der Leitungen /Reset, MISO, MOSI und SCK, sind ein paar Dinge zu berücksichtigen, die ich am obigen Beispiel-Schaltplan erklären möchte.
Bei allen Eingängen müssen Sie den Rest der Schaltung durch Widerstände trennen (R2, R3, R4). So kann der ISP Programmer vorrangig Signale an den AVR Mikrocontroller senden, egal was der Rest der Schaltung gerade macht.
MISO wird während des Programmiervorganges vom AVR Mikrocontroller angetrieben. Der AVR Mikrocontroller kann erheblich höhere Ströme liefern, als ISP-Programmiergeräte. Darum kann beim MISO Signal kann die LED 2 ohne besondere Vorkehrungen direkt angeschlossen werden.
Bei /Reset, MOSI und SCK ist wichtig, daß Sie das antreibenden ISP-Programmiergerät nicht überfordern. Die LED 1 wurde bewusst nicht direkt angeschlossen, weil das ISP-Programmiergerät durch die LED überlastet werden würde. Der Transistor behebt dieses Problem.
Bei jedem PIN, den Sie im Normalbetrieb als Ausgang verwenden, sollten Sie beachten, daß der ISP-Programmierer Signale sendet. Was sonst noch an diesen PIN's hängt, muss dies tolerieren. Im obigen Beispiel haben wir nur LED's die beim Programmieren unerwünscht flackern, das schadet sicher niemandem.
Achten Sie beim /Reset PIN darauf, daß der Trenn-Widerstand R2 ungefähr 4,7k Ohm hat. Bei zu hohem Wert funktioniert das Reset Signal der Schaltung nicht, bei zu niedrigem Wert überlasten Sie den ISP-Programmierer.
Achtung Falle:
Durch ungeschickte Programmierung der Fuse-Bits kann man die ISP Schnittstelle ungewollt und unreparabel deaktivieren. Folgende Einstellungen sollten Sie vermeiden:
Um den ISP Stecker mit dem Computer zu verbinden, benötigt man ein Programmiergerät und dazu eine passende Software. Da unzählige Programmiergeräte zu sehr unterschiedlichen Preisen angeboten werden, fällt es dem Anfänger schwer, ein passendes Gerät auszuwählen.
Am billigsten ist es, den Mikrocontroller direkt an den echten Parallel-Port des PC anzuschließen und das Programm PonyProg zu benutzen. Das folgende Foto zeigt ein solches Kabel. Am Ende hat es sowohl den oben genannten 6-Pin Stecker, als auch den älteren 10-Pin Stecker.
In folgenden Fällen funktioniert das Kabel nicht:
Etwas professioneller ist ein sogenannter ISP Programmer oder AVR910 kompatibler Programmer welchen man für 20-30 Euro kaufen kann.
Es wird an den USB Anschluß angeschlossen und mit dem Programm Avr Osp II benutzt. Gegenüber einer direkten Verbindung mit dem Parallel-Port bietet dieses Gerät folgende Vorteile:
Mittlerweilen werden im Handel zahlreiche preisgünstige Experimentierplatinen angeboten, vor allem bei Ebay und bei dem Versandhandel Pollin. Suchen Sie nach den Stichworten "AVR Board" oder "AVR Experimentier" oder "AVR Evaluation". Das Angebot wechselt alle paar Wochen.
Mein erstes Gerät soll ein Nachbau des Spiels "Senso" werden. Das Spiel könnte so aussehen:
Oder so:
Die vier Tasten sind beleuchtet und das Teil kann Musik von sich geben. Jeder Taste ist ein bestimmter Ton zugeordnet, wie bei einem Mini-Klavier. Ein Zufallsgenerator erzeugt eine kurze Melodie, die der Spieler nachspielen muss. Bei Erfolg, wird die Melodie um einen Ton verlängert, der Spieler muss sie erneut nachspielen. Je besser der Spieler ist, um so länger werden also seine Melodien.
Das Gerät besteht aus verblüffend wenig Bauteilen, deswegen ist es zum Erlernen der AVR Grundlagen sicher gut geeignet.
| Anzahl | 4,5V | 3V |
| 1 | Atmel Tiny13 | Atmel Tiny13V |
| 1 | IC Sockel 8-Pin | |
| 1 | Piezo Schallwandler | |
| 4 | Eingabetaster in rot, gelb, grün und blau | |
| 4 | LED's in rot, gelb, grün und blau | rote Low-Current LED's |
| 1 | Widerstand 100 Ohm | Widerstand 330 Ohm |
| 1 | Kondensator 100nF | |
| 1 | Batterien 3xAAA | Lithium Knopfzelle CR2032 |
| 1 | Batteriehalter dazu | |
| 1 | Gehäuse | |
| 1 | Stück Punktrasterplatine | |
Um Material zu sparen und die Schaltung so einfach wie möglich zu halten, habe ich ausnahmsweise keinen ISP Stecker vorgesehen. Verwenden Sie dazu die oben abgebildete OSP Schaltung, um den Chip direkt an den ISP Programmer anzuschließen.
Zur 3V Version: Die roten Low-Current LED's kommen mit weniger Spannung aus, als alle anderen Farben und sie brauchen weniger Strom. Das ist wichtig, weil Lithium Knopfzellen nur sehr geringe Ströme liefern können. Sie werden feststellen, daß die Batteriespannung unter der Last einer solchen Leuchtdiode schon auf etwa 2,5V abfällt. Genau darum brauchen Sie auch die Low-Voltage Version des Mikrocontrollers.
Wenn man eine der vier Tasten drückt, leuchtet die entsprechende LED und der Mikrocontroller empfängt ein "Low" Signal. Umgekehrt kann auch der Mikrocontroller die Led's einschalten. Da normalerweise immer nur eine LED von den vieren leuchten soll, können sie sich alle einen einzigen Vorwiderstand teilen. Hier wird sehr schön demonstriert, daß die I/O Anschlüsse des Mikrocontroller wechselweise sowohl als Eingang als auch als Ausgang verwendbar sind. Das Programm kann die Signalrichtung einfach umschalten.
Wenn man eine Taste loslässt, sollte der Mikrocontroller eigentlich ein eindeutiges "High" Signal empfangen, doch das ist zunächst nicht der Fall, weil an den LED's zuviel Spannumg abfällt. Die Lösung besteht in den per Software zuschaltbaren Pull-Up Widerständen, welche sich quasi im Chip befinden:
Diese Pull-Up Widerstände haben einen Wert von etwa 50k Ohm und sorgen dafür, daß bei losgelassenem Taster ein eindeutiges "High" Signal erkannt wird.
Der Piezo-Schallwandler wirkt elektrisch wie ein Kondensator mit etwa 12nF Kapazität. Bei Gleichspannung fließt kein Strom, je höher die Frequenz ist, um so mehr Strom fließt und um so lauter wird er. Im Bereich 400-2000Hz ergibt sich eine angenehme Lautstärke.
Der /Reset PIN wird nicht benutzt, weil der Mikrocontroller intern schon ein Reset-Signal erzeugt. Selbst der Takt wird vom Chip intern erzeugt, so daß der sonst übliche Quarz entfällt.
Das Gerät benötigt keinen Ein/Aus Schalter, weil der Mikrocontroller im Power-Down Modus fast keinen Strom verbraucht. Bei der Programmierung werden wir den Power-Down Modus so oft wie möglich verwenden und außerdem die Taktfrequenz soweit wie möglich herabsetzen.
Das Programm setzt sich aus vielen kleinen Bausteinen zusammen, die alle einzeln ausprobiert werden. Dabei wird der Simulator im AVR Studio sehr hilfreich sein. Zum Schluß wird aus diesen Teilen das Spiel zusammengesetzt.
Wir werden nicht alle Funktionen des Tiny13 nutzen (z.B. den ADC Wandler). Nach dem Reset sind alle Register mit sinnvollen Standardwerten initialisiert. Mit uninteressanten Funktionen brauchen Sie sich daher auch nicht zu beschäftigen. Tun Sie einfach so, als würden diese Funktionen nicht existieren.
Starten Sie also das AVR Studio und beginnen Sie ein neues Projekt mit dem Namen Senso. Als Programmiersprache wählen Sie bitte den Atmel AVR Assembler. Als Debug Plattform wählen Sie den AVR Simulator und stellen das richtige Device (Tiny13) ein. Im Menü Tools/Optons/Editor ändern Sie die Tabulator-Breite auf 8.
Geben Sie dieses Programm ein.
#include "tn13def.inc" lädt Chip-Spezifische Einstellungen in den Assembler. Dieser Befehl erzeugt keinen Programmcode.
sbi ddrb,1 schaltet den Port B1 als Ausgang um, standardmäßig sind alle Pins Eingänge. Da das Port-Register PORTB standardmäßig auf 0 steht (also alle Bits auf Low) geht dadurch die Led an.
ende: rjmp ende ist eine Endlosschleife und bildet somit das Programmende. Ohne diesen Befehl würde der Mikrocontroller den unprogrammierten Rest des Programmspeichers abarbeiten. Ungenutzter Programmspeicher enthält je nach Programmiergerät Zufallswerte oder lauter 0xFF, so daß völlig unbestimmt ist, was passieren würde.
Drücken Sie Strg-F7, um den Simulator zu starten. Es erscheint ein gelber Pfeil vor dem ersten Befehl:
Drücken Sie F11, um das Programm Schrittweise auszuführen. Im Fenster links oben können Sie die Auswirkungen direkt nachvolziehen. Der Befehl sbi ddrb,1 setzt im Register ddrb das Bit 1 auf High, was als schwarzes Kästchen angezeigt wird.
Bewegen Sie den Cursor auf den sbi Befehl und drücken Sie F1. Es erscheint eine Beschreibung dieses Befehls. Schauen Sie bitte ins Datenblatt auf Seite 157, dort finden Sie die Übersicht der I/O Register. Wozu das Register ddrb gut sein soll, geht aus dieser Seite allerdings nicht hervor. Diese Beschreibung der einzelnen Register befinden sich in den vorherigen Seiten des Datenblattes, in diesem Fall ab Seite 42. Lesen Sie dieses Kapitel durch, von besonderem Interesse ist momentan der Absatz "Configuring the Pin" auf Seite 43 und die Seite 52.
Wenn Sie jetzt noch ein paar mal F11 drücken, sehen Sie, daß der letzte Befehl unendlich oft wiederholt wird.
Sie sollten bei allen weiteren Schritten ebenso das Datenblatt und die Hilfe zu Rate ziehen, um die verwendeten Befehle und Register kennen zu lernen.
Übertragen Sie das Programm in den Mikrocontroller, um es innerhalb der Schaltung zu testen.
Verbinden Sie die oben genannte OSP Schaltung mit dem ISP-Programmiergerät. Starten Sie Avr-Osp-II und Klicken Sie auf den Detect Knopf. Der name des Chips sollte erscheinen. Klicken Sie auf Erase Device um den Chip zu löschen. Klicken Sie dann auf Browse, um die *.hex Datei zu laden, die Sie mit dem AVR Studio erstellt haben. Durch den Program Knopf übertragen Sie das Programm in den Tiny13. Mit dem Verify können Sie den Erfolg überprüfen.
Verbinden Sie die oben genannte OSP Schaltung mit dem Parallel-Port Kabel. Starten Sie PonyProg. Falls Ihr PC (oder Notebook) Energiesparfunktionen hat, deaktivieren Sie diese jetzt. Wählen Sie den Menüpunkt Setup/Kalibrierung, und danach Setup/Hardware. Die Richtige Einstellung ist "Parallel, AVR ISP I/O". Die Polaritätswahl-Felder lassen Sie alle ausgeschaltet. Im Menü Device wählen Sie den Tiny13 (oder alternativ den Tiny12). Durch Befehl/Löschen löschen Sie den Chip. Laden Sie die *.hex Datei, die Sie mit dem AVR Studio erstellt haben, indem Sie den Menüpunkt Datei/Öffne Programm Datei wählen. Durch Befehl/Programm übertragen Sie das Programm in den Tiny13. Durch Befehl/Vergleiche Programm können Sie den Erfolg überprüfen.
Sie können den Chip jetzt auf dem Programmiersockel herausnehmen und in das Spiel stecken. Dann die Batterie einsetzen und: Led1 leuchtet. Wahnsinn :-)
Sorgen Sie dafür, daß der Chip Spannungsfrei ist, wenn Sie ihn aus einem Sockel ziehen oder einstecken. Falls Sie dafür zu faul sind, verwenden Sie dazu wenigstens ein isolierendes Werkzeug, damit Sie keinen Kurzschluß herbeiführen.
Folgendes Programm soll geschrieben werden:
Zunächst sollen alle Led's aus sein,
die Pull-up Widerstände sollen an allen vier Tastern aktiviert werden.
Das Programm soll warten, bis irgendeine Taste gedrückt wird.
Dann soll es die Led1 einschalten und sich beenden.
Geben Sie dieses Programm ein. Lesen Sie die Kommentare und vergleichen Sie die Befehle mit der Hilfe und den Datenblatt, um sie zu verstehen.
Der Audruck (1<<clkpce) setzt das Bit mit dem Namen clkpce. Hinter clkpce steht die Zahl 7 (weil Bit7). Der Ausdruckt schiebt die 1 sieben mal nach Links, das ergibt 128 oder 0b10000000. Ich hätte an dieser Stelle auch einfach 128 schreiben können, aber dann kann man nicht mehr so leicht erkennen, wie das Bit heißt.
Drücken Sie Strg-F7 und dann 10 mal F11. Sie sollten dann ungefähr folgendes Bild sehen:
Im linken I/O-View Fenster können Sie die Auswirkungen des Programmes nach dem ersten Durchlauf sehen. Am Register ddrb erkennen Sie, daß Port B1 als Ausgang umgeschaltet wurde und das Port B1 Low ist. Das Programm hat offensichtlich nicht gewartet. Warum denkt der Simulator, daß eine Taste gedrückt worden sei? Sie haben doch gar keinen entsprechenden Befehl gegeben.
Achten Sie auf die Anzeige von Pinb. Dort erscheinen alle Bits als Low. Low ist das Signal, welches bei gedrückter Taste an den Mikrocontroller gesendet wird. Nun machen Sie den Gegentest:
Drücken Sie Shift-F5, um das Programm neu zu starten. Wie gewohnt hält der Simulator wieder vor dem ersten Befehl an. Er gibt Ihnen dadurch die Möglichkeit, die Eingangssignale der Taster einzustellen. Schalten Sie die vier Bits 1-4 im Register Pinb auf High, was losgelassenen Tastern entspricht. Sie brauchen dazu einfach nur mit der Maus drauf klicken.
Drücken Sie danach Alt-F5. Das Programm läuft nun automatisch weiter, der gelbe Pfeil zeigt, welcher Befehl gerade ausgeführt wird. Sie sehen, daß ein Teil des Programms in einer Endlosschleife wiederholt wird. Dieses mal wartet das Programm darauf, daß eine Taste gedrückt wird.
Simulieren Sie einen Tastendruck, indem Sie irgendein Bit in Pinb wieder aus klicken. Das Programm erkennt dies als Tastendruck und schaltet daraufhin wie gewünscht die Led1 an. Dann endet es.
Übertragen Sie dieses Programm jetzt in den Mikrocontroller und probieren Sie es innerhalb der Schaltung aus.
Dies ist eine gute Gelegenheit, die Stromaufnahme der Schaltung zu messen. Bei 3V und ohne gedrückten Taster verbraucht er etwa 0,7mA. Das ist schön wenig, aber es geht noch viel besser.
Das obige Programm soll so verändert werden, daß es weniger Strom verbraucht.
Geben Sie dieses Programm ein. Es hat nur vier zusätzliche Zeilen ganz am Anfang. Lesen Sie die Kommentare und vergleichen Sie die Befehle mit der Hilfe und dem Datenblatt, um sie zu verstehen. Von besonderem Interesse sind die Seiten 25 und 26.
Hier wird der Clock-Prescaler genutzt, um die Taktfrequenz herab zu setzen. Standardmäßig ist der Teilerfaktor 8 durch die Fuse-Bits eingestellt, also 1,2Mhz, denn der interne RC-Oszillator schwingt mit ungefähr 9,6Mhz. Das Programm ändert diesen Teilerfaktor auf 256. Dadurch wird die effektive Taktfrequenz auf 37,5kHz reduziert.
Die geringere Taktfrequenz bewirkt eine geringere Stromaufnahme, wir sind jetzt bei etwa 0,15mA (bei 3V). Das hat sich gelohnt!
Das obige Programm soll so verändert werden, daß es noch weniger Strom verbraucht.
Geben Sie dieses Programm ein. Dieses mal habe ich das Programmende verbessert. Nachdem die Led eingeschaltet wurde, durchläuft das Programm eine kurze Warteschleife und schaltet sie dann wieder aus. Dann schläft der Mikrocontroller ein. Vergleichen Sie die Befehle des letzten Abschnittes mit dem Datenblatt Seite 28 und 29.
Wenn der Mikrocontroller einschläft, schaltet er sämtliche Taktsignale aus, was logischerweise die Stromaufnahme noch weiter reduziert. Er kann aus diesem Zustand nur durch ein Interrupt-Signal wieder aufgeweckt werden. Da dieses Programm aber keine Interrupt-Signale aktiviert, wird der Mikrocontroller nie wieder aufwachen. In diesem Fall ist das so beabsichtigt. Sie müssen die Batterie eine Weile lang heraus nehmen und wieder einsetzen, um das Programm neu zu starten.
Probieren Sie das Programm in der Schaltung aus. Wenn Sie eine Taste kurz antippen, geht die Led1 für eta 5 Sekunden an und dann wieder aus. Danach beträgt die Stromaufnahme unter 0,001mA, also Ziel ereicht.
Eine durchschnittliche Knopfzelle würde so rein Rechnerisch über 100 Jahre lang ausreichen. Natürlich ist keine Batterie so lange lagerbar. Dieses flache Rechenexempel zeigt jedoch, daß unser Senso Spiel tatsächlich keinen Ein-/Aus-Schalter benötigt.
Schauen Sie sich im Programmcode bitte den Absatz an, wo die Led aus geschaltet wird. Hier wird der Port B1 wieder als Eingang konfiguriert. Warum schalte ich den Ausgang nicht einfach auf High?
Stellen Sie sich vor, Sie würden den Taster1 gedrückt halten, während der Ausgang auf High geschaltet wird. Dann hätten Sie einen Kurzschluß durch den Taster. Dieses Beispiel zeigt, daß Sie den Chip unter ungünstigen Bedingungen tatsächlich kaputt programmieren können.
Gemäß Datenblatt Seite 44 können die Port Pins folgende Zustände haben:
Den Zustand 1) können wir gemäß Kapitel 6.2 nicht gebrauchen. Der Zustand 4) darf nicht benutzt werden, weil dabei ein Kurzschlußstrom durch die Taster fließen kann.
Der Befehl sbi portb,1 ist übrigens nicht unbedingt nötig, denn nach dieser Zeile werden die Eingänge nicht mehr abgefragt. Wer sich mit C-MOS Technologie beschäftigt hat, der mag einwenden, daß Eingänge ohne eindeutigen Pegel (High/Low) mehr Strom verbrauchen, als nötig. Das ist richtig, allerdings deaktiviert der Mikrocontroller alle Eingänge während er schläft. Siehe dazu das Datenblatt Seite 29 ganz unten und das Schaltbild auf Seite 43.
Beim Studieren des Datenblattes haben Sie sicher auch etwas über den Idle-Modus gelesen. In diesem Modus wird der Prozessorkern angehalten, während der Timer und die I/O Funktionen aktiv bleiben. Die Nutzung des Idle-Modus bringt uns allerdings keine Vorteile, denn wir haben die Taktfrequenz bereits sehr weit herabgesetzt. Der Unterschied zwischen 37,5kHz Taktfrequenz und Idle-Modus ist nur verschwindend gering.
Dennoch hat das Programm aus dem vorherigen Kapitel noch Verbesserungspotential. Die Wiederholschleife, in der auf einen Tastendruck gewartet wird, verschwendet regelrecht Energie.
Im vorherigen Kapitel haben Sie gelernt, daß der sleep Befehl den Mikrocontroller einschlafen läßt, bis er durch ein Interrupt-Signal aufgeweckt wird. Das haben wir noch nicht ausgenutzt. Schauen Sie ins Datenblatt auf Seite 53. Dort wird unter dem Namen "Pin Change Interrupt" erklärt, daß Pegeländerungen an jedem beliebigen Pin einen Interrupt auslösen können, man muß diese Funktion einfach nur für die gewünschten Pins (also die Tasten) aktivieren.
Genau das macht dieses Programm. Geben Sie das Programm in den Simulator ein und testen Sie es, indem Sie Strg-F7 drücken. Klicken Sie die vier Bits 1-4 im Register Pinb wieder auf High, um losgelassene Tasten zu simulieren. Drücken Sie dann Alt-F5, um das Programm automatisch laufen zu lassen. Ihr Programm wird an der Zeile hinter dem sleep Befehl stehen bleiben, bis eine Taste gedrückt wird.
Die Assembler Direktive .org 0x000 teilt dem Assembler mit, daß die dahinter stehenden Befehle ab Adresse 0x000 im Programmspeicher stehen sollen. Das ist übrigens auch die Standard-Vorgabe, wenn Sie keine .org 0x000 Direktive angeben.
Wenn der Mikrocontroller Resetted wird (also beim Einsetzen der Batterien), beginnt der Prozessor an Adresse 0x000. In diesem Fall steht dort ein Sprungbefehl rjmp start an den Beginn des Programmes.
Die Adresse 0x002 ist für Pin-Change Interrupts vorgesehen. Immer, wenn ein Signalwechsel an einem entsprechend aktiviertem Pin erkannt wird, unterbricht der Mikrocontroller das laufende Programm, um eine besondere Interruptroutine an eben dieser Adresse auszuführen. Diese Interrupt-Routine brauchen wir nicht, und darum steht an Adresse 0x002 nur der reti Befehl.
Alle Interrupt Routinen müssen mit dem Befehl reti enden. Leere Interrupt Routinen bestehen einfach nur aus diesem einen Befehl.
Die Interrupt Vektoren (0x000, 0x002 und weitere) sind im Datenblatt auf Seite 41 aufgelistet.
Etwas weiter unten im Programm steht der Befehl sbi acsr,acd. Er schaltet den Analog-Comparator aus, siehe dazu das Datenblatt Seite 76. Der Analog Comparator ist die einzige Funktion, die standardmäßig eingeschaltet ist. Da wir sie nicht brauchen, schaten wir sie ab, so sparen wir noch ein klein wenig Strom.
Direkt darunter kommt ein Befehlsblock, der den Pin-Change Interrupt für alle vier Tasten aktiviert. Daß Interrupts das laufende Programm unterbrechen, interessiert uns dabei gar nicht so sehr. Wir wollen nur den Power-Down Schlaf unterbrechen.
Das Programm wiederholt sich immer wieder, wobei es bei jedem Durchlauf solange einschläft, bis man eine Taste drückt. Das Programm ist nun so weit entwickelt, daß man die Batterie in der Fassung lassen kann. Überzeugen Sie sich davon, daß dies stimmt, indem Sie die Stromaufnahme nachmessen.
Das Programm soll in Prozeduren zerlegt werden, um den Quellcode übersichtlicher zu machen. Geben Sie dieses Programm in den Simulator ein.
Die Prozeduren werden durch den rcall Befehl aufgerufen. Der Befehl ret springt zurück ins Hauptprogramm.
Die 5s Pause wurde durch eine 1s Pause ersetzt. In dieser Prozedur wird die Anzahl der nötigen Schleifendurchläufe durch den Ausdruck (1*37500/3) berechnet und durch high() und low() in zwei 8-Bit Werte zerlegt. Schließlich haben wir einen 8-Bit Mikrocontroller vor uns.
In dieser Formel wird die Taktfrequenz durch 3 geteilt, weil die innere Schleife (r17) genau 3 Taktzyklen lang dauert. Der Befehl dec r17 braucht einen Taktzyklus und der Befehl brne p1 braucht 2 Taktzyklen. Die Taktzyklen der anderen Befehle in dieser Prozedur habe ich vernachlässigt, denn hunderprozentig genau muss die Dauer der Pause nicht sein.
Die Prozedur takt_38khz müsste eigendlich takt_37.5khz heissen, aber der Assembler erlaubt weder Punkt noch Komma in den Labels.
Wenn die Led mehrmals blinken soll, brauchen Sie nur den Befehl rcall led_blinken mehrmals hintereinander zu schreiben. Spätestens dann dürfte ein weiterer Vorteil von Prozeduren offensichtlich werden. Sie verwenden die Prozedur wo sie wollen und so oft sie wollen, ohne den vielfachen Speicherplatz zu benötigen.
Das Programm soll so geändert werden, daß es einen Piepton von sich gibt, anstatt die Led blinken zu lassen. Geben Sie dieses Programm in den Simulator ein.
Die erste Änderung wurde im Hauptprogramm vorgenommen. Die Prozedur zum Led-Blinken wurde durch eine Prozedur zum Piepen ersetzt. In der Init-Prozedur ist der Befehl sbi ddrb,0 hinzugefügt worden, damit der Port B0 als Ausgang umgeschaltet wird, schließlich soll der Lautsprecher ja angesteuert werden.
Die 1s Pause wurde durch eine 500ms Pause ausgetauscht - nur so zum Spaß.
Der Ton wird mit dem Timer/Counter erzeugt. Vergleiche dazu das Datenblatt ab Seite 74. Dieses Kapitel im Datenblatt ist sicher das komplizierteste, weil der Timer/Counter so viele einstellbare Parameter hat. Es wird der CTC Modus verwendet, dabei Zählt der Counter die Taktzyklen wiederholt bis zu einem festgelegten Maximalwert. Jedes mal, wenn der Maximalwert erreicht wird, wechselt der Ausgang OC0A (das ist Port B0, der Lautsprecher) seinen Pegel.
Wenn der Timer also z.B. 3200 mal pro Sekunde seinen Maximalwert erreicht, schwingt der Lautsprecher mit 1600 Hz. Ist der Timer erstmal gestartet, Piept der Lautsprecher solange, bis der Timer wieder angehalten wird.
Bei dem 37,5kHz Systemtakt können Sie 255 unterschiedliche Töne zwischen 73 Hz und 18kHz wiedergeben. Für gut klingende Musik ist das viel zu wenig, für das Senso Spiel reicht das aber. Schließlich brauchen wir nur 4 Töne die eine harmonische Folge ergeben.
Wenn Sie Interesse haben, können Sie sich ja überlegen, wie sie feiner abgestufte Töne wiedergeben können. Tip: Ich würde dazu eine erheblich höhere Taktfrequenz verwenden und den Counter durch eine Interruptroutine per Software zu einem 16Bit Counter erweitern.
Geben Sie dieses Programm in den Simulator ein und erzeugen Sie die Hex-Datei durch Druck auf F7. Übertragen Sie das Programm in den Mikrocontroller und probieren Sie es aus.
Drücken Sie die Taste 1, dann Taste 2. Legen Sie das Spiel dann weg. Wenn jemand anders nun damit spielen möchte, muß er genau da weiter spielen, wo Sie aufgehört haben, nämlich bei Taste 3. Das ist blöd. Das Spiel sollte sich nach einer Gewissen Zeit automatisch zurück setzen, um diese Situation zu verhindern
Dazu verwenden wir den Watchdog. Eigentlich wurden Watchdogs erfunden, um abgestürzte Computer zurück zu setzen. In unserem Fall kann er das gerne tun, doch die Hautpaufgabe wird darin bestehen, liegen gelassene Spiele zurück zu setzen.
Geben Sie dieses Programm in den Simulator ein und erzeugen Sie die Hex-Datei durch Druck auf F7. Übertragen Sie das Programm in den Mikrocontroller und probieren Sie es aus. Drücken Sie die Taste 1, dann Taste 2 und dann warten Sie 6 Sekunden. Innerhalb dieser Zeit schlägt der Watchdog zu und setzt das Spiel zurück. Sie können nun also wieder mit Taste 1 beginnen.
Ganz am Anfang des Programmes habe ich eine Prozedur für den Pin-Change Interrupt geschrieben. Sie setzt den Watchdog zurück. Jedesmal, wenn eine Taste gedrückt oder auch losgelassen wird, setzt der wdr Befehl den Watchdog Timer zurück. Seine 4 Sekunden Auszeit beginnt dann wieder von neuem. Sobald Sie länger als 4 Sekunden keine Taste drücken, wird das Spiel zurück gesetzt.
Der Anfang des Hauptprogramm wurde etwas verändert. Zuerst wird der Mikrocontroller initialisiert, dann wird der Takt herabgesetzt. Danach wird der Watchdog aus geschaltet (falls er an war) und geschlafen. Die Arbeit beginnt mit einer Runde Schlafen :-). Da der Watchdog aus ist, kann dieser Schlaf beliebig lange dauern, das ist also der Ruhezustand des Spiels.
Im Ruhezustand darf der Watchdog nicht ständig eingeschaltet bleiben, denn er würde die Stromaufnahme unnötig erhöhen. Bei Batteriebetrieb ohne Ein-/Aus-Schalter sind solche "Kleinigkeiten" sehr wichtig.
Wenn Sie irgendeine Taste drücken, wacht der Mikrocontroller wieder auf. Nun beginnt das eigendliche Hauptprogramm. Als erstes schaltet es den Watchdog ein, denn ab jetzt soll das Spiel bei Nicht-Benutzung in den Ruhezustand zurück gesetzt werden. Dann wartet das Spiel wie gehabt darauf, daß die vier Tasten nacheinander gedrückt werden.
Wie man den Watchdog ein und aus schaltet, steht im Datenblatt ab Seite 36. Das Aus-Schalten erfordert absichtlich eine komplizierte Folge von Befehlen, wie das Datenblatt erklärt.
Anmerkung: Aufrund der zahlreichen Warteschleifen und Timer lassen sich die Programme dieses Kapitels nur noch sehr bedingt im Simulator testen.
Für das Senso Spiel brauchen Sie einen Zufallszahlen-Generator. Er erzeugt die Melodien, die der Spieler nachspielen soll. Jedesmal, wenn der Spieler die Melodie richtig nachgespielt hat, soll sie durch einen neuen Zufallston verlängert werden. Sie könnten dazu die bisherige Melodie ins RAM abspeichern. Einfacher geht es mit einem Pseudo-Zufallszahlen-Generator.
Ein Pseudo-Zufallszahlen-Generator benötigt einen Startwert. Von diesem Wert ausgehend, erzeugt er bei wiederholtem Aufruf eine Folge von Zufallszahlen. Wann Immer Sie mit dem gleichen Startwert beginnen, kommt die gleiche Zahlenfolge hinten heraus. Eine solche Zahlenfolge könnte z.B. so aussehen:
5
5 2
5 2 34
5 2 34 12
5 2 34 12 1
und so weiter.
Sie brauchen die Melodie nirgends abzuspeichern, sondern können einfach bei jedem Durchlauf die gleiche Zahlenfolge immer wieder erneut berechnen.
Jetzt brauchen Sie nur noch bei jedem neuen Spiel einen neuen Startwert, den können Sie erzeugen, indem Sie messen, wie lange der Spieler die erste Taste (zum Starten) drückt.
Geben Sie dieses Programm in den Simulator ein starten Sie es durch Durck auf Strg-F7. Gehen Sie mit dem Cursor in die Zeile nochmal: rcall random und drücken Sie F9, um einen Haltepunkt zu setzen. Drücken Sei dann Alt-F5.
Während das Programm darauf wartet, daß Sie die (simulierte) Taste 1 loslassen, stellen Sie die Ansicht im linken Fenster so ein, daß Sie das Register 19 und den Port B sehen können:
Die Zahl im Register r19 ändert sich laufend, das wird unser Startwert für den Zufallsgenerator. Simulieren Sie nun das Loslassen der Taste 1, indem Sie das Bit 1 in Pinb anklicken (so daß es Schwarz wird). Der Simulator erreicht den Haltepunkt, während in Register r19 und r20 irgend ein Zufälliger Startwert steht.
Drücken Sie nun F5, um die nächste Zufallszahl zu berechnen. Drücken Sie nochmal ein paar mal F5 und beobachten Sie, wie bei jeder Wiederholung eine neue Zufallszahl in r20 erzeugt wird.
Den Algorithmus der Prozedur random: habe ich übrigens aus einem Schaltplan abgeleitet, den ich im Internet gefunden habe. Dort wurde der Zufallszahlen-Generator aus einem Schieberegister und drei Exklusiv-Oder Gattern gebildet.
In den vorherigen Kapiteln haben Sie gelernt, den AVR Mikrocontroller von Typ Tiny13 zu programmieren. Sie haben alle Komponenten kennen gelernt, die für das Senso Spiel benötigt werden.
Folgende Komponenten brauchen Sie für das Senso Spiel nicht:
Der vollständige Quelltext des Spiels wurde aus den bisher besprochenen Bausteinen zusammen gesetzt.
Nach dem Anlegen der Stromversorgung wird die Hardware initialisisert. Er ertönt ein tiefer Ton und dann schaltet sich das Gerät ab.
Wenn Sie nun irgend eine Taste drücken, schaltet sich das Spiel ein. Es gibt eine kurze Melodie aus 2 Tönen vor, die Sie nachspielen müssen.
Wenn Sie richtig gespielt haben, ertönt ein Bestätigungston. Danach wird die Melodie um einen Ton verlängert vorgespielt.
Wenn Sie gepatzt haben beginnt das Programm wieder ganz von oben, also beim Reset. Das Spiel ist damit beendet.
Wenn Sie 4 Sekunden lang keine Taste drücken, beißt der Wachhund zu (Watchdog) und setzt den Mikrocontroller ebenfalls zurück, wodurch das Spiel beendet wird.
Viel Spaß beim Nachbauen!