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 |