Code:
;Dieses Programm produziert ein Lauflicht. Bei jedem LED-Wechsel kommt ein kurzer Sound.
.include "m8def.inc"
.equ time1 = 65536-1800 ;Damit wird der Timer1 vorgeladen, für die halbe Sekunde
.equ time0 = 256-57 ;Damit wird der Timer0 vorgeladen, für den Sumer
.equ Summer = PB5 ;Summer an B.5
.def lpm_reg = r0 ;Register, wo Werte von r0 gespeichert werden
.def tmp = r16 ;Mein Universallregister
.def statusLED = r17 ;In diesem Register wird gespeichert, welche LED gerade leuchtet
.org 0x000
rjmp reset ;Interruptvektor "reset:"
.org OVF1addr
rjmp hSekEnde ;Interruptvektor für Timer1 Überlauf, hier springt
;das Programm hin, wenn der Timer überläuft
.org OVF0addr
rjmp tonloop ;Interruptverktor für Timer0 Überlauf, hier springt
;das Programm hin, wenn der Timer überläuft
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
ldi tmp, 0b11111111
out DDRB, tmp ;PortB als Ausgang
ldi statusLED, 0b00000010
out PORTB, statusLED ;Am Anfang soll LED1 leuchten
;Timer Register für halbe Sekunde werden belegt, hier Timer1
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/2 speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
;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
ldi tmp, (1<<TOIE1) | (1<<TOIE0);Hier werden Interrupts eingeschaltet
out TIMSK, tmp ;Register TIMSK ist dafür zuständig
;Z-Register mit DB "tonwerte" füllen
ldi ZH, HIGH(tonwerte * 2)
ldi ZL, LOW(tonwerte * 2)
sei ;Interrupts zulassen
main:
rjmp main ;Immer wieder die main durchlaufen
;********************INTERRUPT-TIMER1********************;
;Jede halbe Sekunde wird geprüft, welche LED an ist und dementsprechen die
;nächste LED angemacht. Die aktuelle wird dabei natürlich ausgeschaltet
hSekEnde:
push tmp ;tmp-Register auf Stack sichern
in tmp, SREG
push tmp ;SREG auf Stack sichern
;TIMER1 wird neu geladen
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 speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
cpi statusLED, 0b00001000 ;Leuchtet die 3. LED?
breq wiederholen ;Wenn JA...
;Wenn NEIN....
adiw ZL, 1 ;Zeiger auf nächstes Byte in "tonwerte"
lsl statusLED ;Register "statusLED" mit 2 multiplizieren
;dadurch verschieben sich alle Bits um 1 nach link ->
;nächste LED blinkt
rjmp endehSek
wiederholen:
sbiw ZL, 2
ldi statusLED, 0b00000010 ;Wieder erste LED leuchten lassen
endehSek:
out PORTB, statusLED ;nächste LED leuchtet
pop tmp
out SREG, tmp ;SREG wiederherstellen
pop tmp ;tmp wiederherstellen
reti ;springe wieder dahin, wo du hergekommen bist
;********************INTERRUPT-TIMER0********************;
tonloop:
push tmp ;tmp-Register auf Stack sichern
in tmp, SREG
push tmp
sbis PINB, Summer ;Ist B.5 = 1?
rjmp umschalten ;NEIN -> auf 1 setzen
cbi PORTB, Summer ;JA -> auf 0 setzen
rjmp endeTon
umschalten:
sbi PORTB, Summer
endeTon:
;Timer neu laden
lpm ;Werte von "tonwerte" in r0 schreiben
mov tmp, lpm_reg
out TCNT0, tmp
pop tmp
out SREG, tmp ;SREG wiederherstellen
pop tmp ;tmp wiederherstellen
reti
;Das sind die Werte, womit der Timer0 (Sound-Timer) vorgeladen wird
;Anzahl der Wert muss GERADE sein
tonwerte:
.db 256-57, 256-14, 256-3, 0
Man hätte es auch mit nur einem Timer lösen können, aber wollte hier mal die Variante mit 2 Timern vorstellen.
Lesezeichen