PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Overflow Interrupt für Timer



Maestro
27.09.2004, 03:34
Hallo,
ich sitze jetzt schon seit gut 2 Tagen vor meinem Programm und finde einfach nicht den Fehler. ](*,)

Ich wollte im Grunde nur eine billige StopUhr machen, sprich ein Port soll eine gewisse Zeit 5V führen und wenn die Zeit abgelaufen ist soll der Port auf 0V wechseln.

Mein Problem konnte ich jetzt schon auf die Interrupt rutine eingrenzen.
Momentan verhält sich sich sobald ich mehr als 4 Zeilen Code in ihr stehen habe nicht mehr so wie ich es will.

Gibt es vielleicht dinge die man beachten muss wenn man eine Interrupt Rutine schreibt? 8-[



.INCLUDE "m32def.inc"

; Registerdefinition
; Zählregister
.DEF SekX4 = R20 ; Register in dem die 250ms * 240 = 60s gespeichert werden (1s/250ms = 4)
.DEF Min = R21 ; Register in dem die Minuten gespeichert werden
.DEF Stunden = R22 ; Register in dem die Stunden gespeichert werden
.DEF temp = R25

; Konstantenregister
.DEF CSekX4 = R1 ; Register in dem die Konstante 250ms * 240 = 60sgespeichert ist (240)
.DEF CMin = R2 ; Register in dem die Konstante Minuten gespeichert ist (60)
.DEF CStunden = R3 ; Register in dem die Konstante Stunden gespeichert ist (24)
.DEF CTimer = R4 ; Register in dem die Konstante zum Vorladen des Timers gespeichert ist (10)
.DEF Config = R5 ; Reagister zeigt ob die Config schon mal asugeführt wurde

.DEF CompareMIN = R23 ; Vergleichsregister für die Sekunden
.DEF CompareSEC = R24 ; Vergleichsregister für die Minuten
; ... Erweiterung möglich

; Schreibregister für alle Einstellungen
.DEF Port = R16 ; Register für Port zugriffe
.DEF Inter = R17 ; Register für Interrupt zugriffe
.DEF Timer = R18 ; Register für Zeitintervall
.DEF SleepM = R19 ; Register für SleepModiekonfiguration

;Konstenatendefinition
.EQU CFaktor = 4 ; Faktor für die Multiplikation der Sekunden (1s/250ms = 4)
.EQU Initialisiert = 0 ; Bit das Zeigt ob Initialisiert wurde

.EQU LED = 3 ; LED Portbit 3 für 5V Output
.EQU Relai = 2 ; Realai Portbit 2 für 5V Output
.EQU INLang = 0 ; Eingang für 15min Laufzeit
.EQU INKurz = 1 ; Eingang für 1 min Laufzeit

; Lange Laufzeit
.EQU Langmin = 1 ; Laufzeit für die min. (15min)
.EQU Langsec = 0*CFaktor; Laufzeit für die sec. (0sec)
; ... Erweiterung möglich

; Kurze Laufzeit
.EQU Kurzmin = 0 ; Laufzeit für die min. (1min)
.EQU Kurzsec = 10*CFaktor; Laufzeit für die sec. (0sec)
; ... Erweiterung möglich



.ORG 0x000
rjmp main ; Reset Handler

.ORG OVF2addr
rjmp ovf2_handler ; Overflow Timer/Counter 2 Handler



;**************************************Interrupt-Handel-BEGINN******************************************** **
ovf2_handler: ; Interrupt Handler für TimerOverflow

;################################################# ################################################## ##

; Zeitzähler bei Jedem Interrupt

inc SekX4 ; Sekunde wird erhöt, da alle 250ms erhöt wird wird bis 240 gezählt
cp SekX4,CSekX4 ; Prüfen ob 60Sekunden um sind (1s/250ms = 4*60 = 240), wenn ja zur Erhöhung der
brne fertig

min:
clr SekX4 ; SekundenZähler wieder auf Null setzen wenn eine Minute um ist
inc Min ; Minuten wird erhöht wenn 60sec vorbei sind
cp Min, CMin ; Prüfen ob 60Minuten um sind, wenn ja zur Erhöhung der
brne fertig

clr Min ; MinutenZähler wieder auf Null setzen wenn eine Stunde um ist

sbis PINA, Relai
sbi PORTA, Relai ; LED anschalten

sbic PINA, Relai
cbi PORTA, Relai ; Relai anschalten

; ... Erweiterung möglich

fertig:

; ... Erweiterung möglich
cpse Min, CompareMin ; Minuten übereinstimmen
rjmp zeit_zaehler_ende

cpse SekX4, Comparesec ; Sekunden übereinstimmen
rjmp zeit_zaehler_ende


; Prozedur zum Ausschalten des AVR etc.
ende:
clr TIMER
ldi TIMER, (0<<TOIE2) ; Interrupt ausschalten
out TIMSK, TIMER ; Timer/Counter 2 Overflow Onterrupt aktivated

ldi SleepM,(1<<SE)|(1<<SM1) ; erste 1 für SE, Power-Down Sleep Modus eingeschalten (010)
out MCUCR, SleepM ; Sleep eingstellen
Sleep ; Sleep Modus Power-Down (010)

zeit_zaehler_ende: ; Sprungziehl für das Ende des ZeitzählerUnterprogramm

ldi temp, 12
out TCNT2, temp ; Timer/Counter 2 mit 12 vorladen (255-243 = 12 <aufgerundet wegen befehlslaufzeiten)

;################################################# ################################################## ##


reti




;************************************************* ***Macros***************************************** **********
.MACRO CompareSetzen ; Start macro definition
ldi CompareMIN, @1 ; Vergleichsminuten mit der LangenZeit laden
ldi CompareSEC, @0 ; Vergleichssekundenmit der LangenZeit laden
rjmp Compare_gesetzt ; zurück zu main
.ENDMACRO ; End macro definition



;************************************************* Hauptprogramm************************************* **********
.CSEG
main:

Config:
; Konstantendefinition Register
ldi temp, 240 ; CSekX4 Konstante 250ms * 240 = 60s (Sekunden) (240)
mov CSekX4,temp

ldi temp, 60 ; CMin Minuten (60)
mov CMin,temp

ldi temp, 24 ; CStunden Stunden (24)
mov CStunden,temp

ldi temp, 12 ; CTimer Konstante zum vorladen des Timer gespeichert ist (255-243 = 11)
mov CTimer,temp

; Interruptdifinition
sei ; Interrupts global aktivieren

; Ports initialisieren
clr PORT
ldi PORT, 0b00001100 ; Port A bis auf Bit3 und Bit4 alles Eingänge
out DDRA, PORT ; Richtungsregister DDRA als Ausgang konfigurieren
sbi PORTA, LED ; LED anschalten
sbi PORTA, Relai ; Relai anschalten

sbis PINA, INKurz ; Prüfen Ob Kurz oder Lange Laufzeit
rjmp lang

CompareSetzen KurzSec,KurzMin ; Compare werte auf Kurz setzten
lang:
CompareSetzen LangSec,LangMin ; Compare werte auf Lang setzten

Compare_gesetzt:

; SleepModus initialisieren (Idle)
ldi SleepM,(1<<SE) ; Sleep ModusAktivieren, |(0<<SM2)|(0<<SM1)|(0<<SM0) 000 ist der Idle Sleep Modus
out MCUCR, SleepM ; Sleep eingstellen


; Timer/Counter 2 initialisieren
clr TIMER
ldi TIMER, (1<<TOIE2) ;|(1<<OCIE2) < für Compare Interrupt
out TIMSK, TIMER ; Timer/Counter 2 Overflow Onterrupt aktivated

clr TIMER
ldi TIMER, (1<<CS22)|(1<<CS21)|(1<<CS20) ; noPWM, OCR2 update Normal + off, vorfaktor 1024
out TCCR2, TIMER ; Port Timer/Counter 2 mit Funktionen laden, Timer wird gestartet

out TCNT2, CTimer ; Timer/Counter 2 mit 12 vorladen (255-245 = 12 <aufgerundet wegen befehlslaufzeiten)

ldi temp, (1<<initialisiert)
mov Config, temp ; Config bereits ausgeführt !!!

rjmp back

back:
Sleep


wäre echt superdankbar wenn sich mal jemand das Programm anschaut.

Es soll erstmal auf einem ATMega 32, mit Batterie, laufen mit (hoffentlich) 1MHz internen Takt.

Das Problem sollte nach meinem Debuggen im bereich der "##" linien zu finden sein.

Bitte um Hilfe ....

Thx

x-ryder
27.09.2004, 14:11
Hallo,

Was passiert denn, wenn du die so lang hast? Zählt der dann nur falsch?

Martin

Maestro
27.09.2004, 16:42
Hm also das mit den Zeilen im Interrupt hat sich als falsch rausgestellt.

Trotzalledem macht mein Programm nicht was es soll kann mir vielleicht einer sagen woran das liegen kann?

Habe übrigens eine Stack implementierung bereits ergänzt.

Kjion
27.09.2004, 19:51
Hier mal ein paar Dinge dir mir spontan aufgefallen sind :

Du sicherst das SREG Register in der Interruptroutine nicht. Das kann zu einigen Fehlern in der Hauptroutine führen die man einfach nicht finden ;-)

