Startseite

AVR Assembler Workshop

Anhand eines kleinen elektronischen Spiels lernst du in kleinen Schritten, einen AVR Mikrocontroller in Assembler zu programmieren. Es werden grundlegende Kenntnisse in Elektronik (Widerstände, LED, Spannung, Strom) vorausgesetzt. Es ist nötig, englische Texte zu lesen.

Wir werden den ATtiny 13 benutzen. Er hat insgesamt 8 Pins, davon können 5 Pins frei programmiert werden.

Senso Spiel

Wir werden ein elektronisches Spiel nachbauen, dass in den 80er Jahren von MBO mit dem Namen "Senso" vertrieben wurde. Es ist auch unter dem Namen "Simon" bekannt. 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.

Die ISP Schnittstelle

Mit einem ISP Programmieradapter wirst du deine selbst geschriebenen Programme vom PC in den Mikrocontroller übertragen. Achte beim Kauf darauf, dass er eine Stromversorgung für die Zielschaltung bereit stellen kann und einen 6 Poligen Stecker hat. Ich empfehle den USB ISP Stick von Diamex:

Dies ist die Pinbelegung der 6-poligen Stiftleiste aus Sicht des Mikrocontrollers:

Daten, Ausgang MISO 1 2 VCC Spannungsversorgung
Takt, Eingang SCK 3 4 MOSI Daten, Eingang
Eingang, LOW=Programmieren /RESET 5 6 GND Masse

Pin 1 ist in der Regel rot oder mit einem Pfeil markiert.

Die Abkürzung ISP bedeutet "In System Programming". Der Name soll andeuten, dass diese Mikrocontroller in der Schaltung programmiert werden können. Wir werden den Chip allerdings zum Programmieren auf eine separate Adapterplatine stecken, weil das für den Anfang einfacher ist:

Alternativ eignet sich auch ein Steckbrett mit einer Hand voll Dupont-Kabeln.

Material

Benötigte Bauteile für das Spiel:

Anzahl Für die 4,5V Variante Für die 3V Variante
4 LEDs in rot, gelb, grün und blau rote LEDs
1 Batterien 3xAAA Lithium Knopfzelle CR2032
1 Batteriehalter
1 Widerstand 330 Ohm 1/4 Watt
1 ATtiny13A-PU oder ATtiny13V-10PU
1 IC Sockel 8-Pin
1 Piezo Schallwandler
4 Eingabetaster in rot, gelb, grün und blau
1 Kondensator 100 nF
1 Punktrasterplatine 8x5 cm

Für den Programmieradapter:

Anzahl Bauteil
1 IC Sockel 8 Pins
1 Stiftleiste 6 Pins
1 Kondensator 100 nF
1 Punktrasterplatine 4x5 cm

Schaltplan

Das Gerät besteht aus sehr wenig Bauteilen, deswegen ist es zum Erlernen der AVR Grundlagen sicher gut geeignet.

Plane und Löte eine Platine gemäß diesem Schaltplan. Lasse Dir dabei eventuell von jemandem mit Erfahrung helfen.

Funktionsweise

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 LEDs einschalten. Da normalerweise immer nur eine LED von den vier leuchten soll, können sie sich alle einen einzigen Vorwiderstand teilen. Hier wird sehr schön demonstriert, dass 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 LEDs zu viel Spannung 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, dass 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 dass 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, was auch Energie spart.

Programmierung in kleinen Schritten

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.

Installiere das AVR Studio 4.19 auf deinen PC.

Starte das AVR Studio und beginne ein neues Projekt mit dem Namen "Senso". Als Programmiersprache wählst du den Atmel AVR Assembler. Als Debug Plattform wähle den AVR Simulator und stelle das richtige Device (ATtiny13) ein. Ändere im Menü Tools/Options/Editor die Tabulator-Breite auf 8.

Im Datenblatt ist der Mikrocontroller dokumentiert. Sein Befehlssatz ist im AVR 8bit Instruction Set ausführlich dokumentiert.

Eine Led einschalten

Gebe 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) wird die dort angeschlossene LED leuchten.

ende: rjmp ende ist eine Endlosschleife und bildet somit das Programmende. Ohne diesen Befehl würde der Mikrocontroller den un-programmierten Rest des Programmspeichers abarbeiten. Dort werden zufällige alte Kommandos stehen, die will man nicht ausführen.

Drücke Strg-F7 um den Simulator zu starten. Es erscheint ein gelber Pfeil vor dem ersten Befehl:

Drücke F11 um das Programm Schrittweise auszuführen. Im Fenster links oben kannst du die Auswirkungen direkt nachvollziehen. Der Befehl sbi ddrb,1 setzt im Register DDRB das Bit 1 auf HIGH, was als schwarzes Kästchen angezeigt wird.

Bewege den Cursor auf den sbi Befehl und drücke F1. Es erscheint eine Beschreibung dieses Befehls. Schaue bitte ins Datenblatt auf Seite 158, dort findest du die Übersicht der I/O Register. Wozu das Register DDRB gut sein soll, geht aus dieser Seite allerdings nicht hervor. Die Beschreibung der einzelnen Register befinden sich in den vorherigen Seiten des Datenblattes, in diesem Fall ab Seite 49. Lies dieses Kapitel durch, von besonderem Interesse ist momentan der Absatz "Configuring the Pin" auf Seite 50 und die Seite 51.

Wenn du jetzt noch ein paar mal F11 drückst, siehst du, dass der letzte Befehl unendlich oft wiederholt wird.

Bei allen weiteren Schritten sollst du ebenso das Datenblatt und die Hilfe-Funktion vom AVR Studio zu Rate ziehen, um die verwendeten Befehle und Register kennen zu lernen.

Mikrocontroller flashen

Schließe den AVR Chip an den ISP-Programmieradapter an. Benutze die Software, die zu deinem Programmieradapter gehört, um den Chip zuerst zu löschen und anschließend die *.hex Datei zu übertragen, die du mit dem AVR Studio erstellt hast. Stecke den Programmieradapter vom PC ab, bevor du den Mikrocontroller aus der Fassung heraus nimmst.

Setze den Mikrocontroller jetzt in die Fassung des Spiels ein. Dann die Batterie einsetzen und: Led1 leuchtet. Wahnsinn :-)

Achtung: Niemals den Chip unter Spannung in seine Fassung stecken oder heraus ziehen.

Mit der Software des Programmieradapters kannst du sogenannte "Fuses" ändern. Lasse davon besser die Finger, denn es ist dort möglich, den Mikrocontroller durch falsche Einstellungen unbrauchbar zu machen. Die Standardvorgaben, mit denen der Chip verkauft wird, sind für dieses Tutorial bereits passend.

Eine Taste abfragen

Folgendes Programm soll geschrieben werden:

Zunächst sollen alle LEDs 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.

Gebe dazu dieses Programm ein. Lese die Kommentare und vergleiche die Befehle mit der Hilfe vom AVR Studio und dem Datenblatt, um sie zu verstehen.

Drücke Strg-F7 und dann zehn mal F11. Da Resultat sollte so aussehen:

Im linken I/O-View Fenster kann man die Auswirkungen des Programms nach dem ersten Durchlauf sehen. Am Register DDRB erkennst du, dass Port B1 als Ausgang umgeschaltet wurde und das Port B1 LOW ist. Das Programm hat offensichtlich nicht gewartet. Warum denkt der Simulator, dass eine Taste gedrückt worden sei? Du hast doch gar keinen entsprechenden Befehl gegeben! Achte dazu auf die Anzeige von PINB. Dort erscheinen alle Bits als LOW, was einem gedrückten Taster entspricht. Nun mache den Gegentest:

Drücke Shift-F5, um das Programm neu zu starten. Wie gewohnt hält der Simulator wieder vor dem ersten Befehl an. Er gibt dir dadurch die Möglichkeit, die Eingangssignale der Taster einzustellen. Schalte die vier Bits 1-4 im Register PINB auf HIGH, was einem losgelassenen Taster entspricht. Du brauchst dazu einfach nur mit der Maus drauf klicken.

Drücke danach Alt-F5. Das Programm läuft nun automatisch weiter, der gelbe Pfeil zeigt, welcher Befehl gerade ausgeführt wird. Du siehst, dass ein Teil des Programms in einer Endlosschleife wiederholt wird. Dieses mal wartet das Programm darauf, dass eine Taste gedrückt wird.

Simuliere einen Tastendruck, indem du irgendein Bit in PINB wieder aus klickst. Das Programm interpretiert dies als Tastendruck und schaltet daraufhin wie gewünscht die LED1 an. Dann endet es.

Übertrage dieses Programm jetzt in den Mikrocontroller und probiere es innerhalb der Schaltung aus.

Dies ist eine gute Gelegenheit, die Stromaufnahme der Schaltung zu messen. Bei 3V und ohne gedrückten Taster verbraucht sie etwa 0,7mA. Das ist schön wenig, aber es geht noch viel besser.

Taktfrequenz herabsetzen

Das obige Programm soll so verändert werden, dass es weniger Strom verbraucht.

