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".
Der zweite Dateianhang war eingentlich ein Unfall... Der Code im ersten Anhang erzeugt den Fehler, der im zweiten nicht. Gruß Johnny
Entferne die return-Befehle aus den ISRs, die gehören da nicht rein. Weiß allerdings nicht, ob das den Fehler behebt. :-)
@ 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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.