Ich weiß nicht ob das mit dem sleep Befehl in der Interruptroutine so funktioniert. Lass das mal raus oder setze es ins Hauptprogramm...

Das Makro finde ich irgendwie unübersichtlich, da es erst so aussieht als hättest du einen Sprung vergessen. Ich persöhnlich würde es da eher weglassen.

Setzt mal das "rjmp back" ganz ans Ende, sodass du da eine Endlosschleife hast. Der AVR darf nämlich niemals das Hauptprogramm ganz abarbeiten und das wäre da soweit ich das sehe der Fall. Dann bräuchtest du auch die Sleep Anweisung in der Interruptroutine nicht...

Ich hoff mal das stimmt so alles was ich geschrieben hab :-k

MfG Kjion

Maestro
28.09.2004, 14:56
Super Danke,

mit der Rettung des SREG Registers und einer Schleife über Sleep hats hingehauen.

Läuft auch mittlerweile super, hatte aber eine 5s verzögerung wenn ich die erste Minute zähle, kann ich mir irgentwie nicht genau erklären. Habe jetzt einfach noch eine schleife eingebaut die die 5s abzieht und damit ist es jetzt perfekt.

Thx nochmal

Ganz nebenbei haben alle AVR einen Timer mit Overflow Interrupt, oder gibts dort ausnahmen ?

