Code:
.include "TN15def.inc" ; Prozessor ATtiny15
.cseg ; Kennung für Programmcode
.def TMP = R0 ; Allgemeine Variable für Rückgabewerte
.def TMP1 = R16 ; Allgemeine Variable
.def Status = R20 ; Statusregister für Betriebszustände
.def Helligkeit = R21 ; Wert für PWM Regelung
.def KeyOld = R26 ; Taster die gedrückt waren
.def KeyNew = R27 ; Taster die gedrückt sind
.def KeyEnter = R28 ; Taster die neu gedrückt wurden
.def KeyExit = R29 ; Taster die neu losgelassen wurden
.def ZL = R30 ; 16-Bit Variable L-Byte
.def ZH = R31 ; 16-Bit Variable H-Byte
; Status 7 6 5 4 3 2 1 0
; |_ 0=Lampe aus, 1=Lampe an
.org 0x0000 ; Programm Startadresse $0000
rjmp Init ; Einsprung ins Hauptprogramm
.org 0x0001 ; Interrupt Pin 7 (INT0)
rjmp Int0i ; Sprung zu INT0-Interrupt
Init:
; *******************************************************
; * Internen Oszillator kalibrieren *
; *******************************************************
ldi ZL, low (2*Kalibrierung) ; Low-Byte Endadresse Flashspeicher lesen
ldi ZH, high(2*Kalibrierung) ; High-Byte Endadresse Flashspeicher lesen
lpm ; Kalibrierungsbyte auslesen
ser ZL ; $FF in ZL setzen für Vergleich
cpse TMP, ZL ; Kalibrierungsbyte gültig? (Nein, wenn $FF)
out OSCCAL, TMP ; Ja, dann Chip kalibrieren und danach
clr ZL ; den Vergleich löschen.
; *******************************************************
; * Statusregister löschen und PowerDown vorbereiten *
; *******************************************************
mov Status, ZL ; Statusregister löschen.
in TMP1, MCUCR ; Controllregister des Prozessors einlesen
cbr TMP1, 1<<ISC01 | 1<<ISC00 ; Interrupt an INT0 auf Low-Level stellen
out MCUCR, TMP1 ; und speichern.
in TMP1, TCCR1 ; Timer1 Kontrollregister für PWM
sbr TMP1, 1<<PWM1 | 1<<CS12 | 1<<CS11 | 1<<CS10 ; vorbereiten und
out TCCR1, TMP1 ; speichern..
; *******************************************************
; * Ports des ATtiny15 einstellen *
; *******************************************************
ldi TMP1, 1<<DDB4 | 1<<DDB3 | 1<<DDB1 ; Pin 2, 3, 6 auf Ausgabe schalten.
out DDRB, TMP1 ; schalten und entsprechende
com TMP1
out PORTB, TMP1 ; PullUp-Widerstände einschalten.
in TMP1, PORTB ; Aktuellen Portinhalt einlesen und
ori TMP1, 0b011000 ; grüne + rote LED ausschalten
out PORTB, TMP1 ; neuen Zustand ausgeben.
ldi Helligkeit, 0xC0 ; Startwert 40% Helligkeit
; *******************************************************
; * Interrupts freigeben *
; *******************************************************
in TMP1, GIMSK ; Interrupt an INT0 (Taster Aus/Ein) freigeben
sbr TMP1, 1<<INT0
out GIMSK, TMP1 ; und speichern.
sei ; Interrupts freigeben.
rcall PowerDown ; Prozessor in PowerDown-Modus versetzen.
; >>>>>>> Hauptprogramm Anfang <<<<<<<
Start:
rcall KeyCheck ; Tasten abfragen
cpi KeyExit, 0x01 ; Taste Helligkeit gedrückt $01
brne Taste1 ; Nein, dann nächste Taste.
tst Status ; Ist die Lampe ausgeschaltet? Ja, dann
breq TastEnde ; nicht Taste heller/dunkler auswerten.
rcall Dimmer ; Sprung nach Dimmroutine
rjmp TastEnde ; Spung an Auswerteende.
Taste1:
cpi KeyExit, 0x04 ; Taste "Ein/Aus" gedrückt $04
brne TastEnde ; Nein, dann weiter, sonst
rcall EinAus ; Sprung nach Ein- Ausschaltroutine
TastEnde:
rjmp Start
; >>>>>>>> Hauptprogramm Ende <<<<<<<<
; >>>>>>>> INTERRUPTPROGRAMME <<<<<<<<
; *******************************************************
; * INT0-Interrupt *
; *******************************************************
Int0i:
in TMP1, GIMSK ; Interrupt-Freigaberegister einlesen und
cbr TMP1, 1<<INT0 ; INT0-Interrupt sperren um Prozessor
out GIMSK, TMP1 ; beim Aufwachen nicht zu stören.
reti ; Rücksprung.
; >>>>>>>>>> UNTERPROGRAMME <<<<<<<<<<
; *******************************************************
; * Tasterabfrage mit Entprellung *
; *******************************************************
; * Keyenter (R28) = Rückgabe neu gedrückte Taste *
; * Keyexit (R29) = Rückgabe der losgelassenen Taste *
; * Taste an PB0 (Hell/Dunkel) = 01 *
; * Taste an PB2 (Ein/Aus) = 04 *
; *******************************************************
KeyCheck: ; Unterprogramm zur Tastaturabfrage
ldi KeyEnter, 0
ldi KeyExit, 0
in KeyNew, PINB ; Lade PB
com KeyNew ; invertieren
andi KeyNew, 0b000101 ; Maskieren der nicht verwendeten Pins
cpse KeyOld, KeyNew ; Test ob Veränderung
rjmp KeyAction ; Veränderung
ret
; alles gleich
KeyAction:
rcall Wait12ms ; etwas warten
in ZL, PINB ; nochmal einlesen
com ZL ; invertieren bei neg. Logik
andi ZL, 0b000101 ; maskieren der nicht verwendeten Pins
cpse KeyNew, ZL ; ist es stabil
ret ; war nix, da nicht stabil
mov KeyEnter, KeyOld
com KeyEnter ; invertieren
and KeyEnter, KeyNew ; steigende Flanken, !alt & neu
mov KeyExit, KeyNew
com KeyExit ; invertieren
and KeyExit, KeyOld ; fallende Flanken, alt & !neu
mov KeyOld, KeyNew ; alt := neu
ret ; Interrupt verlassen
Dimmer:
; *******************************************************
; * Taster für Dimmstufen $01 *
; *******************************************************
subi Helligkeit, 0x40 ; Bei jedem Aufruf Helligkeitswert -40
out OCR1A, Helligkeit ; Neuen wert ins PWM-Vergleichsregister
ret ; Lampe wird heller. Rücksprung
EinAus:
; *******************************************************
; * Ein- / Ausschalter $04 an INT0 *
; *******************************************************
cpi Status, 0x00 ; Lampe ausgeschaltet?
breq LampeEin ; Dann Lampe einschalten, sonst im
cbr Status, 1 ; Statusregister Lampe ein löschen..
in TMP1, PORTB ; PortB einlesen und.
sbr TMP1, 0b001000 ; LED grün durch H-Pegel ausschalten.
out PORTB, TMP1 ; PortB ausgeben.
in TMP1, TCCR1 ; PWM-Timer Steuerregister laden und
cbr TMP1, 1<<COM1A1 | 1<<COM1A0 | 1<<CS12 | 1<<CS11 | 1<<CS10 ; diesen ausschalten.
out TCCR1, TMP1 ; Alles Speichern.
in TMP1, PORTB ; Falls Scheinwerfer-LED Ausgang geschaltet
cbr TMP1, 1<<PORTB1 ; ist, diesen auf jeden Fall ausschalten.
out PORTB, TMP1 ; LED wird sonst zerstört!
in TMP1, GIMSK ; Vor PowerDown-Modus Interrupt
sbr TMP1, 1<<INT0 ; INT0 wieder freigeben. Über diesen wird
out GIMSK, TMP1 ; der Prozessor aufgeweckt.
rcall PowerDown ; PowerDown-Modus aktivieren.
ret ; Rücksprung.
LampeEin:
sbr Status, 1 ; Kennung für Lampe an setzen
ldi TMP1, 0xA0 ; LED-Scheinwerfer ein mit ca. 60% Helligkeit
out OCR1A, Helligkeit ; Wert in Timer-Vergleichsregister laden.
out TCNT1, TMP1 ; Timercounter ebenfalls laden.
in TMP1, TCCR1 ; Und Timer im PWM-Modus
sbr TMP1, 1<<COM1A1 | 1<<COM1A0 | 1<<CS12 | 1<<CS11 | 1<<CS10 ; starten.
out TCCR1, TMP1 ; Alles im Timer-Steuerregister speichern.
; --------- TEST -----------
in TMP1, PORTB ; PortB einlesen und LED grün durch Ausgabe
cbr TMP1, 0b001000 ; von L-Pegel einschalten.
out PORTB, TMP1 ; PortB ausgeben.
ret ; Rücksprung.
; *******************************************************
; * Warteschleife mit ca. 12ms *
; *******************************************************
Wait12ms:
ldi ZL, low (2500) ; 16-Bit Zähler mit Startwert laden
ldi ZH, high(2500) ; für Taktfrequenz 1.6MHz
WaitMs1:
dec ZL ; Low-Byte des Zählers erniedrigen
brne WaitMs1 ; wenn 0, dann
dec ZH ; High-Byte des Zählers erniedrigen
brne WaitMs1 ; wenn auch0, dann Warteschleife
ret ; verlassen.
; *******************************************************
; * Prozessor in PowerDown-Modus versetzen *
; *******************************************************
PowerDown:
in TMP1, MCUCR ; Prozessorcontrollregister auslesen um
sbr TMP1, 1<<SE | 1<<SM1 ; PowerDown-Mode zu aktivieren
out MCUCR, TMP1 ; Speichern.
sleep ; Prozessor in PowerDown-Mode versetzen
ret ; Nach Aufwecken Rücksprung
Kalibrierung: .db 0x79 ; Kalibrierungswert für int. Oszillator
.exit
Lesezeichen