Forum: Mikrocontroller und Digitale Elektronik ATmega16: Timerinterrupt spinnt in Verbindung mit Sleep Modes


von Johnny (Gast)


Angehängte Dateien:

Lesenswert?

Hallo liebe Leute,

ich habe vor mittels eines ATmega16 eine Steuerung zu bauen, die mittels 
eines analogen Messerwerts (Temperatursensor) und der Uhrzeit arbeitet. 
Dies ist mein erste µC Projekt.

Beim experimentellen implementieren bin ich auf ein sehr merkwürdiges 
Verhalten des Atmels gestoßen.

Die Uhr wird über einen externen 32,768 kHz Uhrenquarz an Timer2 
gesteuert, der jede Sekunde einen Overflow Interrupt erzeugen soll. In 
der Interruptroutine läuft ein Zähler für die Zeit.
Die Hauptschleife schickt die CPU in den Power Save Modus, der nächste 
Timer-Interrupt weckt sie wieder auf und zählt die Uhr weiter.
Das funktioniert auch soweit.

Jetzt möchte ich zusätzlich jede Sekunde einmal mit dem intergrierten 
ADC das analoge Signal abtasten und dabei den ADC Noise Reduction Sleep 
Mode verwenden. Hier kommt es zu einem Problem:

Der ADC konvertiert wie gewünscht einmal pro Sekunde, die CPU wacht auch 
wieder auf, aber die Timer2 Overflow Interruptroutine wird aus mir 
unerklärlichen Gründen zwei mal ausgeführt (der Sekundenzähler erhöt 
sich um zwei pro Sekunde).
Verzichte ich jedoch entweder auf den Power Save Modus (Hauptschleife 
rennt einfach durch unt startet eine conversion nach der anderen) oder 
auf den ADC Noise Reduction Sleep Mode (Konvertierung im normalen 
Betriebsmodus), läuft der Sekundenzähler normal.


Was habe ich übersehen?


Vielen Dank für eure Hilfe.
Johnny

PS: An PortA und PortC hänge jeweils an den ersten 6 Bit LEDs, an PortD 
hängen 8 LEDs als "Debugausgabe".

von Johnny (Gast)


Lesenswert?

Der zweite Dateianhang war eingentlich ein Unfall...

Der Code im ersten Anhang erzeugt den Fehler, der im zweiten nicht.

Gruß
Johnny

von Florian L. (muut) Benutzerseite


Lesenswert?

Entferne die return-Befehle aus den ISRs, die gehören da nicht rein.

Weiß allerdings nicht, ob das den Fehler behebt. :-)

von Falk B. (falk)


Lesenswert?

@  Johnny (Gast)

>Die Uhr wird über einen externen 32,768 kHz Uhrenquarz an Timer2
>gesteuert, der jede Sekunde einen Overflow Interrupt erzeugen soll. In
>der Interruptroutine läuft ein Zähler für die Zeit.

Die meisten deiner return in den Funktionen sind überflüssig und 
irritieren nur.
Diese merkwürdigen Abfragen, ob der ADC noch läuft etc. sind nicht 
sinnvoll, das wird Kuddelmuddel
Die Definition deines struct time und der Variable systime sieht mir 
merkwürdig aus. Mach es lieber sauber getrennt. Definition über typedef 
struct, dann volatile time systime.
VErgiss erstmal den ADC noise reductions mode, der ist nicht wirklich 
sinnvoll, weil man dabei keine riesige Signalverbesserung erreicht, 
entgegen dem Namen.
Für weitere Tips, siehe Sleep Mode.

MfG
Falk

von Johnny (Gast)


Lesenswert?

Erst mal danke für eure Antworten. Sind soweit alles sinnvolle 
Anmerkungen, ich hab mir auch fast gedacht, dass der ADC noise reduction 
mode nicht die Welt ausmacht.

Nichts desto trotz würde ich sehr gerne wissen, warum bei der 
Konstellation der Sleep Modes die Interruptroutine zwei mal aufgerufen 
wird. In der Simulation scheint das nicht der Fall zu sein (da muss ich 
allerdings das ADC Interrupt bit manuel durch Anklicken setzen, da der 
Simulator das irgendwie nicht tut...).

Das Problem zu umgehen, in dem man die Fehlererzeugende Konstellation 
vermeidet, ist zwar eine Lösung, aber irgendwie nicht befriedigend...

Gruß
Johnny

von Hc Z. (mizch)


Lesenswert?

Du hast mit ziemlicher Sicherheit ein Problem:
1
If Timer/Counter2 is used to wake the device up from Power-save or Extended Standby
2
mode, precautions must be taken if the user wants to re-enter one of these modes: The
3
interrupt logic needs one TOSC1 cycle to be reset.  If the time between wake-up and re-
4
entering sleep mode is less than one TOSC1 cycle, the interrupt will not occur, and the
5
device will fail to wake up.
6
7
(Atmega16 DS, „Asynchronous Operation of Timer/Counter2“)
Bei 8 MHz (angenommen) müssen also mindestens ca. 240 Zyklen vergehen, 
bis Du wieder in den Sleep gehst.  So viel macht Dein Programm nicht. 
Deine CPU wacht deshalb vermutlich gar nicht durch den Timer2-Interrupt 
auf, sondern durch den ADC-Interrupt, den Du ja vor dem Sleep ebenfalls 
startest¹.  Da die Timing-Bedingungen für den Interrupt des asynchronen 
Timer 2 somit nicht erfüllt sind, ist vorstellbar, dass er nicht 
rechtzeitig zurückgesetzt wird, auch wenn ich im Datenblatt nichts dazu 
gefunden haben.

Der oben zitierte Abschnitt geht mit einer Empfehlung weiter, wie in 
diesem Fall verfahren werden kann.  Alternativ kannst Du ins 
Hauptprogramm testweise eine sehr kurze Warteschleife einbauen, um die 
240 Wartezyklen zu verbraten (volatile nicht vergessen).  Damit könntest 
Du herausfinden ob's wirklich daran liegt.

Eine Nebenbemerkung, die nichts damit zu tun hat:
1
  //Timer2 Intrrupt Flags löschen
2
  TIFR &= ~((1<<OCF2)|(1<<TOV2));
Das tut nicht, was der Kommentar sagt.  Schau in der Beschreibung von 
TIFR nach, wie man solche Bits löscht.  Dieselbe Vorgehensweise gilt 
übrigens (sinnvollerweise) für alle AVR-Interrupt-Flags.

____
[¹] und damit vermutlich laufend - hast Du mal nachgemessen, ob das Ding 
wirklich 1 ganze Sekunde schläft?

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.