Ich würde gern das Programm auf einen ATTiny 11 laufen lassen, gibts da vielleicht Probleme oder Dinge worauf mach achten sollte ?

Das er einen anderen Internen Takt hat habe ich schon gelesen, da muss ich dann halt wieder ein wenig Zeittunig betreiben, aber im Grunde sollte doch alles auch dort laufen oder ?

Gottfreak
28.09.2004, 15:29
Einen Timer mit Overflow haben, soweit ich weis, alle AVRs.


Ich würde gern das Programm auf einen ATTiny 11 laufen lassen, gibts da vielleicht Probleme oder Dinge worauf mach achten sollte ?

Den Tiny11 kann man nicht über die ISP-Schnittstelle programmieren.
Die Ausgänge vom Tiny11 sind openCollector-Ausgänge.
Sonst sollte da alles genauso gehen.

Maestro
28.09.2004, 16:21
Cool :mrgreen: dann geh ich mir jetzt mal einen Tiny11 holen :-b

So habe jetzt mal ein wenig Laufzeiten getestet und mir fällt auf das es anscheinend alle 5min (schätze ich) ein 5s delay aufftritt. Kann ich mir nicht erklären, habe in Bereich bis 5min, einfach nach der ersten Min einmal -5s eingefügt, damit läuft er ziehmlich genau.

