Hallo, ich habe mir eine Digitaluhr bestehend aus vier 7-Segment Displays aufgebaut, welche ich über einen Atmega8 über vier Transistoren im Zeitmultiplex-Betrieb ansteuere (C-Code im Anhang). Ich benutze hierfür die ISR von Timer0. Für die Erzeugung des Sekundentakts nutze ich Timer1 im CTC-Modus (Takt läuft zu Testzwecken über internen RC-Oszillator, ist also nicht besonders genau) . Nach dem Drücken des Ein-Tasters kann man die Minuten und Stunden mit zwei separaten Tastern eingeben und durch erneutes Drücken des Ein-Tasters Timer1 starten, der dann den Sekundentakt generiert und die Displays jede Minute mit neuen Werten versorgt. Ich habe jetzt komischerweise das Problem, das manchmal nach zweimaligem Drücken des Ein-Tasters Timer1 nach ca. 20 Minuten offenbar stehenbleibt, da der sonst blinkende Doppelpunkt in der Mitte der Minuten- und Stundendisplays plötzlich nicht mehr blinkt und sich die Anzeige auf den Displays nicht mehr ändert. Dies tritt aber auch nur manchmal auf, da sonst in einigen Tests die Uhr eigentlich über mehrere Tage einwandfrei funktioniert hat. Mal funktioniert's, mal eben nicht. Hab es auch mit einem anderen Atmega8 probiert, um einen Hardwaredefekt auszuschließen, aber es liegt offenbar am Programm. Der Controller ist auch nicht abgestürzt, da sich über einen zusätzlichen Taster noch die Schaltfrequenz der Transistoren im laufenden Betrieb ändern lässt. Das Problem liegt also in irgendeiner Form bei Timer1. Vielleicht hat ja einer eine Idee!
Die Tasterentprellung mit langen Delays in der ISR hat einen gewissen Seltenheitswert.
Ja gut, bei der ISR von Timer0 geb ich dir Recht^^ Ich mach das aber zum ersten Mal, deshalb ist mir da nichts besseres eingefallen. Was wäre denn eine Alternative dazu?
Jan Ückerseifer schrieb: > Was wäre denn eine Alternative dazu? Alternative wäre mit Zähler zu arbeiten, die in der Timer-ISR erhöht oder heruntergezählt werden. Mit einem Delay in der ISR legst du alles lahm. Fürs Entprellen gibt es hier im Forum etliche Infos/Beispiel, z.B. http://www.mikrocontroller.net/articles/Entprellung Beitrag "Tasten entprellen - Bulletproof"
Ok, danke! Das kann ich ja dann noch ändern! Hast du denn auch eine Idee zu meinem ursprünglichen Problem? Weil Timer1 zählt ja im Sekundentakt und da ist das mit der Tasterentprellung mittels delay ja eigentlich unkritisch, oder?
Jan Ückerseifer schrieb: > Weil Timer1 zählt ja im Sekundentakt und da ist das mit der > Tasterentprellung mittels delay ja eigentlich unkritisch, oder? Das Delay darf aber nicht in der ISR stehen, weil dann die ganze Zeit auch andere Interrupts nicht abgearbeitet werden können. Warum hast du für den 1-Sekunden-Takt überhaupt einen eigenen Timer? Genauso könntest du deinen Multiplex-Takt verwenden, dort einen Zähler mitlaufen lassen und immer nach der passenden Anzahl von Timer-Events deinen Sekundenzähler erhöhen.
p.s. ... und statt der ganzen Case Anweisungen bietet sich für die Anzeigemuster eine Tabelle/Array an, auf die über Einer-/Zehner Sekunden/Minuten/Stunden zugegriffen wird. Das Bitmuster für die Auswahl der aktiven Anzeige kann man einfach durch eine Shift-Operation passend ändern.
Ich habe Timer1 wegen dem CTC-Mode benutzt, weil ich da ja durch den eingestellten Comparewert die Taktfrequenz des Quarz ganzzahlig teilen kann und dann wirklich exakt die eine Sekunde bekomme. Habe das mit dem CTC-Mode mal irgendwo hier im Forum gelesen, deswegen habe ich das so gemacht. Gut, dass du das mit dem delay nochmal ansprichst.Die Tasterabfrage mit dem delay war dort nämlich ürsprünglich garnicht vorhanden. Ich habe sie nur eingefügt, um die zweite if-Abfrage in der ISR von Timer1 zu erfüllen. Diese Abfrage stand nämlich ursprünglich am Ende der Funktion anfangszustand(), aber komischerweise stand der Wert der Variable taster_ein nach setzen von TOIE0 für diese Abfrage dann nicht mehr zur Verfügung. Den genauen Grund hierfür kenne ich nämlich auch nicht. Nur deshalb steht das alles in der ISR von Timer1 mit drin.
Jan Ückerseifer schrieb: > Den genauen Grund hierfür kenne ich nämlich auch nicht Vielleicht fehlte da ein "Volatile" bei der Variablendeklaration. Zum genauen Sekundentakt gibt es hier von Peter Dannegger Beitrag "Die genaue Sekunde / RTC"
Gibt es darüber hinaus eigentlich keine Möglichkeit der delay funktion eine Variable zu übergeben? Dann könnte ich mir die drei zusätzlichen Funktionen für die Frequenz nämlich sparen!
>Gibt es darüber hinaus eigentlich keine Möglichkeit der delay funktion >eine Variable zu übergeben? kA. >Dann könnte ich mir die drei zusätzlichen >Funktionen für die Frequenz nämlich sparen! Machs doch so: for (i=0, i<max, i++) delay(5) als Funktion definieren und max als Parameter übergeben. Funktioniert garantiert. Kannst dann halt nur in 5 ms-Stückelungen delayen. Am besten ist übrigens, man verwendet delay überhaupt nicht.
@Mike: Hab das mit der volatile-Deklaration gerade probiert und den Code entsprechend angepasst. Funktioniert aber leider immer noch nicht! @Vuvuzelatus: Also das müsste so eigentlich schon funktionieren. Dachte eben, es ginge wirklich direkt mit Variablenübergabe, weil das das einfachste wäre. Aber trotzdem danke!
Ich glaube das Problem liegt in der Transistoransteuerung. Ich habe nämlich mal in der Funktion zur Transistoransteuerung den Wert in der Delay-Funktion von 3 auf 1 gesetzt und das Display hat seinen Dienst dann auch dreimal so schnell eingestellt (ca nach sieben Minuten statt vorher 20 Minuten). Das kann doch kein Zufall sein, oder?
Wenn du noch einen UART Ausgang frei hast, dann nimm den zum debuggen. Einfach Ausgaben bei ISR einstieg und raus rein und bei jedem Druchlauf in der main
Ich habe meinen Fehler jetzt endlich gefunden. Es lag offenbar an der delay-Funktion in der ISR von Timer1. Habe mein Programm so geändert, dass ich auch ohne die Verzögerung die gleiche Funktion habe und nun läuft's endlich!! :) Dann noch eine andere Frage: Ich möchte jetzt als Taktgeber einen Uhrenquarz (32,768 MHz) benutzen und weiß auch schon wie ich die CKSEL-Bits für die Auswahl der Taktquelle und die CKOPT-Bits für das Zuschalten der beiden nötigen Kapazitäten setzen muss. Meine einzige Frage ist jetzt noch, ob ich XTAL1 in DDRB als Eingang bzw. XTAL2 als Ausgang programmieren muss, damit es dann auch wirklich funktioniert? Bin mir da nämlich nicht sicher!
Mike schrieb: > Das Delay darf aber nicht in der ISR stehen, ... Jan Ückerseifer schrieb: > Ich habe meinen Fehler jetzt endlich gefunden. Es lag offenbar an der > delay-Funktion in der ISR von Timer1. Mein Reden ...
>Mein Reden ... lach... Ungut wäre allerdings, wenn ihn diese Fehlerbeseitigungsmaßnahme jetzt glauben lässt, dass ein delay in einer ISR plus ein delay in der main generell in Ordnung sind. @Jan: Das wäre ein Irrtum! Dein schnellster Weg zum langfristigen, sicheren Erfolg, d. h. auch im Hinblick auf spätere, komplexere oder wirklich sehr komplexe Programme, ist die Erkenntnis, dass es auch völlig ohne blockierende Delayschleifen geht und welche Vorteile es hat, es tatsächlich so zu machen. Ich lege Dir diesen Artikel ans Herz, besonders den Abschnitt "kooperatives Multitasking": http://www.mikrocontroller.net/articles/Multitasking Vielleicht bekommst Du ja Lust, Dein Programm entsprechend umzustricken - was Besseres könntest Du Dir nicht tun. PS: Vermutlich ist Dein "altes" Programm nach 20 min in dem Moment teilweise eingefroren, in dem TIMER0_OVF und TIMER1_COMPA zufällig gleichzeitig oder fast gleichzeitig aufgetreten sind. Wenn die zugehörigen Zeitintervalle in einem "krummem" Verhältnis zueinander stehen, muss das zwangsläufig irgendwann passieren. Eine der ISRs war als erste dran und wegen des 200 ms-Delays darin musste die andere erstmal 200 ms anstehen. Vielleicht ist zwischenzeitlich auch schon wieder die Interrupt-Condition der ersten (oder sogar von beiden) eingetreten, d. h. das Pending-Flag wieder gesetzt. Die Folge wäre, dass der µC dann nur durch die ISRs komplett ausgelastet und die main praktisch lahmlegt ist. Nicht ganz, weil zwischen zwei unmittelbar aufeinanderfolgenden ISRs noch eine einzige Instruktion in der main ausgeführt wird. Ich schätze, das delay in Deiner main hat sich durch einen solchen Effekt einfach auf ein paar Tage verlängert. Ich hoffe, Du hast eine Ahnung davon bekommen, warum "Delayschleife in ISR" als No-Go gilt.
Jan Ückerseifer schrieb: > Dann noch eine andere Frage: Ich möchte jetzt als Taktgeber einen > Uhrenquarz (32,768 MHz) benutzen und weiß auch schon wie ich die > CKSEL-Bits für die Auswahl der Taktquelle und die CKOPT-Bits für das > Zuschalten der beiden nötigen Kapazitäten setzen muss. Meine einzige > Frage ist jetzt noch, ob ich XTAL1 in DDRB als Eingang bzw. XTAL2 als > Ausgang programmieren muss, damit es dann auch wirklich funktioniert? > Bin mir da nämlich nicht sicher! Ähm? 1) du willst den ganzen µC mit dem 32768kHz Quarz laufen lassen? wenn du die Fusebits entspechend einstellst, so das der externe Quarz verwendet wird, ist es egal was in DDRB drin steht. Der µC läuft ja schließlich los bevor du das DDRB überhaupt verändern kannst. 2) du willst nur den Timer 2 mit 32768kHz von extern takten, den µC aber mit internem RC-Osz. laufen lassen? dann stellst du mit CKSEL/CKOPT den AVR-Takt auf RC, das hat dann auf den Quarz keinen Einfluss. Mit dem AS2-Bit im ASSR aktivierst du den Quarzoszillator. Die Bits in DDRB haben auch hier keinen Einfluss. Du solltest einfach beide auf Eingang schalten/lassen. Sascha
@Vuvuzelatus: Danke für die Hinweise.Ich werde mal mein Programm noch passend umschreiben, damit ich auch komplett ohne delays auskomme. @Sascha: Also ich möchte eigentlich Variante eins nehmen. Ich habe jetzt die Fusebits im Low-Register für CKSEL auf 1001 gesetzt und statt der internen Kapazitäten zwei externe angeschlossen (je 32pF) und mein Programm noch vorher für die neue Taktfrequenz umgearbeitet. Es ist aber leider alles tot. Kann das vielleicht auch daran liegen, dass der Quarz zu weit vom Controller weg ist? Hab nämlich alles noch auf einem Steckbrett und da liegt der Quarz etwas abseits. Habe nämlich mal gehört, dass man den eigentlich so nah wie möglich an den Controller setzen soll.Von der Verkabelung müsste es nämlich alles richtig sein.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.