Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ; ############################################################
- ;
- ; Fügen Sie in diese Datei bitte Ihren selbst erarbeiteten
- ; Assemblercode ein! Nehmen Sie keine Änderungen am vorge-
- ; gebenen Code vor!
- ;
- ; ############################################################
- .include "m16def.inc"
- ; Symbolische Registernamen und bausteinspezifische
- ; Konstanten importieren
- .dseg
- .org $60
- ; Blockvariablen
- ; ================
- ; ================================
- ; Diese Variablen nicht verändern!
- ; ================================
- block4:
- .byte 8
- block5:
- .byte 8
- block6:
- .byte 8
- block7:
- .byte 8
- block_y:
- .byte 1
- ; ================================
- ; Diese Variablen nicht verändern!
- ; ================================
- ; Variablen
- ; ========================
- ; *** (Ihre Lösung aus Abschnitt 3.1) ***
- figure_pos:
- .byte 1
- block_pos_x:
- .byte 1
- block_pos_y:
- .byte 1
- gameover:
- .byte 1
- seed:
- .byte 1
- start_pos:
- .byte 1
- ; Interrupt-Vektor-Tabelle
- ; ========================
- ; *** (Ihre Lösung aus Abschnitt 3.6) ***
- .cseg
- .org $000 ; Dillsauce
- jmp init
- .org $00C ; OC1Aaddr
- jmp t1comp_isr
- .org $026 ; OC0addr
- jmp t0comp_isr
- ; Unterprogramme
- ; ==============
- .cseg ; Programmspeicher
- .org $030 ; ab Adresse $030 verwenden.
- ; Vorgegebene Unterprogramme einbinden
- ; ------------------------------------
- .include "lcd.asm"
- .include "draw.asm"
- ; INIT_ADC
- ; ----------
- ; Initialisierung von A/D-Converter
- ; I: -
- ; O: -
- init_adc:
- ; *** (Ihre Lösung aus Abschnitt 3.2) ***
- push r16
- ldi r16, (1<<REFS0) | (1<<ADLAR)
- out ADMUX, r16
- ldi r16, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0)
- out ADCSRA, r16
- pop r16
- ret
- ; INIT_TIMER0
- ; ----------
- ; Initialisierung von Timer/Counter0
- ; I: -
- ; O: -
- init_timer0:
- ; *** (Ihre Lösung aus Abschnitt 3.3) ***
- push r16 ; Register retten.
- clr r16 ; Normale Betriebsart,
- ldi r16, (1<<WGM01) | (1<<CS02) | (1<<CS00) ; Bits für Timer Control Register setzen
- out TCCR0, r16 ; setzen des Timer/Counter 0 Control Register
- ldi r16, 39 ; Vergleichswert setzen (entspricht Abtastung von 25Hz)
- out OCR0, r16 ; und speichern
- ldi r16, (1<<OCIE0) ; Interrupterzeugung bei Erreichen des Vergleichswerts A von Timer 0 aktivieren.
- out TIMSK, r16 ; Setzen des Timer/Counter Interrupt Mask Register
- pop r16 ; Register wiederherstellen.
- ret ; Zurueck.
- ; INIT_TIMER1
- ; ----------
- ; Initialisierung von Timer/Counter1
- ; I: -
- ; O: -
- init_timer1:
- ; *** (Ihre Lösung aus Abschnitt 3.4) ***
- push r16 ; Register retten.
- clr r16 ; Normale Betriebsart,
- out TCCR1A, r16 ; Setzen des Timer/Counter 1 Control Register A
- ldi r16, (1<<WGM12) | (1<<CS11) | (1<<CS10) ; keine Ausgabe über OC1A/OC1B, Bits für Timer Control Register setzen
- out TCCR1B, r16 ; Setzen des Timer/Counter 1 Control Register B
- ldi r16, high(3906) ; Vergleichswert setzen erst High-...dann Low-Byte
- out OCR1AH, r16 ;
- ldi r16, low(3906) ;
- out OCR1AL, r16 ;
- in r16, TIMSK ; Interrupterzeugung bei Erreichen des Vergleichswerts A von Timer 1 aktivieren.
- ori r16, (1<<OCIE1A) ; Hinweis: Beachten Sie dass die Interrupts für alle Timer in dem selben Register gesetzt werden!
- out TIMSK, r16 ; Setzen des Timer/Counter Interrupt Mask Register
- pop r16 ; Register wiederherstellen.
- ret ; Zurueck.
- ; READ_ADC
- ; ----------
- ; Liest Daten vom ADC und gibt sie in R16 zurück
- ; I: -
- ; O: Der gewandelte Wert in R16
- read_adc:
- ; *** (Ihre Lösung aus Abschnitt 3.2) ***
- sbi ADCSRA, ADSC
- wait_adc:
- sbic ADCSRA, ADSC
- rjmp wait_adc
- in r16, ADCH
- ret
- ; T0COMP_ISR
- ; ----------
- ; (Interrupt-Service-Routine)
- ; ADC auslesen und Display ansteuern
- t0comp_isr:
- ; *** (Ihre Lösung aus Abschnitt 3.3) ***
- push r16
- in r16, SREG
- push r16
- push r17
- call read_adc ; Wert vom Poti auslesen
- ldi r17, 12
- call div8u ; AD-Wert durch 12 teilen
- sts figure_pos, r16 ; neue Position speichern
- call draw_figure ; Figur zeichnen
- pop r17
- pop r16
- out SREG, r16
- pop r16
- reti
- ; T1COMP_ISR
- ; ----------
- ; (Interrupt-Service-Routine)
- ; Inkrementiert die Blockposition und zeichnet Block neu
- t1comp_isr:
- ; *** (Ihre Lösung aus Abschnitt 3.4) ***
- push r16
- in r16, SREG
- push r16
- push r17
- push r18
- lds r17, block_pos_y ; lade block_pos_y
- inc r17 ; inkrementiere
- cpi r17, 70 ; vergleiche mit 70
- brlo no_collision_check ; ueberpruefe die kollision nur, falls
- call check_collision ; die y-Position des Blocks >= 70 ist
- no_collision_check:
- cpi r17, 78 ; ist die y-Position des Blocks gleich 78,
- brne not_grounded ; dann setze den Block zurueck
- lds r17, start_pos ; auf die Startposition
- call lfsr
- sts block_pos_x, r16 ; setze die x-Position des Blocks auf einen Zufallswert (lfsr)
- not_grounded:
- sts block_pos_y, r17
- call draw_box
- ; passe die Block-Geschwindigkeit an
- in r16, OCR1AL
- in r17, OCR1AH
- subi r16, 10
- brpl sub_fertig
- cpi r17, 5
- brlo reached_limit ; hart am Limit!
- ldi r18, 0xFF
- add r16, r18 ; Zimt
- subi r17, 1 ; Muskatnuss
- rjmp sub_fertig
- reached_limit:
- ldi r16, 0 ; zurueck mit dir
- ldi r17, 4 ; weiche Teufel...
- sub_fertig:
- out OCR1AL, r16 ; setze zaehler
- out OCR1AH, r17 ; neu
- pop r18
- pop r17
- pop r16
- out SREG, r16
- pop r16
- reti
- ; CHECK_COLLISION
- ; Überprüft, ob Box und Figur kollidieren
- ; I: -
- ; O: -
- check_collision:
- ; *** (Ihre Lösung aus Abschnitt 3.5) ***
- push r16
- push r17
- lds r16, block_pos_x
- lds r17, figure_pos
- sub r16, r17
- cpi r16, 0
- brlo collision_end ; die Box ist links von der Figur
- cpi r16, 9
- brsh collision_end ; die Box ist rechts von der Figur
- ldi r16, 1
- sts gameover, r16 ; Spiel vorbei...
- collision_end:
- pop r17
- pop r16
- ret
- ; Systeminitialisierung und Hauptprogramm
- ; =======================================
- ; Systeminitalisierung
- ; --------------------
- init:
- ; *** (Ihre Lösung aus Abschnitt 3.6) ***
- ldi r16, high(RAMEND)
- out SPH, r16
- ldi r16, low(RAMEND)
- out SPL, r16
- call lcd_init
- call init_timer0
- call init_timer1
- call init_adc
- sbi PINC, PINC0
- ; Hauptprogramm
- ; -------------
- main:
- ; *** (Ihre Lösung aus Abschnitt 3.7) ***
- ; *** Eigene Lösungsvorschläge sind auch erlaubt ***
- call lcd_startdisplay ; rufe den Startdisplay auf
- ldi r16, 0 ; setze gamover auf '0'
- sts gameover, r16 ; und speichere dies
- in r17, PINC ; lade PINC in r16
- startloop:
- in r16, PINC ; solange es keine Veränderung gibt
- cp r16, r17
- breq startloop ; springe zurück
- call lcd_clear
- in r16, TCNT1L ; wenn Taster gedrückt wurde
- cpi r16, 0 ; dann lade den Timerwert als seed
- brne set_seed ; wenn er gleich 0 ist
- ldi r16, $42 ; dann wähle eine andere Zahl als seed
- set_seed:
- sts seed, r16 ; und speichere den seed
- call lfsr
- sts block_pos_x, r16 ; setze auch gleich den Start des Blocks
- lds r17, start_pos
- sts block_pos_y, r17 ; auch in y-Richtung
- sei ; und aktiveier die Interrupts
- mainloop:
- lds r16, gameover ; gameover?
- cpi r16, 1 ; wenn nein, dann warte weiter
- brne mainloop
- maingameover: ; wenn doch,
- cli ; dann sperre Interrupts
- call lcd_gameover ; und schreibe gameover
- call init_timer1 ; Timer 1 initialisieren
- rjmp main
- ; =======================================
- ; =======================================
- ; VORGEGEBENE UNTERPROGRAMME
- ; =======================================
- ; =======================================
- ; LFSR
- ; --------
- ; Linear rückgekoppeltes Schieberegister
- ; Verwendet für das Fibonacci-LFSR das Generatorpolynom x^8+x^6+x^5+x^4+1
- ; Gibt eine Zufallszahl zwischen 11 und 15 zurück
- ; I: Erwartet in der Variablen "seed" einen Seed bzw. den alten Schieberegisterwert
- ; O: R16: Zufallszahl
- lfsr:
- push R15 ; Register sichern
- push R17
- clr R17
- lds R16, seed
- sbrc R16, 7 ; Bit x^8
- inc R17
- sbrc R16, 5 ; Bit x^6
- inc R17
- sbrc R16, 4 ; Bit x^5
- inc R17
- sbrc R16, 3 ; Bit x^4
- inc R17
- inc R17 ; +1
- andi R17, 1 ; Bitmaske mit 1
- lsl R16 ; shifte alten Wert nach links
- or R16, R17 ; und addiere Wert aus Polynom drauf
- sts seed, R16 ; speichere Wert wieder ab.
- ldi R17, 12 ; lade 12 in R17
- call div8u ; und berechne R15 = R16/12
- mov R16, R15 ; schreibe das Ergebnis in R16 zurück
- subi R16, -4 ; und addiere eine 4 drauf
- pop R17 ; Register wieder herstellen
- pop R15
- ret
- ; DIV8U
- ; ----------
- ; 8/8 Division (unsigned)
- ; I: R16: Dividend, R17: Divisor
- ; O: R16: Ergebnis, R15: Rest
- div8u: push R18
- clr r15 ; clear remainder and carry
- ldi r18,9 ; init loop counter
- d8u_1: rol r16 ; shift left dividend
- dec r18 ; decrement counter
- brne d8u_2 ; if done
- pop R18
- ret ; return
- d8u_2: rol r15 ; shift dividend into remainder
- sub r15,r17 ; remainder = remainder - divisor
- brcc d8u_3 ; if result negative
- add r15,r17 ; restore remainder
- clc ; clear carry to be shifted into result
- rjmp d8u_1 ; else
- d8u_3: sec ; set carry to be shifted into result
- rjmp d8u_1
- ; Vorgegebenes Unterprogramm "warte":
- ; Routine zur Verzoegerung des Programmablaufs
- ; Parameter: R16: Verzoegerungszeit in 100us
- warte: push R16 ; Register sichern
- push R17
- warte_schleife1:
- ldi R17, 32
- nop
- warte_schleife2:
- dec R17 ; innere Schleife (Laufzeit 100us)
- brne warte_schleife2 ; die dann R16 mal abgearbeitet wird
- dec R16
- brne warte_schleife1
- pop R17
- pop R16 ; Register wiederherstellen
- ret
- ; Vorgegebenes Unterprogramm "warte_1s":
- ; Routine zur Verzoegerung des Programmablaufs
- ; Wartet 1 Sekunde
- warte_1s:
- push R16
- push R17
- ldi R17, 250
- warte_1s_schleife:
- ldi R16, 250
- call warte
- dec R17
- brne warte_1s_schleife
- pop R17
- pop R16
- ret
Advertisement
Add Comment
Please, Sign In to add comment