Hatte jetzt jedoch mal 11min laufen lassen, naja und was soll ich sagen es gab ein +10s delay, was mich stutzig macht und nu denke ich einfach mal das alle 5min. ein +5s delay auftritt.

Also hier mal de Code ... wenn mir jemand sagen kann woran das liegt wäre ich ihm sehr dankbar.



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PB0 = 11min (IN) ;;
;; PB1 = 1 min (IN) ;;
;; PB2 = Relai (5V - OUT) ;;
;; PB3 = LED (5V - OUT) ;;
;; ;;
;; Zeitzähler für Internen 1MHZ takt ausgelegt ;;
;; mit 1024 vorfaktor ergibt für 250ms 240 ;;
;; Interrupts, somit brauch 1s 4*250ms Inter. ;;
;; ;;
;; Gezählt werden die Sek., Min., Stunden ;;
;; Erweiterungsmöglichkeiten sind möglich ;;
;; ;;
;; HINWEIS: Die Zeit hatt alle ca. 5min ein ;;
;; Verzögerung von ca. 5s. Die Ursache ;;
;; ist unbekannt. Genaue messungen für ;;
;; gewünschtenzeitraum empfehlenswert ;;
;; ;;
;; GETESTET bis ca. 5min !!! in diesem Zeitraum ;;
;; ist die korrekte Zeit erreicht ;;
;; worden !!! (bei 11min, +10s) ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.INCLUDE "m32def.inc"

; Registerdefinition
; Zählregister
.DEF SekX4 = R20 ; Register in dem die 250ms * 240 = 60s gespeichert werden (1s/250ms = 4)
.DEF Min = R21 ; Register in dem die Minuten gespeichert werden
.DEF Stunden = R22 ; Register in dem die Stunden gespeichert werden
.DEF temp = R25

; Konstantenregister
.DEF CSekX4 = R1 ; Register in dem die Konstante 250ms * 240 = 60sgespeichert ist (240)
.DEF CMin = R2 ; Register in dem die Konstante Minuten gespeichert ist (60)
.DEF CStunden = R3 ; Register in dem die Konstante Stunden gespeichert ist (24)
.DEF CTimer = R4 ; Register in dem die Konstante zum Vorladen des Timers gespeichert ist (10)
.DEF Config = R5 ; Reagister zeigt ob die Config schon mal asugeführt wurde

.DEF CompareMIN = R23 ; Vergleichsregister für die Sekunden
.DEF CompareSEC = R24 ; Vergleichsregister für die Minuten
; ... Erweiterung möglich

; Schreibregister für alle Einstellungen
.DEF Port = R16 ; Register für Port zugriffe
.DEF Inter = R17 ; Register für Interrupt zugriffe
.DEF Timer = R18 ; Register für Zeitintervall
.DEF SleepM = R19 ; Register für SleepModiekonfiguration

;Konstenatendefinition
.EQU CFaktor = 4 ; Faktor für die Multiplikation der Sekunden (1s/250ms = 4)
.EQU Initialisiert = 0 ; Bit das Zeigt ob Initialisiert wurde
.EQU KorrektturSek = 1 ; Bit das Zeigt ob KorrektturSek bereits gessetzt wurde
.EQU Korrekttur = 2 ; Bit das Zeigt ob KorrektturSek bereits gessetzt wurde

.EQU LED = 3 ; LED Portbit 3 für 5V Output
.EQU Relai = 2 ; Realai Portbit 2 für 5V Output
.EQU INLang = 0 ; Eingang für 11min Laufzeit
.EQU INKurz = 1 ; Eingang für 1 min Laufzeit

; Lange Laufzeit
.EQU Langmin = 11 ; Laufzeit für die min. (11min)
.EQU Langsec = 0*CFaktor; Laufzeit für die sec. (0sec)
; ... Erweiterung möglich

