Projektpraktikum Künstliche Intelligenz und Roboterbau

Carl von Ossietzky Universität Oldenburg
Sommersemster 2003
Dozent Dr. Achim Kittel

Home

Erste Vorstellung
Theorie
Hardware
   - Baugruppen
Software
   - Entwicklung
   - Quellcode
Ergebnis
Das Team
Quellen und Links

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