Hallo,
Was passiert denn, wenn du die so lang hast? Zählt der dann nur falsch?
Martin
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?
wäre echt superdankbar wenn sich mal jemand das Programm anschaut.Code:.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
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
Hallo,
Was passiert denn, wenn du die so lang hast? Zählt der dann nur falsch?
Martin
Linus Torvalds, Entwickler von LinuxIch will Microsoft wirklich nicht zerstören. Das wird nur ein gänzlich unbeabsichtigter Nebeneffekt sein.
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.
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
MfG Kjion
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 ?
Einen Timer mit Overflow haben, soweit ich weis, alle AVRs.
Den Tiny11 kann man nicht über die ISP-Schnittstelle programmieren.Ich würde gern das Programm auf einen ATTiny 11 laufen lassen, gibts da vielleicht Probleme oder Dinge worauf mach achten sollte ?
Die Ausgänge vom Tiny11 sind openCollector-Ausgänge.
Sonst sollte da alles genauso gehen.
it works best if you plug it (aus leidvoller Erfahrung)
Cool dann geh ich mir jetzt mal einen Tiny11 holen
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.
Code:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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
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.).
it works best if you plug it (aus leidvoller Erfahrung)
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.
Lesezeichen