; Kurze Laufzeit
.EQU Kurzmin = 1 ; Laufzeit für die min. (1min) (min < 60 !!!)
.EQU Kurzsec = 0*CFaktor; Laufzeit für die sec. (0sec) (sec < 60 !!!)
; ... Erweiterung möglich



.ORG 0x000
rjmp main ; Reset Handler

.ORG OVF2addr
rjmp ovf2_handler ; Overflow Timer/Counter 2 Handler



;**************************************Interrupt-Handel-BEGINN******************************************** **
ovf2_handler: ; Interrupt Handler für TimerOverflow
in XL, SREG ; SREG register retten

out TCNT2, CTimer ; Timer/Counter 2 mit 12 vorladen (255-243 = 12 <aufgerundet wegen befehlslaufzeiten)



; ES SIND AUF DEM ATMEGA32 -5s NACH DER ERSTEN MIN ALS KORREKTUR NÖTIG !!!
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
sbrs Config, KorrektturSek; Korrektursek gesetzt?
rjmp Sek ; Nur einmal, nach der ersten Minute 5s abziehen.

ldi temp, (1<<initialisiert)|(0<<KorrektturSek)|(1<<Korrekttur)
mov Config, temp ; ; Config + KorrektturSek + Korrekttur bereits ausgeführt !!!

ldi SekX4, 20 ; 20/4 = 5s , die abzuziehen sind.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~



sek:
inc SekX4 ; Sekunde wird erhöt, da alle 250ms erhöt wird wird bis 240 gezählt
cp SekX4,CSekX4 ; Prüfen ob 60Sekunden um sind (1s/250ms = 4*60 = 240), wenn ja zur Erhöhung der
brne fertig

clr SekX4 ; SekundenZähler wieder auf Null setzen wenn eine Minute um ist



;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
sbrc Config, Korrekttur ; Korrektur schon mal gesetzt?
rjmp min ; wenn nein dann setzten sonst weiter wie gehabt.

ldi temp, (1<<initialisiert)|(1<<KorrektturSek)|(1<<Korrekttur)
mov Config, temp ; Config + Korrekttur bereits ausgeführt !!!
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~

min:
inc Min ; Minuten wird erhöht wenn 60sec vorbei sind
cp Min, CMin ; Prüfen ob 60Minuten um sind, wenn ja zur Erhöhung der
brne fertig

clr Min ; MinutenZähler wieder auf Null setzen wenn eine Stunde um ist

Stunden:
inc Stunden ; Minuten wird erhöht wenn 60sec vorbei sind
cp Stunden, CStunden ; Prüfen ob 60Minuten um sind, wenn ja zur Erhöhung der
brne fertig

clr Stunden ; MinutenZähler wieder auf Null setzen wenn eine Stunde um ist

; ... Erweiterung möglich

fertig:

cpse Min, CompareMin ; Minuten übereinstimmen
rjmp Prüfungoke

cpse SekX4, Comparesec ; Sekunden übereinstimmen
rjmp Prüfungoke

; ... Erweiterung möglich


; Prozedur zum Ausschalten des AVR etc.
ende:
clr TIMER
ldi TIMER, (0<<TOIE2) ; Interrupt ausschalten
out TIMSK, TIMER ; Timer/Counter 2 Overflow Onterrupt aktivated

cbi PORTA, Relai ; Relai Auschalten


Prüfungoke:
out SREG, XL ; SREG register wiederzurückholen
reti




;************************************************* ***Macros***************************************** **********
.MACRO CompareSetzen ; Start macro definition
ldi CompareMIN, @1 ; Vergleichsminuten mit der LangenZeit laden
ldi CompareSEC, @0 ; Vergleichssekundenmit der LangenZeit laden

rjmp Compare_gesetzt ; zurück zu main
.ENDMACRO ; End macro definition



;************************************************* Hauptprogramm************************************* **********
.CSEG
main:

sbrc Config,initialisiert
rjmp back

