rogerberglen
17.09.2019, 18:10
Wie der Titel schon sagt, im Simulator funktioniert das mit dem Sleep (PowerDown-Modus). Der Prozessor hält an. Und bei einer Änderung am INT0-Eingang (Taster gegen 0 mit internen PullUp-Widerstand) Pinchange-Interrupt wacht der Prozessor auf und arbeitet weiter.
Aber in der realen Schaltung tut sich nichts. Kein Aufwecken.
Im Programm habe ich zum Testen des Restes mal die Sleeps auskommentiert.
Hier mal der bisherige Quellcode:
.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 Test ; Sprung zur Testroutine
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.
mov Status, ZL ; Statusregister löschen.
in TMP1, MCUCR ; Controllregister des Prozessors einlesen
sbr TMP1, 1<<ISC00 ; PowerDown-Modus freischalten
out MCUCR, TMP1 ; und speicehrn.
; ************************************************** *****
; * 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.
; ************************************************** *****
; * Interrupts freigeben *
; ************************************************** *****
in TMP1, GIMSK ; Interrupt an INT0 (Taster Aus/Ein) freigeben
sbr TMP1, 1<<INT0
out GIMSK, TMP1 ; und speichern.
sei ; Interrupts freigeben.
in TMP1, MCUCR
sbr TMP1, 1<<SE | 1<<SM1
out MCUCR, TMP1
; sleep
; >>>>>>> Hauptprogramm Anfang <<<<<<<
Start:
rcall KeyCheck ; Tasten abfragen
cpi KeyExit, 0x04 ; Taste "Ein/Aus" gedrückt $04
brne Weiter1 ; Nein, dann weiter, sonst
rcall PinInt0 ; Sprung nach Ein- Ausschaltroutine
Weiter1:
rjmp Start
; >>>>>>>> Hauptprogramm Ende <<<<<<<<
; >>>>>>>> INTERRUPTPROGRAMME <<<<<<<<
; ************************************************** *****
; * Testinterrupt um PowerDown-Mode zu beenden *
; ************************************************** *****
Test:
nop
reti
PinInt0:
; ************************************************** *****
; * Ein- / Ausschalter $04 an INT0 *
; ************************************************** *****
cpi Status, 0x00 ; Lampe ausgeschaltet?
breq LampeEin ; Dann Lampe einschalten
cbr Status, 1 ; Ist die Lampe an? Dann Lampe aus und
in TMP1, PORTB
sbr TMP1, 0b001000
out PORTB, TMP1
; 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.
reti ; Rücksprung.
LampeEin:
sbr Status, 1 ; Kennung für Lampe an setzen
; --------- TEST -----------
in TMP1, PORTB
cbr TMP1, 0b001000
out PORTB, TMP1
reti
; >>>>>>>>>> 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
; ************************************************** *****
; * 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.
Kalibrierung: .db 0x79 ; Kalibrierungswert für int. Oszillator
.exit
Aber in der realen Schaltung tut sich nichts. Kein Aufwecken.
Im Programm habe ich zum Testen des Restes mal die Sleeps auskommentiert.
Hier mal der bisherige Quellcode:
.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 Test ; Sprung zur Testroutine
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.
mov Status, ZL ; Statusregister löschen.
in TMP1, MCUCR ; Controllregister des Prozessors einlesen
sbr TMP1, 1<<ISC00 ; PowerDown-Modus freischalten
out MCUCR, TMP1 ; und speicehrn.
; ************************************************** *****
; * 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.
; ************************************************** *****
; * Interrupts freigeben *
; ************************************************** *****
in TMP1, GIMSK ; Interrupt an INT0 (Taster Aus/Ein) freigeben
sbr TMP1, 1<<INT0
out GIMSK, TMP1 ; und speichern.
sei ; Interrupts freigeben.
in TMP1, MCUCR
sbr TMP1, 1<<SE | 1<<SM1
out MCUCR, TMP1
; sleep
; >>>>>>> Hauptprogramm Anfang <<<<<<<
Start:
rcall KeyCheck ; Tasten abfragen
cpi KeyExit, 0x04 ; Taste "Ein/Aus" gedrückt $04
brne Weiter1 ; Nein, dann weiter, sonst
rcall PinInt0 ; Sprung nach Ein- Ausschaltroutine
Weiter1:
rjmp Start
; >>>>>>>> Hauptprogramm Ende <<<<<<<<
; >>>>>>>> INTERRUPTPROGRAMME <<<<<<<<
; ************************************************** *****
; * Testinterrupt um PowerDown-Mode zu beenden *
; ************************************************** *****
Test:
nop
reti
PinInt0:
; ************************************************** *****
; * Ein- / Ausschalter $04 an INT0 *
; ************************************************** *****
cpi Status, 0x00 ; Lampe ausgeschaltet?
breq LampeEin ; Dann Lampe einschalten
cbr Status, 1 ; Ist die Lampe an? Dann Lampe aus und
in TMP1, PORTB
sbr TMP1, 0b001000
out PORTB, TMP1
; 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.
reti ; Rücksprung.
LampeEin:
sbr Status, 1 ; Kennung für Lampe an setzen
; --------- TEST -----------
in TMP1, PORTB
cbr TMP1, 0b001000
out PORTB, TMP1
reti
; >>>>>>>>>> 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
; ************************************************** *****
; * 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.
Kalibrierung: .db 0x79 ; Kalibrierungswert für int. Oszillator
.exit