Forum: Mikrocontroller und Digitale Elektronik Digitaluhr bleibt plötzlich stehen


von Jan Ü. (janiboy46)


Angehängte Dateien:

Lesenswert?

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!

von Mike (Gast)


Lesenswert?

Die Tasterentprellung mit langen Delays in der ISR hat einen gewissen 
Seltenheitswert.

von Jan Ü. (janiboy46)


Lesenswert?

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?

von Mike (Gast)


Lesenswert?

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"

von Jan Ü. (janiboy46)


Lesenswert?

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?

von Mike (Gast)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

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.

von Jan Ü. (janiboy46)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

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"

von Jan Ü. (janiboy46)


Lesenswert?

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!

von Vuvuzelatus (Gast)


Lesenswert?

>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.

von Jan Ü. (janiboy46)


Lesenswert?

@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!

von Jan Ü. (janiboy46)


Lesenswert?

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?

von Troll (Gast)


Lesenswert?

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

von Jan Ü. (janiboy46)


Lesenswert?

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!

von Michi (Gast)


Lesenswert?

Jan Ückerseifer schrieb:
> 32,768 MHz
du meinst sicherlich 32,768 KHz

von Jan Ü. (janiboy46)


Lesenswert?

Oh, ja klar! Sorry, war ein Flüchtigkeitsfehler ;)

von Mike (Gast)


Lesenswert?

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 ...

von Vuvuzelatus (Gast)


Lesenswert?

>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.

von Sascha W. (sascha-w)


Lesenswert?

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

von Jan Ü. (janiboy46)


Lesenswert?

@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.

von Jan Ü. (janiboy46)


Lesenswert?

Hat denn keiner eine Idee, woran es liegen könnte?

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
Noch kein Account? Hier anmelden.