Code:
;Programm
;CDurTonleiter rauf spielen
.include "m8def.inc"
.def tmp = r16 ;Mein Universallregister
.def tonwert = r17 ;aktueller Wert für den Ton
.def lpm_reg = r0 ;Mein lpm-Register
.equ Summer = PB2 ;Summer an B.2
.equ time0 = 256-255 ;Timer0 für die Tonleiter
.equ time1 = 65536-3600 ;Damit wird der Timer1 vorgeladen, für die Sekunde
.equ daten_laenge = 9 ;Anzahl der Werte
.org 0x000
rjmp reset ;Interruptvektor "reset:"
.org OVF1addr
rjmp pruefSek ;Interruptvektor "pruefSek:"
.org OVF0addr
rjmp timerSummer ;Interruptvektor "timerSummer:"
reset:
;Stack einrichten
ldi tmp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, tmp
ldi tmp, LOW(RAMEND) ;Low-Byte der obersten RAM-Adresse
out SPL, tmp
;Timer Register für Ton werden belegt, hier Timer 0
ldi tmp, (1<<CS02) ;Prescaler ist 256
out TCCR0, tmp ;Register TCCR0 ist für den Prescaller zuständig
ldi tmp, time0 ;Hier wird der Timer vorgeladen
out TCNT0, tmp
;Timer Register für Sekunde werden belegt, hier Timer 1
ldi tmp, (1<<CS12) | (1<<CS10) ;Prescaler ist 1024
out TCCR1B, tmp
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde (10000) speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
ldi tmp, (1<<TOIE0) | (1<<TOIE1);Hier werden Interrupts nach Timer0 Überlauf eingeschaltet
out TIMSK, tmp ;Register TIMSK ist dafür zuständig
;Z-Register mit DB "tonleiter1" füllen
ldi ZH, HIGH(tonleiter1 * 2)
ldi ZL, LOW(tonleiter1 * 2)
sbi DDRB, Summer ;B.2 als Ausgang
sbi PORTB, Summer ;B.2 auf HIGH stellen
sei ;Interrupts zulassen
;Die Hauptschleife, die sich immer wiederholt und den Tonwert neu einliest
main:
lpm ;Daten von tonleiter1: holen
mov tonwert, lpm_reg ;Wrt von lpm_reg in tonwert speichern
rjmp main ;immer wieder zurück zu main springen
;Läuft Timer1 über, so wird erstmal geprüft, ob der letzte Ton
;erreicht ist und der Timer1 wird neu vorgeladen
pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
rjmp tonPruefen ;springe zu "tonPruefen"
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde (10000) speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti ;Spring wieder dahin, wo du hergekommen bist
;Hier wird Z-Zeiger um 1 erhöht. Es wird hier auch verglichen,
;ob der letzte Ton erreicht, wenn ja, dann springt er zu "endeTon"
tonPruefen:
lpm ;Daten von tonleiter1: holen
adiw ZL,1 ;Z um 1 erhöhen, nächstes Byte
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
breq endeTon ;springe zu "endeTon:", wenn letztes Byte ausgelesen
ret ;zurück, wo du hergekommen bist
;Hier wird der Timer gestoppt, indem wir den Prescaler auf 0 setzen
endeTon:
ldi tmp, (0<<CS02) ;Timer stoppen
out TCCR0, tmp
ret ;zurück wo du hergekommen bist
;Läuft Timer0 über, so wird B.2 umgeschaltet, sodass Ton
;aus dem Summer zu hören ist
timerSummer:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
sbis PINB, Summer ;ist B.2 = 1?
rjmp timerSummer1 ;NEIN -> spring zu "timerSummer1:"
cbi PORTB, Summer ;JA -> setze B.2 auf 0
rjmp timerSummer2 ;springe zu "timerSummer2:"
timerSummer1:
sbi PORTB, Summer ;B.2 auf 1 setzen
timerSummer2:
out TCNT0, tonwert ;Timer0 neu vorladen
pop tmp ;SREG wiederholen
out SREG, tmp
pop tmp ;tmp wiederholen
reti
;Das sind die Werte, womit der Timer0 (Tonleiter-Timer) vorgeladen wird
tonleiter1:
.db 256-55, 256-49, 256-44, 256-41 ;Wert zum Vorladen für den Timer
.db 256-37, 256-33, 256-29, 256-27, 0 ;für die Tonleiter
Hab schon überprüft, also richtig hochzählen müsst er ja, also nach 1 Sekunde immer den nächsten Wert holen. Komisch...
Lesezeichen