; Test 2: Board kennenlernen: Eingabe von einem Port ; Was man hier dazu lernen kann: ; - Eingabe von einem Port lesen ; - Das Aufrufen von Unterprogrammen, Stack- (Stapel-Befehle) ; - Binäre Rechen Operationen (AND, OR, ROL, etc.) ; - Bedingte Verzweigungen (SBIx, BRxx) .NOLIST .INCLUDE "C:\avrtools\appnotes\8515def.inc" .LIST ; Ein Universalregister definieren: .DEF mp = R16 ; Der Rest-Sprungbefehl an Adresse 0: rjmp main ; Hier beginnt das Hauptprogramm main: ldi mp,LOW(RAMEND) ;Initiate Stackpointer out SPL,mp ldi mp,HIGH(RAMEND) out SPH,mp ; Diese Befehle richten einen Stack im SRAM ein. Ein Stack wird immer ; dann gebraucht, wenn Unterprogramme oder Interrupts aufgerufen werden. ; Beim Aufruf muss der aktuelle Zählerstand der Bearbeitung in einem ; Speicher abgelegt werden, damit nach Beendigung wieder an die auf- ; rufende Stelle zurückgekehrt werden kann. Der Stack wird immer am ; oberen Speicherende des SRAM angelegt. Das Speicherende des jeweili- ; gen Chips ist in der Datei "xxxxdef.inc" mit dem Namen RAMEND defi- ; niert. ; Wird ein Byte auf dem Stapel oder Stack abgelegt, dann wird ein ; Byte in das SRAM geschrieben (an die Adresse SPH:SPL), dann wird der ; Stapelzähler SPH:SPL um Eins verringert. Weiteres Ablegen bringt den ; Zeiger näher an den Anfang des SRAMs. Wird ein Wert aus dem Stapel ; entnommen, dann wird der Zeiger um eins erhöht und der Wert ausgelesen. ; Der jeweils zuletzt im SRAM abgelegte Wert kommt bei der Entnahme ; wieder als erster heraus (Last-in-First-Out-Struktur). ; Da der Programmzähler und die weitere Adressverwaltung 16 Bits ; Breite hat, alle Register und das SRAM aber 8 Bits, muss man jeweils ; mit 2 Bytes zu 8 Bits oder einem Wort zu 16 Bits arbeiten. Der ; SRAM-Speicher hat 16 Bit Adresse, also gibt es den Port SPL für die ; unteren 8 Bits, den Port SPH für die oberen 8 Bits der Adresse. Zusam- ; men ist SPH:SPL ein 16-Bit-Zeiger in das SRAM. ; Die Rechenoperationen LOW und HIGH veranlassen den Assembler, das ; 16-Bit-Wort RAMEND jeweils zu je 8-Bits aufzuteilen, damit es in die ; Ports SPL und SPH übertragen werden kann. ; An Port D sind die Schalter angeschlossen. Der Port D wird gelesen. ; Sein Datenrichtungsregister muss also acht Nullen kriegen: ldi mp,0x00 ; 8 Nullen in Universalregister out DDRD,mp ; an Datenrichtungsregister ; Die Schalter verbinden die Eingänge des Ports D mit GND. Damit bei ; offenem Schalter ein definierter Pegel herrscht, können die Pull-Up- ; Widerstände eingeschaltet werden. Das ist beim STK200 nicht nötig, ; weil diese extern schon auf dem Board vorhanden sind. Aus pädagischen ; Gründen schalten wir sie trotzdem ein. Das erreicht man durch das ; Schreiben von Einsen in das Datenausgangsregister: ldi mp,0xFF ; 8 Einsen in Universalregister out PORTD,mp ; und an Port D (das sind jetzt die Pull-Ups!) ; Port B mit den LEDs soll wieder als Ausgang dienen (siehe TEST1), die ; Lampen sollen zu Beginn alle aus sein. ldi mp,0xFF ; 8 Einsen in Universalregister out DDRB,mp ; und in Datenrichtungsregister out PORTB,mp ; und an alle Ausgänge ; Das Drücken der Schalter 0 und 1 soll die Lampen 0 und 1 anmachen, ; das Drücken eines der Schalter 2 bis 6 die anderen Lampen. Das ; Drücken von Schalter 7 macht alle Lampen aus. ; Im Hauptloop erfolgt die Abfrage der Schalter, wenn die Bedingungen ; erfüllt sind, wird zu den jeweiligen Unterprogrammen verzeigt. loop: ; Abfrage von Schalter 0 (einfachst) ; Überspringe den nächsten Befehl (Aufruf des Unterprogrammes zum ; Anmachen der Lampe 0), wenn das 0-te Bit im Port D eine Eins ist ; (Schalter aus, Pull-Up erzeugt eine Eins). Das Unterprogramm ; Lampe 0 steht weiter hinten. Beim RCALL wird die aktuelle Adresse ; auf den Stapel abgelegt, beim Rücksprung wird diese wieder vom Stapel ; genommen und das Programm mit dem Befehl nach RCALL fortgesetzt. Weil ; mit dem SBIS-Befehl immer nur ein Befehl übersprungen wird, muss es ; sich um einen Ein-Byte-Befehl handeln. RCALL ist ein solcher, der ; absolute CALL-Befehl wäre ein 2-Byte-Befehl und ginge nicht! sbis PIND,0 ; Springe, wenn Bit 0 im Port D Eins ist rcall Lampe0 ; Führe ein relativ angegebenes Unterprogramm aus ; Nach Abarbeiten des Unterprogrammes und beim Überspringen des Unter- ; programmes wird nun nächste Befehl durchgeführt. ; Abfrage von Schalter 1 (exotisch) ; Die Ports sind in den Adressraum des SRAMs gespiegelt, die Adresse ; ergibt sich durch Addition von 20 hex. Anstelle der IN/OUT-Befehle ; können auch die Lade-/Speicher-Befehle mit Zeigern verwendet werden. .EQU d_in_spiegel=PIND + $20 ; Mit dem Registerpaar R27:R26 kann ein Zeiger X in das SRAM konstruiert ; werden, mit dem LD-Befehl kann der Inhalt des Ports gelesen werden, als ; wenn es ein SRAM-Byte wäre. ldi R26,LOW(d_in_spiegel) ; unteres Byte Zeiger ldi R27,HIGH(d_in_spiegel) ; oberes Byte Zeiger ld mp,X ; Lade Register aus Zeiger auf PIND ; Isoliere Pin1 mit AND-Befehl und teste auf Null andi mp,0b00000010 ; AND Bit 1 ; Überspringe die folgenden Befehle, wenn nicht Null bei AND herauskam ; (= Bit 1 war Eins, Schalter 1 ist aus). Der Sprungbefehl ist für eine ; größere Anzahl Befehle geeignet, da zu einem Label verzweigt wird. brne weiter ; Verzweige nach weiter, falls nicht Null rcall Lampe1 ; Führe Unterprogramm Lampe1 aus ; Schalter 2 bis 6 ; Einlesen des Ports D in ein Register, Maskieren der anderen Schalter, ; Vergleich mit Schalter 2 bis 6, ; Vergleich mit LEDs 2 bis 7 anmachen weiter: in mp,PIND ; Lese Port D ori mp,0b10000011 ; Maskiere Schalter 0, 1 und 7 cpi mp,0b11111111 ; Irgendein Schalter gedrückt? breq sw7 ; Verzweige nach sw7, falls = $FF in mp,PINB ; Lese LED-Port andi mp,0b00000011 ; Lampen 2 bis 7 anmachen out PORTB,mp ; an LED-Port sw7: in mp,PIND ; Lese Schalter-Port rol mp ; Schiebe siebtes Bit in das Carry-Flag brcs endloop ; Siebtes Bit ist 1 (BRanch if Carry is Set) ldi mp,0xFF ; Alle Lampen aus out PORTB,mp endloop: rjmp loop ; ; Unterprogramm Lampe 0 ; schaltet Lampe 0 ein. Lampe0: in mp,PINB ; Lese aktuellen Zustand von Port B andi mp,0b11111110 ; Lösche Bit 0 mit UND-Befehl out PORTB,mp ; Schreibe Ergebnis zurück ret ; Hole Rücksprungadresse vom Stapel und kehre zurück ; Unterprogramm Lampe 1 ; schaltet Lampe 1 ein Lampe1: in mp,PINB ; Lese Zustand von Port B cbr mp,0b00000010 ; Lösche Bit 2 mit CBR-Befehl out PORTB,mp ; Schreibe Ergebnis zurück ret ; Adresse vom Stapel und zurück