Carl von Ossietzky Universität Oldenburg
Sommersemster 2003
Dozent Dr. Achim Kittel
|
Erste Vorstellung |
Der Quellcode des Microcontrollers
; Roboterfahrprogramm des Praktikums "Kuenstliche Intelligenz und Roboterbau" an
; der Carl von Ossietzky Univesitaet Oldenburg im SoSe 2003.
; Aufgabe: Infrarotsignal in einem Raum suchen und Anfahren.
; Implementierte Funktionen:
; - Suchschleife fahren
; - Daten der Abstandssensoren verarbeiten und Hindernissen ausweichen
; - Kollisionstaster ueberwachen
; - IR-Signal mit Infrarotempfaenger erkennen
; - Vor Ziel zum Stehen kommen
;
; Autoren: Ludwig Worbes ludwig.worbes@mail.uni-oldenburg.de
; Robert Berganski robert.berganski@fortytwo.uni-oldenburg.de
; Per Petersen per.s.petersen@mail.uni-oldenburg.de
; Juli 2003
.nolist
.include "C:\Atmel\AVR Tools\AvrAssembler\Appnotes\m32def.inc"
.list
; Register deklarieren
.def wb=R0 ; Variable fuer die obere Grenze des TCCR0 definieren
.def wd=R1 ; Variable fuer die obere Grenze des TCCR1B definieren
.def mb=R2 ; Motorparameter am Motor0
.def md=R3 ; Motorparameter am Motor1
.def tg=R4 ; Toggle-Register
.def al=R5 ; Datenregister linker ABstandssensor
.def ar=R6 ; Datenregister linker ABstandssensor
.def mp=R16 ; Temporaeres Register
.def mq=R17 ; Temporaeres Register
.def rs=R18 ; Register zur SREG-Sicherung
.def sp=R19 ; Geschwindigkeitszaehler
.def na=R20 ; Navistatusregister
.def ad=R21 ; Bit-Maske fuer den AD-Wandler definieren
.def sc=R22 ; Streckenregister der Suchschleife
.def sh=R24 ; 16-bit Register aus R24 und R25. sh:sl ist
.def sl=R25 ; der Streckezaehler.
; Interrupts initialisieren
.org 0x0000
rjmp main
.org 0x0002 ; Int0-Interrupt (extern)
rjmp right ; Rechter Kollisionstaster
.org 0x0004 ; Int1-Interrupt (extern)
rjmp left ; Linker Kollisionstaster
RETI
RETI
RETI
RETI
RETI
RETI
RETI
RETI
.org 0x0016 ; Timer/Counter 0 Overflow
rjmp distance ; Schrittzaehler
RETI
RETI
RETI
RETI
.org 0x0020 ; ADC Conversation Complete
rjmp scan ; Entfernungsmessung verarbeiten
RETI
RETI
RETI
RETI
; Beginn Hauptprogramm --------------------------------------------------------------
main:
ldi mp,LOW(RAMEND) ; Initialisierung des Stackpointers
out SPL,mp ;
ldi mp,HIGH(RAMEND) ;
out SPH,mp ;
; Initialisierung AD-Wandler
ldi mp,0b01100000
out ADMUX,mp ; AD-Multiplexer initialisieren
ldi ad,0b11000110 ; Status des ADCSR setzen - IRQ disabled
out ADCSR,ad ; Scan ausfuehren
; Ein- und Ausgaenge definieren
ldi mp,0xF3
out DDRD,mp ; PortD: Pin 2 und 3 Eingang, Rest Ausgang
ldi mp,0xFF
out DDRB,mp ; PORTB: Alle Pins als Ausgang
out PORTB,mp ; PortB: Pins einen definierten Zustand geben
out PORTD,mp ; PortD: Pins einen definierten Zustand geben
out PinD,mp ; PortD: Pins auf 1 setzen
ldi mp,0b00000000
out DDRC,mp ; PortC: Alle Pins als Eingang
ldi mp,0xFE
out PORTC,mp ; PortC: Pins einen definierten Zustand geben
out PinC,mp ; PortC: Pin 0 auf 0 setzen
; Status der Stepperboards setzen
ldi mp,0b01000000
out PORTB,mp
ldi mp,0b00001100
out PORTD,mp
; Hardwarecounter initialisieren
ldi mp,0b00011011 ; Initialisierung des Timer/Counter Control-Registers 0
out TCCR0,mp ; Prescaler auf 64 gesetzt
ldi mp,0b00011100 ; Initialisierung des Timer/Counter Control-Registers 2
out TCCR2,mp ; Prescaler auf 64 gesetzt
; Output Compare Register laden
ldi mp,255
mov wb,mp
mov wd,mp
out OCR0,wb ; Obere Grenze OCR0 auf Maximum setzen
out OCR2,wd ; Obere Grenze OCR2 auf Maximum setzen
; Externe Interrupts
ldi mp,0b00001010
out MCUCR,mp ; Externe Interrupts freischalten
; Register laden
ldi mp,0b00001111
mov tg,mp ; Toggle Register zur Abstandssensorwahl laden
ldi na,0b00001000 ; Navistatusregister laden; Beginn mit Suchdrehung
ldi sc,0x04 ; Streckenregister der Suchschleife laden
; Schleife zur Tasterabfrage --------------------------------------------------------
start:
nop
nop
nop
nop
sbic PINC,6 ; Prüfen, ob Taster an PinC 6 betaetigt wird
rjmp start
; Navigationsabschnitt --------------------------------------------------------------
navi:
ldi sp,0
sbrc na,0
rjmp back ; Parameter zum Zuruecksetzen einlesen
sbrc na,1
rjmp turnleft ; Parameter zur Linksdrehung einlesen
sbrc na,2
rjmp turnright ; Parameter zur Rechtsdrehung einlesen
sbrc na,3
rjmp cycle ; Parameter der Suchdrehung einlesen
sbrc na,6
rjmp main ; Ziel erreicht, an den Anfang springen
sbrc na,7
rjmp ahead ; Parameter zur Zielanfahrt einlesen
; Parameter fuer Vorrausfahrt
ldi na,0b00001000 ; Navistatusregister fuer die Suchdrehung setzen
ldi mp,0xAA
mov wb,mp ; Grenze des Hardwarecounters 0 (OCR0) laden
mov wd,mp ; Grenze des Hardwarecounters 2 (OCR2) laden
ldi mp,0b00100100
mov mb,mp ; Motorparameter fuer PortB laden
ldi mp,0b01101101
mov md,mp ; Motorparameter fuer PortD laden
mov sh,sc ; Strecke der Suchschleife laden
ldi ad,0b11001110 ; Werte fuer AD-Wandler laden
jmp input
; Parameter fuer Zielanfahrt
ahead:
ldi na,0b11000000 ; Navistatusregister fuer die Zielanfahrt setzen
ldi mp,0xAA
mov wb,mp ; Grenze des Hardwarecounters 0 (OCR0) laden
mov wd,mp ; Grenze des Hardwarecounters 2 (OCR2) laden
ldi mp,0b00100100
mov mb,mp ; Motorparameter fuer PortB laden
ldi mp,0b01101101
mov md,mp ; Motorparameter fuer PortD laden
ldi sh,0x2C ; Strecke im oberen Register setzen
ldi sl,0xFF ; Strecke im unteren Register setzen
ldi ad,0b11001110 ; Werte fuer AD-Wandler laden
jmp input
; Parameter fuer Zuruecksetzen
back:
dec na ; Navistatusregister fuer Suchstrecke setzen
ldi mp,0xAA
mov wb,mp ; Grenze des Hardwarecounters 0 (OCR0) laden
mov wd,mp ; Grenze des Hardwarecounters 2 (OCR2) laden
ldi mp,0b01100100
mov mb,mp ; Motorparameter fuer PortB laden
ldi mp,0b00101101
mov md,mp ; Motorparameter fuer PortD laden
ldi sh,0x0F ; Strecke im oberen Register setzen
ldi sl,0x0C ; Strecke im unteren Register setzen
ldi ad,0b11000110 ; Werte fuer AD-Wandler laden - IRQ disabled
jmp input
; Parameter fuer Linksdrehung
turnleft:
ldi na,0b00000000 ; Navistatusregister Null setzen
ldi mp,0xAA
mov wb,mp ; Grenze des Hardwarecounters 0 (OCR0) laden
mov wd,mp ; Grenze des Hardwarecounters 2 (OCR2) laden
ldi mp,0b00100100
mov mb,mp ; Motorparameter fuer PortB laden
ldi mp,0b00101101
mov md,mp ; Motorparameter fuer PortD laden
ldi sh,0x02 ; Strecke im oberen Register setzen
ldi sl,0xC2 ; Strecke im unteren Register setzen
ldi ad,0b11000110 ; Werte fuer AD-Wandler laden - IRQ disabled
jmp input
; Parameter fuer Rechtsdrehung
turnright:
ldi na,0b00000000 ; Navistatusregister Null setzen
ldi mp,0xAA
mov wb,mp ; Grenze des Hardwarecounters 0 (OCR0) laden
mov wd,mp ; Grenze des Hardwarecounters 2 (OCR2) laden
ldi mp,0b01100100
mov mb,mp ; Motorparameter fuer PortB laden
ldi mp,0b01101101
mov md,mp ; Motorparameter fuer PortD laden
ldi sh,0x01 ; Strecke im oberen Register setzen
ldi sl,0xFA ; Strecke im unteren Register setzen
ldi ad,0b11000110 ; Werte fuer AD-Wandler laden - IRQ disabled
jmp input
cycle:
ldi na,0000000000 ; Navistatusregister Null setzen
ldi mp,0xAA
mov wb,mp ; Grenze des Hardwarecounters 0 (OCR0) laden
mov wd,mp ; Grenze des Hardwarecounters 2 (OCR2) laden
ldi mp,0b01100100
mov mb,mp ; Motorparameter fuer PortB laden
ldi mp,0b01101101
mov md,mp ; Motorparameter fuer PortD laden
inc sc ; Suchschleifenstrecke erhoehen
ldi sh,0x12 ; Strecke im oberen Register setzen
ldi sl,0x8F ; Strecke im unteren Register setzen
ldi ad,0b11000110 ; Werte fuer AD-Wandler laden - IRQ disabled
;------------------------------------------------------------------------------------
; Parameter einlesen
input:
out OCR0,wb ; Grenze des Hardwarecounters 0 (OCR0) schreiben
out OCR2,wd ; Grenze des Hardwarecounters 2 (OCR2) schreiben
out PORTB,mb ; Motorparameter PortB schreiben: Einschalten und Richtung geben
out PORTD,md ; Motorparameter PortB schreiben: Einschalten und Richtung geben
ldi mp,0b00000010
out TIMSK,mp ; Ueberlaufinterrupt des Hardwarecounters 0 freischalten
ldi mp,0b11000000
out GICR,mp ; Externe Interrupts Int0 und Int1 freischalten
ldi mp,0b01100000
out ADMUX,mp ; Im AD-Wandler Vergleichsspannung waehlen und 8-bit Ergebnis einstellen
sei ; Alle Interrupts einschalten
;------------------------------------------------------------------------------------
; Warteschleife waehrend der Suche
loop:
nop
nop
sbrc na,7
rjmp found
sbis PINC,0 ; Empfaenger am PinC 0 ueberwachen
ldi na,0b10000000 ; Navistatusregister setzen, wenn Ziel gefunden
sbis PINC,0 ; Empfaenger am PinC 0 ueberwachen
ldi sc,0xFF ; Maximale Strecke laden
sbis PINC,0 ; Empfaenger am PinC 0 ueberwachen
rjmp stop
rjmp loop
; Warteschleife nach Finden des Zieles
found:
nop
nop
nop
nop
rjmp found
;------------------------------------------------------------------------------------
; Stoproutine
stop:
ldi mp,0b00000000
out PORTB,mp ; Motor an Port B ausschalten
ldi mp,0b00001100
out PORTD,mp ; Motor an Port D ausschalten
ldi mp,0
out TIMSK,mp ; Ueberlaufinterrupt des Hardwarecounters 0 abschalten
ldi sh,0 ; Oberes Streckenregister null setzen
ldi sl,0 ; Unteres Streckenregister null setzen
sbrs na,4 ; Test, ob Abstandssensoren Hindernis gemessen haben
rjmp navi
; Winkel "berechnen"
cp ar,al ; Vergleich der letzten Abstandsmessungen je Sensor
brlo lower ; Verzweigen, wenn rechte Messung kleiner als linke Messung
ldi na,0b00000010 ; Navistatusregister fuer Linksdrehung setzen
rjmp navi
lower:
ldi na,0b00000100 ; Navistatusregister fuer Rechtsdrehung setzen
rjmp navi
;-----------------------------------------------------------------------------------------
distance:
in rs,SREG
dec sl ; Alle 256 Takte Geschwindigkeitsaenderung moeglich
brbc 1,clear
cpi sp,20 ; Test, ob maximale Beschleunigungerreicht wurde
brbc 0,decspeed
cp sh,sp ; Sicherheit, dass genug Wegstrecke vorhanden ist
brbs 0,decspeed
ldi mp,4 ; erhoehe Geschwindigkeit
sub wb,mp ;
sub wd,mp ;
out OCR0,wb ;
out OCR2,wd ;
inc sp
jmp clear
decspeed:
cp sh,sp ; Test, ob Bremsweg erreicht
brbc 0,clear
in mp,OCR0 ; verringere Geschwindigkeit
ldi mq,168
cp mq,mp
brbs 0,clear
ldi mp,1
add wb,mp ;
add wd,mp ;
out OCR0,wb ;
out OCR2,wd ;
clear:
swap tg
sbrs tg,0
ldi mp,0b01100000
sbrc tg,0
ldi mp,0b01100001
out ADMUX,mp
out ADCSR,ad ; scannen
tst sl ; Die letzten 8 bit des16-bit-Registers werden erniedrigt
brbs 1,decsh
out SREG,rs
reti
decsh:
dec sh ; Die ersten 8 bit des16-bit-Registers werden erniedrigt
in mp,SREG
sbrc mp,1
rjmp stop ; warum funktioniert Carry-Flag nicht? Egal, muss sh+1 beachtet werden.
out SREG,rs
reti
;-----------------------------------------------------------------------------------------
; Interrupt-Routinen fuer Fuehler
left:
in rs,SREG
ldi mp,0b00000000 ; Motor an Port B ausschalten
out PORTB,mp ;
ldi mp,0b00001100 ; Motor an Port D ausschalten
out PORTD,mp ;
sbrc na,7
rjmp aus
ldi na,0b00000011
ldi sh,0
ldi sl,0
out SREG,rs
sei
rjmp navi
right:
in rs,SREG
ldi mp,0b00000000 ; Motor an Port B ausschalten
out PORTB,mp ;
ldi mp,0b00001100 ; Motor an Port D ausschalten
out PORTD,mp ;
sbrc na,7
rjmp aus
ldi na,0b00000101
ldi sh,0
ldi sl,0
out SREG,rs
sei
rjmp navi
;-----------------------------------------------------------------------------------------
; Interrupt-Routine fuer AD-Wandlung
scan:
in rs,SREG
in mp,ADCH
sbrs tg,0
mov ar,mp
sbrc tg,0
mov al,mp ;
cpi mp,180 ; Bei Schwellenueberschreitung -> Notaus
brbc 2,end ; springt in Ende, wenn Abbruchentfernung noch nicht erreicht
sbrc na,7
rjmp reached
ldi na,0b00010000
out SREG,rs
sei
rjmp stop
end:
out SREG,rs
sei
rjmp loop
reached:
out SREG,rs
sei
rjmp stop
|