Config:
; Konstantendefinition Register
ldi temp, 240 ; CSekX4 Konstante 250ms * 240 = 60s (Sekunden) (240)
mov CSekX4,temp

ldi temp, 60 ; CMin Minuten (60)
mov CMin,temp

ldi temp, 24 ; CStunden Stunden (24)
mov CStunden,temp

ldi temp, 11 ; CTimer Konstante zum vorladen des Timer gespeichert ist (255-244 = 11)
mov CTimer,temp

;Stack initialisieren
ldi temp, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
out SPL, temp ; Laden der niederen 8-Bit des Stacks

ldi temp, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
out SPH, temp ; Laden der höheren 8-Bit des Stacks

; Interruptdifinition
sei ; Interrupts global aktivieren

; Ports initialisieren
clr PORT
ldi PORT, 0b11111100 ; Port A bis auf Bit3 und Bit4 alles Eingänge
out DDRA, PORT ; Richtungsregister DDRA als Ausgang konfigurieren
sbi PORTA, LED ; LED anschalten
sbi PORTA, Relai ; Relai anschalten

sbis PINA, INKurz ; Prüfen Ob Kurz oder Lange Laufzeit
rjmp lang

CompareSetzen KurzSec,KurzMin ; Compare werte auf Kurz setzten
lang:
CompareSetzen LangSec,LangMin ; Compare werte auf Lang setzten

Compare_gesetzt:

; SleepModus initialisieren (Idle)
ldi SleepM,(1<<SE) ; Sleep ModusAktivieren, |(0<<SM2)|(0<<SM1)|(0<<SM0) 000 ist der Idle Sleep Modus
out MCUCR, SleepM ; Sleep eingstellen


; Timer/Counter 2 initialisieren
clr TIMER
ldi TIMER, (1<<TOIE2) ;|(1<<OCIE2) < für Compare Interrupt
out TIMSK, TIMER ; Timer/Counter 2 Overflow Onterrupt aktivated

clr TIMER
ldi TIMER, (1<<CS22)|(1<<CS21)|(1<<CS20) ; noPWM, OCR2 update Normal + off, vorfaktor 1024
out TCCR2, TIMER ; Port Timer/Counter 2 mit Funktionen laden, Timer wird gestartet

out TCNT2, CTimer ; Timer/Counter 2 mit 12 vorladen (255-245 = 12 <aufgerundet wegen befehlslaufzeiten)

ldi temp, (1<<initialisiert)
mov Config, temp ; Config bereits ausgeführt !!!


back:
Sleep
rjmp back

Gottfreak
28.09.2004, 16:38
Du benutzt den internen Oscillator.
Der ist(bei den Megas, die ich kenne, den 32 hab' ich mir nie angeseh'n) nicht temperaturkompensiert und hat eine allgemeine Toleranz im %-Bereich. Außerdem ist die Frequenz von der Versorgungsspannung abhängig(wenn du ihn direkt an Batterien oder Akkus betreibst, sinkt die mit der Zeit ja ab.).
Viele Megas(ich glaube sogar, alle) haben eine RTC, wo du einen Uhrenquarz anschließen kannst.
Am genauesten ist es mit einem Quarzoszillator(obwohl die bis zu 20mA brauchen können, was für eine Uhr im Dauerbetrieb natürlich inakzeptabel ist.).

Maestro
28.09.2004, 18:02
Hm, also von der Version mit Batterie bin ich jetzt auch schon weg, werde mir ein billiger 4,5V Steckernetzteil nehmen.

Und du denkst da 5s von der temperatur kommen konnen, kommt mir nämlich sehr konstant vor. Kann aber durchaus sein, da der bei 10 min schon ein wenig wärmer wird (1-2°C). Will das Programm nur auf einem Tiny11 laufen lassen und da wirds dann eng wenn ich auch noch einen Quarz anschliesen will.

Ich werds mal mit einem Quarz bei gelegenheit versuchen.

Thx für den Hinweis, weiß ich erstmal worauf ich achten muss.