Gebe dieses Programm ein. Es hat nur vier zusätzliche Zeilen ganz am Anfang. Lese die Kommentare und vergleiche die Befehle mit der Hilfe vom AVR Studio und dem Datenblatt, um sie zu verstehen. Von besonderem Interesse sind die Seiten 26 und 28.

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!

Einschlafen

Das obige Programm soll so verändert werden, dass es noch weniger Strom verbraucht.

Gebe 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. Vergleiche die Befehle des letzten Abschnittes mit dem Datenblatt Seite 30 und 33.

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. Du musst die Batterie eine Weile lang heraus nehmen und wieder einsetzen, um das Programm neu zu starten.

Probiere das Programm in der Schaltung aus. Wenn du eine Taste kurz antippst, geht die LED1 für etwa 5 Sekunden an und dann wieder aus. Danach beträgt die Stromaufnahme unter 0,001mA, also ist das Ziel erreicht.

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, dass unser Senso Spiel tatsächlich keinen Ein-/Aus-Schalter benötigt.

Schaue dir 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? Stelle dir vor, du würdest den Taster1 gedrückt halten, während der Ausgang auf HIGH geschaltet wird. Dann hättest du einen Kurzschluss durch den Taster. Das wollen wir vermeiden.

Gemäß Datenblatt Seite 51 können die Port Pins folgende Zustände haben:

  1. Eingang ohne Pull-up
  2. Eingang mit Pull-up
  3. Ausgang LOW
  4. Ausgang HIGH

Den Zustand 1) können wir gemäß Kapitel "Funktionsweise" nicht gebrauchen. Der Zustand 4) darf nicht benutzt werden, weil dabei ein Kurzschluss-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.

Einschlafen und wieder aufwachen

Beim Studieren des Datenblattes hast du 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 nämlich regelrecht Energie.

Im vorherigen Kapitel hast du gelernt, dass der sleep Befehl den Mikrocontroller einschlafen lässt, bis er durch ein Interrupt-Signal aufgeweckt wird. Das haben wir noch nicht ausgenutzt. Schaue ins Datenblatt auf Seite 47 und 48. Dort wird unter dem Namen "Pin Change Interrupt" erklärt, dass Pegeländerungen an jedem beliebigen Pin einen Interrupt auslösen können, man muss diese Funktion einfach nur für die gewünschten Pins (also die Tasten) aktivieren.

Genau das macht dieses Programm. Gebe das Programm in den Simulator ein und teste es, indem du Strg-F7 drückst. Klicke die vier Bits 1-4 im Register PINB wieder auf HIGH, um losgelassene Tasten zu simulieren. Drücke dann Alt-F5, um das Programm automatisch laufen zu lassen. Dein 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, dass die dahinter stehenden Befehle ab Adresse 0x000 im Programmspeicher stehen sollen. Das entspricht übrigens auch der Standard-Vorgabe, falls diese Direktive fehlt.

Wenn der Mikrocontroller Resetted wird (also beim Einsetzen der Batterien), beginnt der Prozessor mit der Ausführung des Programms ab Adresse 0x000. In diesem Fall steht dort ein Sprungbefehl rjmp start an den eigentlichen Beginn des Programms.

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 Vektoren (0x000, 0x002 und weitere) sind im Datenblatt auf Seite 45 aufgelistet.

Etwas weiter unten im Programm steht der Befehl sbi acsr,acd. Er schaltet den Analog-Comparator aus, siehe dazu im Datenblatt ab Seite 80. Der Analog Comparator ist die einzige Funktion, die standardmäßig eingeschaltet ist. Da wir sie nicht brauchen, schalten 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. Das 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, dass man die Batterie in der Fassung lassen kann. Überzeuge dich davon, dass dies stimmt, indem du die Stromaufnahme mit einem Meßgerät kontrollierst.

Prozeduren

Das Programm soll in Prozeduren zerlegt werden, um den Quellcode übersichtlicher zu machen. Gebe 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 hundertprozentig genau muss die Zeit gar nicht sein.

Die Prozedur takt_38khz wollte ich eigentlich takt_37.5khz nennen, aber der Assembler erlaubt weder Punkt noch Komma in den Labels.

Wenn die LED mehrmals blinken soll, braucht man nur den Befehl rcall led_blinken mehrmals hintereinander zu schreiben. Spätestens dann dürfte ein weiterer Vorteil von Prozeduren offensichtlich werden. Du wirst die Prozedur beliebig oft verwenden, ohne den vielfachen Speicherplatz zu benötigen.

Töne wiedergeben

