Code:
;*******************************************************************
;*
;* Programm: GTRiegel
;*
;* Version: 1.0
;*
;*
;* Portzuordnung:
;* PB0 < Schalter Tor zu PinChange Interrupt
;* PB1 < Impuls Tor auf/zu INT0 Interrupt
;* PB2 < Sensor Riegel offen/zu 3 Zustände möglich!!! (ADC)
;* PB3 > Riegel auf
;* PB4 > Riegel zu
;* PB5 > Impuls zur Torelektronik auf/zu
;*
;* PB0 und PB1 sind Interrupt gesteuerte Eingänge ;*
;*******************************************************************
; Definitionen
;*******************************************************************
#include "tn13def.inc"
.cseg
.org 0x000 ; Interrupt Vektoren
rjmp MAIN ; Hauptprogrammroutine (Reset)
rjmp IMPLS ; Interrupt0
rjmp CLSLATCH ; PinChangeInterrupt Tor zu
rjmp TMROVF ; TimerOverFlow für Warteschleife
rjmp MAIN ; Hauptprogrammroutine
rjmp MAIN ; Hauptprogrammroutine
rjmp MAIN ; Hauptprogrammroutine
rjmp MAIN ; Hauptprogrammroutine
rjmp MAIN ; Hauptprogrammroutine
rjmp MAIN ; Hauptprogrammroutine
.def TIM1 = R16 ; Timer 1 für Wartezeit
.def TIM2 = R17 ; Timer 2 für Wartezeit
.def TSEC = R18 ; Sekundenregister für Zeitügabe
.def SCNT = R19 ; Sekundenregister für Timer
.def TEMP = R20 ; dient für diverse Operationen
.def SAVR = R21 ; dient zum Sichern des SREG
.def ADCV = R22 ; enthält Wert von ADCH nach AD-Wandlung
.def DIMI = R23 ; "Door In Motion" Indikator
; dient zur Abfrage bei weiterem Impuls
; während Tor in Bewegung
; Bit Bedeutungen:
; Bit2: 1=Tor während Bewegung gestoppt
; Bit1: 0=Bewegung war auf, 1=war zu
; Bit0: 1=in Bewegung, 0=abgeschlossen
;*******************************************************************
MAIN:
;*******************************************************************
; Generelle Initialisierungen
;-------------------------------------------------------------------
; Allgemeine Interrupts verhindern
cli
; Arbeitsregister löschen
clr ADCV
clr DIMI
; Stack anlegen
ldi temp,LOW(RAMEND)
out SPL,temp
; Ports initialisieren
ldi temp,0b00111000 ; Register für DDRB in/out laden
out DDRB,temp ; 0 1 2 Eingänge 3 4 5 Ausgänge
ldi temp,0b00000010 ; Register für PORTB PB1 laden
out PORTB,temp ; PB1 PullUp, Ausgänge low
; ADC initialisieren
ldi temp,6 ; Reg. für ADC prescaler laden
out ADCSRA,temp ; 6 (divider 64) sind ca 18kHz
ldi temp,1 ; Reg. für ADMUX PB2 laden
out ADMUX,temp ; ADMUX setzen
; Wait-Timer setzen
ldi temp,3 ; Vorteiler /64
out TCCR0B,temp
; Interrupt Register setzen
ldi temp,0b00110001 ; 0bxxxxxxx1 INT0 jede Level-
; änderung löst Interrupt aus
out MCUCR,temp ; 0bxx11xxxx Sleep-Mode auf
; PowerDown setzen
ldi temp,0b01100000 ; GIMSK Interrupt Mask setzen
out GIMSK,temp ; Int0 und PinChange enable
ldi temp,1 ; PinChange auf PB0 beschränken
out PCMSK,temp
; Initialisierung beendet > enter SLEEP-Modus
rjmp pwrdwn ; dann power down
;*******************************************************************
;******************** START INTERRUPT ROUTINEN *********************
;*******************************************************************
;*******************************************************************
IMPLS: ; OK
;-------------------------------------------------------------------
; Interruptroutine (INT0):
; Diese I-Routine besitz nur den RJUMP Befehl zur Subroutine, da
; diese auch aus dem Programmablauf aufgerufen werden können muss.
; SREG braucht nicht gesichert zu werden, da keine Rückkehr
; erfolgt (rjmp).
;*******************************************************************
rjmp impuls
reti
;*******************************************************************
CLSLATCH: ; OK
;-------------------------------------------------------------------
; Diese Interruptroutine wird durch den PINchange (Tor zu) an PB0
; ausgelöst und schließt den Riegel
;-------------------------------------------------------------------
in savr,SREG
cli ; weitere Interrupts verhindern
clr dimi ; Tor in (Soll)Endstellung ZU
sbi portb,4 ; PB 4 ein = Riegel schließen
WCLSLATCH:
rcall readadc
sbrs adcv,0 ; Bit1=1 = Riegel geschlossen
rjmp wclslatch ; neue Abfrage bis geschlossen
cbi portb,4 ; PB 4 aus
rjmp pwrdwn
reti
;*******************************************************************
TMROVF: ; OK
;-------------------------------------------------------------------
; Diese Interruptroutine wird durch den TimerOVF Interrupt
; aufgerufen
;-------------------------------------------------------------------
in savr,SREG
clr tim1
out TCNT0,tim1 ; Timer zurücksetzen
inc tim2
cpi tim2,75 ; 75 cylces = ca. Sekunde
brlo tmrovfe
clr tim2
inc scnt ; Sekundenzähler um 1 erhöhen
TMROVFE:
out SREG,savr
reti
;******************** ENDE INTERRUPTROUTINEN ***********************
;*******************************************************************
;*********************** START SUB ROUTINEN ************************
;*******************************************************************
;*******************************************************************
IMPULS: ; OK
;-------------------------------------------------------------------
; Fragt Status von Tor und Riegel ab und führt entsprechende
; Routinen aus
;-------------------------------------------------------------------
cli ; weitere Interrupts verhindern
cpi dimi,0 ; DIMI=0, Torbewegung abgeschlossen
breq normrun ; wenn ja, normaler Ablauf
sbrc dimi,2 ; Bit2=0 Tor in Bewegung > skip
rjmp revers
rcall doorimp ; Bewegung stoppen
sbr dimi,2 ; Tor in Bewegung gestoppt
rjmp pwrdwn
REVERS: ; letzte Torrichtung umdrehen
sbrs dimi,1 ; Tor Richtung war ZU > skip
rcall clsdoor ; mit Schließen des Riegels
rcall doorimp ; Tor öffnen
cbr dimi,1 ; Torrichtung = AUF
ldi tsec,30 ; Wartezeit laden
rcall wait
clr dimi ; wenn alles OK, DIMI = 0
rjmp pwrdwn
NORMRUN:
sbis pinb,2 ; Abfrage Riegel zu? > skip
rjmp clsdoor ; Tor + Riegel schließen
rjmp opndoor ; Riegel + Tor öffnen
ret
;*******************************************************************
READADC: ; OK
;-------------------------------------------------------------------
; Liest den A/D Wandler an PB2 aus ADC 10 Bit Messung
; Da es sich hier um keine digitale „Spannungsmessung“ handelt
; sondern lediglich um eine „Statusabfrage“ reicht hierzu nur die
; Abfrage des Hi-Byte (ADCH):
; 0V = Riegel offen ADCH = 0
; 2V = Riegel „unterwegs“ ADCH = 1
; 5V = Riegel geschlossen ADCH = 3 (oder Abfrage dec. >1)
; Die Messung muss doppelt erfolgen ansonsten wird die vorherige
; Messung eingelesen – Eigenheit des Tiny13
;-------------------------------------------------------------------
sbi ADCSRA,ADEN ; ADC ENable
sbi ADCSRA,ADSC ; ADC Start Conversion
WREADADC1: ; Schleife bis Messung
sbic ADCSRA,ADSC ; abgeschlossen = ADSC=0
rjmp wreadadc1
sbi ADCSRA,ADSC ; ADC Messung 2tes Mal starten
WREADADC2:
sbic ADCSRA,ADSC ; warten bis ADSC = 0
rjmp wreadadc2
in temp,ADCL ; lowbyte einlesen
in adcv,ADCH ; highbyte einlesen
cbi ADCSRA,ADEN ; ADC ausschalten
ret
;*******************************************************************
CLSDOOR: ; OK
;-------------------------------------------------------------------
; Schickt Tor Impuls zum Schließen, setzt DIMI
;-------------------------------------------------------------------
rcall doorimp
sbr dimi,1 ; Bit1=1 = Torbewegung ZU
rjmp pwrdwn ; sleep bis Interrupt „Tor zu“ (PB0)
ret
;*******************************************************************
OPNDOOR: ; OK
;-------------------------------------------------------------------
; Öffnet Riegel und Tor
;-------------------------------------------------------------------
sbi portb,3 ; PB 3 ein = Riegel öffnen
WOPEN:
rcall readadc
nop
cpi adcv,0 ; compare (0=offen)
brge wopen ; neue abfrage bis offen
cbi portb,3 ; PB 3 aus
rcall doorimp
ldi dimi,1 ; Torbewegung AUF
ldi tsec,30 ; Wartezeit von 30 Sek. für Wait
rcall wait ; Warteschleife
clr dimi ; DIM Indikator löschen
rjmp pwrdwn
ret
;*******************************************************************
DOORIMP: ; OK
;-------------------------------------------------------------------
; schickt einen Impuls von etwa 1 Sekunde zur Torelektronik
;-------------------------------------------------------------------
ldi tsec,1 ; Zeit für Impulsspreizung in Sek
sbi portb,5 ; PB 5 ein = Impuls Tor auf
rcall wait ; Impulsspreizung
cbi portb,5 ; PB 5 aus
ret
;*******************************************************************
WAIT: ; OK
;-------------------------------------------------------------------
; Warteschleife für diverse Zeitverzögerungen
; Wartezeit wird von aufrufender Routine in TSEC übergeben
; Es wird der PinChange Interrupt kurzfristig unterdrückt, da beim
; Öffnen des Tores ungewollt ein PCI ausgelöst wird.
; Der PCI wird vor dem enable wieder gelöscht, damit dieser nicht
; nach der generellen Freigabe der Interrupts ausgeführt wird.
;-------------------------------------------------------------------
in temp,GIMSK
cbr temp,5
out GIMSK,temp ; PCI disable
clr scnt
ldi temp,2
out TIMSK0,temp ; Timer Interrupt freigeben
; Timer läuft .....
sei
LOOP:
cp scnt,tsec ; Sekunden abgelaufen?
brlo loop
clr temp
out TIMSK0,temp ; Timer Interrupt sperren, restliche
; Interrupts bleiben ein
in temp,GIFR
cbr temp,5
out GIFR,temp ; PCI löschen
in temp,GIMSK
sbr temp,5
out GIMSK,temp ; PCI enable
clr scnt
ret
;******************************************************************
PWRDWN: ; OK
;-------------------------------------------------------------------
; Beendet alle Funktionen, gibt die Interrupts frei und schaltet ab
; Ein Interrupt an PB1 (INT0) oder an PB0 (PinChange) aktiviert
; den Processor wieder
;-------------------------------------------------------------------
sei ; alle Interrupts frei geben
sleep ; Power Down, warten auf Interrupts
;************************ ENDE SUBROUTINEN *************************
.EXIT
wenn ich ihn in den tiny lade (mittels platine und programm vom franzis lernpaket) scheint er sofort in die "clslatch" routine zu laufen, denn PB4 ist aktiv. wenn ich das signal an PB2 dann gegen Vcc bringe schaltet er ab.
Lesezeichen