Code:
;Programm
;CDurTonleiter rauf und runter spielen
.include "m8def.inc"
.def tmp = r16 ;Mein Universallregister
.def zaehlerSek = r17 ;Mein Zählregister
.def tonwert = r19 ;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 time2 = 256-90 ;Damit wird der Timer2 vorgeladen, für die Sekunde
.equ daten_laenge = 4 ;Anzahl der Werte
.org 0x000
rjmp reset ;Interruptvektor "reset:"
.org OVF2addr
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 512
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 2
ldi tmp, (1<<CS22) | (1<<CS21) | (1<<CS20) ;Prescaler ist 1024
out TCCR2, tmp ;Register TCRR2 ist für den Prescaller zuständig
ldi tmp, (1<<TOIE0) | (1<<TOIE2);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
;Hier wird der nächste Ton geladen und in "tonwert" gespeichert
;Z-Zeiger wird um 1 erhöht, damit er beim nächsten mal den nächsten
;Ton lädt. Es wird hier auch verglichen,, ob der letzte Ton erreicht,
;wenn ja, dann springt er zu "endeTon"
tonLaden:
clr zaehlerSek ;ZählerSek auf 0 setzen
lpm ;Daten von tonleiter1: holen
mov tonwert, lpm_reg ;erstes Byte in tmp verschieben
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
rjmp main ;sonst springe zu "main:"
;Hier wird der Timer gestoppt, indem wir den Prescaler auf 0 setzen
endeTon:
ldi tmp, (0<<CS02) ;Timer stoppen
out TCCR0, tmp
;Die Hauptschleife, die sich immer wiederholt
main:
cpi zaehlerSek, 0b00101000 ;ist zaehlerSek = 40 (also 1 Sekunde um?)
breq tonLaden ;wenn ja, dann lade den nächsten Ton
rjmp main ;immer wieder zurück zu main springen
;Läuft Timer2 über, so wieder zaehlerSek um 1 erhöht und
;Timer2 neu vorgeladen
pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
inc zaehlerSek ;ZählerSek um 1 erhöhen
ldi tmp, time2 ;Hier wird der Timer vorgeladen
out TCNT2, tmp
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti ;Spring wieder dahin, 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 ;zu "timerSummer2:" springen
timerSummer1:
sbi PORTB, Summer ;wenn B.2 = 0 ist, dann auf 1 setzen
;Hier wird Timer0 mit dem aktuellen Tonwert vorgeladen
timerSummer2:
out TCNT0, tonwert ;Timer dementsprechen vorladen
timerSummer3:
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-117, 256-16, 256-2, 0 ;Werte zum Vorladen des Timers für die Töne
;c', a' und c''
Ich hoffe, er ist nicht wieder so unübersichtlich.
Lesezeichen