Zorbing icon

[TGI] Versuch12

Zorbing | PRO | 02/06/14 12:41:14 AM UTC | 0 ⭐ | 275 👁️ | Never ⏰ | []
ASM (NASM) |

0 B

|

None

|

0 👍

/

0 👎

; ############################################################
;
;   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

Comments