.include "m16def.inc" ; ============================================================================= ; Interrupt-Vektor-Tabelle ; ============================================================================= .cseg .org 0x000 jmp main ; ============================================================================= ; ; Loesung zu 11.2 c ii) ; ============================================================================= .org 0x008 ; jmp clock_isr ; im Sekundentakt: Ueberlauf von Timer2 ; ============================================================================= ; Tabelle mit Ziffernansteuerung ; Loesung zu 11.2 a i) ; ============================================================================= ; ============================================================================= .org 0x02a digittab: ; Tabelle mit den Ansteuerungsbitmustern: .db 0x3f,0x06 ; 0, 1 .db 0x5b,0x4f ; 2, 3 .db 0x66,0x6d ; 4, 5 .db 0x7d,0x07 ; 6, 7 .db 0x7f,0x6f ; 8, 9 ; ============================================================================= ; Reservierter Speicher fuer Zeitwerte ; ============================================================================= .dseg .org 0x0100 seconds: .byte 1 minutes: .byte 1 hours: .byte 1 ; ============================================================================= ; Beginn Programmcode ; ============================================================================= .cseg .org 0x034 ; ============================================================================= ; Loesung zu 11.2 a ii) ; ============================================================================= digitout: push R16 ldi ZL,low(digittab*2) ; lade den ldi ZH,high(digittab*2) ; entsprechenden add ZL,R17 ; Tabelleneintrag lpm R17, Z ; in R17 ser R16 ; Maske = 0b11111111 out DDRA, R16 ; PORTA in Schreibmodus setzen out PORTA, R17 ; R17 auf PORTA ausgeben pop R16 ret ; ***************************************************************************** ; ***************************************************************************** ; Vorgegebene Unterprogramme ; ***************************************************************************** ; ***************************************************************************** ; INC_SEC ; ------- inc_sec: push R16 ;Register retten. lds R16,seconds ;Sekundenwert holen. cpi R16,$59 ;Bereits $59? breq inc_sec_59 ;Dann Sonderbehandlung. inc R16 sts seconds,R16 ;abspeichern. jmp inc_sec_end ;Das war's. inc_sec_59: clr R16 ;Sekunden auf $00 sts seconds,R16 ;setzen. inc_sec_end: pop R16 ;Register wiederherstellen ret ; INC_MIN ; ------- inc_min: push R16 ;Register retten. lds R16,minutes ;Minutenwert holen. cpi R16,$59 ;Bereits $59? breq inc_min_59 ;Dann Sonderbehandlung. inc R16 sts minutes,R16 ;abspeichern. jmp inc_min_end ;Das war's. inc_min_59: clr R16 ;Minuten auf $00 sts minutes,R16 ;setzen. inc_min_end: pop R16 ;Register wiederherstellen ret ; INC_HOURS ; ------- inc_hours: push R16 ;Register retten. lds R16,hours ;Stundenwert holen. cpi R16,$23 ;Bereits $23? breq inc_hours_23 ;Dann Sonderbehandlung. inc R16 sts hours,R16 ;abspeichern. jmp inc_hours_end ;Das war's. inc_hours_23: clr R16 ;Stunden auf $00 sts hours,R16 ;setzen. inc_hours_end: pop R16 ;Register wiederherstellen ret ; CLOCK_UPDATE ; ------- clock_update: push R16 ;Register retten. call inc_sec ;Sekunden weiterzaehlen. tst R16 ;Ueberlauf (59 -> 00)? brne clock_update_end ;Nein, dann fertig. call inc_min ;Sonst Minuten weiterzaehlen. tst R16 ;Ueberlauf (59 -> 00)? brne clock_update_end ;Nein, dann fertig. call inc_hours ;Sonst Stunden weiterzaehlen. clock_update_end: pop R16 ;Register wiederherstellen. ret ; DIV_8U ; ------- 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 ; ***************************************************************************** ; ***************************************************************************** ; ============================================================================= ; Initialisierung ; Loesung zu 11.2 b i) ; ============================================================================= main: ldi R16,low(RAMEND) ; Stack- out SPL,R16 ; pointer- ldi R17,high(RAMEND) ; initiali- out SPH,R17 ; sierung ser R16 ; R21 <- 0xFF out DDRB,R16 ; PORTA in Schreibemodus setzen ; ============================================================================= ; ; Loesung zu 11.2 c i) ; ============================================================================= ldi R16,(1<<CS22)|(1<<CS20) ; CLK/128 (Prescale) out TCCR2,R16 ; Modus setzen ldi R16,(1<<TCN2UB) ; Bit 3 des Asynchronous Status out ASSR, R16 ; Registers setzen (32768Hz-Takt) ldi R16,(1<<TOIE2) ; Interrupt out TIMSK,R16 ; enablen ; ============================================================================= ; Initialisierung ; Loesung zu 11.2 b ii) ; ============================================================================= loop: lds R16,seconds ; Dividend = Sekunden ldi R17,2 ; Divisor = 2 call div8u ; Unterprogramm aufrufen und dividieren ldi R18,(1<<PINB0) ; 0. Anzeigenelement ldi R18,(1<<PINB4) ; Anzeigenelement (Doppelpunkt) clr R19 ; Segmentwert cpi R17,0 ; bei geraden Sekunden... breq weiter ; ... Doppelpunkt nicht aktivieren ldi R19,1 ; Doppelpunkt an weiter: out PORTB,R18 ; Doppelpunkt setzen out PORTA,R19 ; ... auf den entsprechenden Wert ; ... hier jetzt alle einzelnen Anzeigenelemente durchlaufen ; und auf den jeweiligen Segmentwert setzen... rjmp loop ; Schloop ; ============================================================================= ; Initialisierung ; Loesung zu 11.2 c iii) ; ============================================================================= clock_isr: ; jede Sekunde: call clock_update ; Uhr updaten
Comments