Pfad:
Home =>
AVR-Übersicht =>
Tutorium => Teil 2
(This page in English:
)
; 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 "8515def.inc"
.LIST
; Ein Universalregister definieren:
.DEF mp = R16
; Der Reset-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 an sich auf dem STK200 nicht
; erforderlich, da diese extern 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
;
; 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
; schaltet Lampe 1 ein
Lampe1: IN mp,PINB
; Lese Zustand von Port B
CBR mp,0b00000010
; Lösche Bit 1 mit CBR-Befehl
OUT PORTB,mp
; Schreibe Ergebnis zurück
RET ; Adresse vom
Stapel und zurück
©2002 by http://www.avr-asm-tutorial.net