Das Programm soll so geändert werden, dass es einen Piepton von sich gibt, anstatt die LED blinken zu lassen. Gebe 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 59. 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 kann man 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 es aber. Schließlich brauchen wir nur 4 Töne die halbwegs harmonisch klingen.

Watchdog

Gebe dieses Programm in den Simulator ein und erzeuge die Hex-Datei durch Druck auf F7. Übertrage das Programm in den Mikrocontroller und probiere es aus.

Drücken die Taste 1, dann Taste 2. Lege das Spiel dann weg. Wenn jemand anders nun damit spielen möchte, muss er genau da weiter spielen, wo du aufgehört hast, 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.

Gebe dieses Programm in den Simulator ein und erzeuge die Hex-Datei durch Druck auf F7. Übertrage das Programm in den Mikrocontroller und probiere es aus. Drücke die Taste 1, dann Taste 2 und dann warte 6 Sekunden. Innerhalb dieser Zeit schlägt der Watchdog zu und setzt das Spiel zurück. Du kannst nun also wieder mit Taste 1 beginnen.

Ganz am Anfang des Programms habe ich eine Prozedur für den Pin-Change Interrupt geschrieben. Sie setzt den Watchdog zurück. Jedes mal, 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 länger als 4 Sekunden keine Taste betätigt wird, 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 nun 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 du irgendeine Taste drückst, wacht der Mikrocontroller wieder auf. Nun beginnt das eigentliche 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, dass 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: Aufgrund der zahlreichen Warteschleifen und Timer lassen sich die Programme dieses Kapitels nur noch sehr bedingt im Simulator testen.

Zufallszahlen-Generator

Für das Senso Spiel brauchst du einen Zufallszahlen-Generator. Er erzeugt die Melodien, die der Spieler nachspielen soll. Jedes mal, wenn der Spieler die Melodie richtig nach gespielt hat, soll sie durch einen neuen Zufallston verlängert werden. Du könntest dazu die bisherige Melodie im 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 du mit dem gleichen Startwert beginnst, kommt erneut 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.

Du brauchst die (nicht wirklich) zufällige Melodie daher nirgends abzuspeichern, sondern lässt sie einfach bei jedem Durchlauf erneut berechnen.

Jetzt brauchst du nur noch bei jedem neuen Spiel einen neuen Startwert. Den kannst du erzeugen, indem du misst, wie lange der Spieler die erste Taste (zum Starten) drückt.

Gebe dieses Programm in den Simulator ein starte es durch Druck auf Strg-F7. Gehe mit dem Cursor in die Zeile nochmal: rcall random und drücke F9, um einen Haltepunkt zu setzen. Drücke dann Alt-F5.

Während das Programm darauf wartet, dass du die (simulierte) Taste 1 loslässt, stellst du die Ansicht im linken Fenster so ein, dass du das Register 19 und den Port B sehen kannst:

Die Zahl im Register r19 ändert sich laufend, das wird unser Startwert für den Zufallsgenerator. Simuliere nun das Loslassen der Taste 1, indem du das Bit 1 in PINB anklickst (so dass es Schwarz wird). Der Simulator erreicht den Haltepunkt, während in Register r19 und r20 irgend ein zufälliger Startwert steht.

Drücke nun F5, um die nächste Zufallszahl zu berechnen. Drücke nochmal ein paar mal F5 und beobachte, 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.

Das fertige Programm

In den vorherigen Kapiteln hast du gelernt, den AVR Mikrocontroller von Typ Tiny13 zu programmieren. Du hast alle Komponenten kennen gelernt, die für das Senso Spiel benötigt werden. Folgende Komponenten wurden nicht verwendet:

Der vollständige Quelltext des Spiels wurde aus den bisher besprochenen Bausteinen zusammen gesetzt. Nach dem Anlegen der Stromversorgung wird die Hardware initialisiert. Er ertönt ein tiefer Ton und dann schaltet sich das Gerät ab.

Wenn du nun irgend eine Taste drückst, schaltet sich das Spiel ein. Es gibt eine kurze Melodie aus 2 Tönen vor, die du nachspielen sollst. Wenn du sie richtig nachgespielt hast, ertönt ein Bestätigungston. Danach wird die Melodie um einen Ton verlängert.

Wenn du versagst, beginnt das Programm wieder von ganz oben, also beim Reset. Das Spiel ist damit beendet. Wenn du 4 Sekunden lang keine Taste drückst, schlägt der Watchdog zu und setzt den Mikrocontroller zurück, wodurch das Spiel beendet wird.

Das war's. Viel Spaß beim Spielen!