Hallo, habe das folgende Programm in eine ATMEGA88 geschrieben, und habe den Eindruck, dass die Sleep-Funktion nicht ausgeführt wird. ;----------------------------------------------------------------- ; ; Name: Sleep-Funktion-Test1_M88-16MHz.asm ; Title: Wait for Timer1 Interupt and blink LED ; ; Version: 0.1 ; Last updated: 2010.09.18 by nobby ; Target: ATMEGA88 ; ;----------------------------------------------------------------- ; ; ; RX/TX: MAX232 ; INT0 and INT1: not used ; ; Output RS-232: not used ; ; ; History: ; ======== ; ; 18.09.2010 ; Software aus anderem Progamm kopiert ; ; 18.09.2010 ; Software geändert. ; CLKDivider zur Reduzierung des Taktes. ; Wichtig: Umschaltung muss innerhalb von 4 Takten erfolgen. ; Interupt darf währenddessen nicht auftreten bzw. muss ; deaktiviert sein. ; ; Aufgabe: ; Timer1 erzeugt ein Zeitintervall von 152 Sekunden: OK ; bis zum Interupt soll die CPU schlafen: nicht OK ; Anzeige des Interupt über Umschaltung der LED an PC0: OK ; Anzeige des Sleep-Modus über Umschaltung der LED an PB0: nicht OK ; ; ;----------------------------------------------------------------- .include "M88def.inc" .equ fq = 16000000 ; Quarzfrequenz .equ prescaler = $05 ; Teilerfaktor 1024 .def temp = r16 .def temp1 = r18 .def count1 = r17 rjmp main ; Reset Handler reti ; IRQ0 Handler reti ; IRQ1 Handler reti ; PCINT0 Handler reti ; PCINT1 Handler reti ; PCINT2 Handler reti ; Watchdog Timer Handler reti ; Timer2 Compare A Handler reti ; Timer2 Compare B Handler reti ; Timer2 Overflow Handler reti ; Timer1 Capture Handler reti ; Timer1 Compare A Handler reti ; Timer1 Compare B Handler rjmp ledon ; Timer1 Overflow Handler reti ; Timer0 Compare A Handler reti ; Timer0 Compare B Handler reti ; Timer0 Overflow Handler reti ; SPI Transfer Complete Handler reti ; USART, RX Complete Handler reti ; USART, UDR Empty Handler reti ; USART, TX Complete Handler reti ; Analog Comparator Handler reti ; 2-wire Serial Interface Handler reti ; Store Programm Memory Ready Handler main: ; Initialisieren ldi temp, high(RAMEND) ; Stackpointer H initialisieren out SPH, temp ; in Register schreiben ldi temp, low(RAMEND) ; Stackpointer L initialisieren out SPL, temp ; in Register schreiben ldi temp, 0x01 ; Port B0 als Ausgang out DDRB, temp ; in Register schreiben ldi temp, 0x01 ; Port C0 als Ausgang out DDRC, temp ; in Register schreiben ldi temp, 0x00 ; Port C0 low = LED on out PORTC, temp ; in Register schreiben ; Externe Interrupts aktivieren ldi temp, (1<<TOIE1) ; Overflow Interupt Timer1 aktivieren sts TIMSK1, temp ; in Register schreiben ; Clock Divider setzen ldi temp, $80 ; Daten laden (CLKPCE = 1) sts CLKPR, temp ; in Clock Prescale Register schreiben ldi temp, $06 ; Daten laden (CLKPS2+CLKPS1 = 1 = /64) sts CLKPR, temp ; in Clock Prescale Register schreiben ; Timer1 initialisieren ldi temp, (1<<TOV1) ; Timerflag zurücksetzen out TIFR1, temp ; in Register schreiben ldi temp, 0x6F ; TimerValueH =0 sts TCNT1H, temp ; in Register schreiben ldi temp, 0x0A ; TimerValueL =0 sts TCNT1L, temp ; in Register schreiben ldi temp, prescaler ; Prescaler setzen sts TCCR1B, temp ; in Register schreiben sei ; Interupts aktivieren ;count1 null setzen ldi count1, $00 ; Lade temp mit 0 ldi temp1, $00 ; setze temp1 =0 ; Power Save Modi aktivieren ldi temp, $E7 ; PRTWI PRTIM2 PRTIM0 - PRTIM1 PRSPI PRUSART0 PRADC sts PRR, temp ; 1 1 1 0 0 1 1 1 ; PRTWI = Power Reduction TWI ; PRTIM2 = Power Reduction Timer2 ; PRTIM0 = Power Reduction Timer0 ; - = not used ; PRTIM1 = Power Reduction Timer1 ; PRSPI = Power Serial Peripheral Interface (no RS232) ; PRUSART0 = Power Reduction USART0 ; PRADC = Power Reduction ADC ldi temp, $0D ; Lade Power Save code sts SMCR, temp ; in Sleep Mode Control Register loop: sleep ; Sleep Modus aktivieren inc temp1 ; temp1 um 1 erhöhen out PORTB, temp1 ; Wert auf PortD schreiben rjmp loop ; Warten auf Interupt ledon: cli ; Interupts deaktivieren ldi temp, $00 ; Temp mit 0 laden sts TCCR1B, temp ; in Register schreiben (Timer1 anhalten) ldi temp, 0x6F ; TimerValueH =0 sts TCNT1H, temp ; in Register schreiben ldi temp, 0x0A ; TimerValueL =0 sts TCNT1L, temp ; in Register schreiben ldi temp, prescaler ; Prescaler setzen sts TCCR1B, temp ; in Register schreiben ldi temp, (1<<TOV1) ; Timerflag zurücksetzen out TIFR1, temp ; in Register schreiben inc count1 ; count1 um 1 erhöhen out PORTC, count1 ; in Register schreiben sei ; Interupts aktivieren reti ; Rücksprung ;----------------------------------------------------------------- Die Anzeige des Interupt funktioniert einwandfrei. Alle 152 Sekunden schaltet die LED um. Das Gleiche müsste meiner Meinung nach doch auch an der anderen LED passieren. Das Programm wird nach der Intialisierung bis zum Sleep-Befehl ausgeführt und hält dort an. Nach dem Interupt und der Ausführung der Interuptrountine sollte das Programm hinter dem Sleep Befehl fortfahren. Das bedeutet, dass die zweite LED auch im 152s Rhythmus schalten müsste. Dem ist aber nicht so. Diese LED leuchtet permanent. Mache ich einen Gedankenfehler? Oder hat das Programm einen Fehler? Hab das Manual in diesem bereich schon zigmal durchgelesen, finde aber keinen Fehler.
du verwendest den STANDBY-MODE lt. Datenblatt sollte der sich doch nur von Timer2 unterbrechen lassen!? was mir sonst noch aufgefallen ist
1 | ledon: cli ; Interupts deaktivieren |
2 | ldi temp, $00 ; Temp mit 0 laden |
3 | sts TCCR1B, temp ; in Register schreiben (Timer1 anhalten) |
4 | ldi temp, 0x6F ; TimerValueH =0 |
5 | sts TCNT1H, temp ; in Register schreiben |
6 | ldi temp, 0x0A ; TimerValueL =0 |
7 | sts TCNT1L, temp ; in Register schreiben |
8 | ldi temp, prescaler ; Prescaler setzen |
9 | sts TCCR1B, temp ; in Register schreiben |
10 | ldi temp, (1<<TOV1) ; Timerflag zurücksetzen |
11 | out TIFR1, temp ; in Register schreiben |
12 | inc count1 ; count1 um 1 erhöhen |
13 | out PORTC, count1 ; in Register schreiben |
14 | sei ; Interupts aktivieren |
15 | reti ; Rücksprung |
*cli/sei kannst du dir schenken, innerhalb der ISR sind die INT's gesperrt *um den Counter zu laden brauchst du ihn nicht anzuhalten, da er bei dir eh nur alle 1024 Takte die ISR aufgerufen wird *das TOVx-Flag wird durch das Aufrufen der ISR gelöscht bleibt also
1 | ledon: |
2 | ldi temp, 0x6F ; TimerValueH =0 |
3 | sts TCNT1H, temp ; in Register schreiben |
4 | ldi temp, 0x0A ; TimerValueL =0 |
5 | sts TCNT1L, temp ; in Register schreiben |
6 | inc count1 ; count1 um 1 erhöhen |
7 | out PORTC, count1 ; in Register schreiben |
8 | reti ; Rücksprung |
Sascha
Sascha Weber schrieb: > du verwendest den STANDBY-MODE lt. Datenblatt sollte der sich doch nur > > von Timer2 unterbrechen lassen!? @ Sascha, vielen Dank für Deine Hinweise. Das ich jetzt den Standby-Mode genommen habe ist Zufall. Ich habe auch Power Save Mode und auch andere versucht. Gleiche Erscheinung. Aber wenn ich der oben genannten Aussage folge, würde dass nicht bedeuten, dass die CPU nie mehr aufgeweckt wird? Wieso läuft denn der Timer1 weiter?
Norbert Hanebeck schrieb: > Aber wenn ich der oben genannten Aussage folge, würde dass nicht > bedeuten, > dass die CPU nie mehr aufgeweckt wird? richtig > Wieso läuft denn der Timer1 weiter? weil der AVR nicht in den SLEEP geht. Wie wird dein AVR getaktet (intern oder extern)? für einige SLEEP-MODEs steht im Datenblatt das die nur funktionieren wenn die Takterzeugung mit externem Quarz/Resonator erfolgt (siehe Kapitel 9) Deine LED aus der Hauptschleife sollte dann eigentlich nicht dauernd leuchten, sondern so schnell umschalten das es nur so aus sieht. Sascha
@Sascha, Der Atmega88 ist mit einem externen 16-MHz Quarz bestückt. Habe zusätzlich noch eine Zeitschleife von 5 Sekunden eingefügt. loop: sleep ; Sleep Modus aktivieren inc temp1 ; temp1 um 1 erhöhen out PORTB, temp1 ; Wert auf PortB schreiben rcall delay ; 5 Sekunden Delay rjmp loop ; Warten auf Interupt Die LED an PortB blinkt nun im 5 Sekunden Rhythmus während die LED an PortC im 152 Sekunden Rhytmus blinkt. Aber warum geht die CPU nicht in den Sleep Modus?
@Norbert Hanebeck (nobbyh)
>Aber warum geht die CPU nicht in den Sleep Modus?
Zuviel Red Bull? ;-)
hab's mal im Simulator getestet ... mit
1 | sts SMCR,temp |
wird das SMCR nicht verändert und bleibt bei 0 mit
1 | out SMCR,temp |
geht's Sascha
++EDIT da ist mir gerade noch eingefallen warum das nicht gehen kann. Zwischen der I/O-Adresse und der SRAM-Adresse hast du einen Offset von 32! In den includes sind die Definitionen für den I/O-Bereich 0..63 auf eben diese I/O-Adressen ausgelegt. Bei allen Registern oberhalb von 63 ist der Offset schon eingerechnet. Willst du also ein Register aus dem mit IN/OUT erreichbaren Bereich mit STS/LDS ansprechen so musst du noch 32 addieren. oder verwende Macros ...
1 | .macro out_ |
2 | .if (@0 <= 63) |
3 | out @0,@1 |
4 | .else |
5 | sts @0,@1 |
6 | .endif |
7 | .endmacro |
8 | .macro in_ |
9 | .if (@1 <= 63) |
10 | in @0,@1 |
11 | .else |
12 | lds @0,@1 |
13 | .endif |
14 | .endmacro |
dann hast du keine Probleme Sascha
@ Sascha, vielen Dank für die freundliche Unterstützung. Ich denke, ich werde jetzt weiterkommen. Manchmal hat man ja das sogenannte Brett vorm Kopf. Hatte schon diverse Dinge ausprobiert, aber nie den Sleep-Modus aktivieren können. Irgendwann ist ein Punkt erreicht, an dem man ja langsam an sich selbst zweifelt. Aber völlig klar. Wenn man das entsprechende Register nicht mit den notwendigen Daten beschreibt, dann reagiert die CPU auch nicht wie sie soll. Wie hast du denn im Debug-Modus festgestellt, dass die Daten nicht in SMCR geschrieben werden? Viele Grüsse Norbert PS: Ich wollte das Register nicht unbedingt über STS/LDS bearbeiten.
Norbert Hanebeck schrieb: > PS: Ich wollte das Register nicht unbedingt über STS/LDS bearbeiten. Leider hast Du bei Adressen oberhalb von hex 3F keine Wahl. Die Befehle IN und OUT akzeptieren keine Adressen von mehr als hex 3F
Norbert Hanebeck schrieb: > Wie hast du denn im Debug-Modus festgestellt, dass die Daten nicht in > SMCR > geschrieben werden? im Simulator des AVR-Studio kann man im IO-Window doch den Inhalt aller Register betrachten. Grrrr (Gast) schrieb: >Norbert Hanebeck schrieb: >> PS: Ich wollte das Register nicht unbedingt über STS/LDS bearbeiten. ----- >Leider hast Du bei Adressen oberhalb von hex 3F keine Wahl. SMCR-Addr =0x33 >Die Befehle IN und OUT akzeptieren keine Adressen von mehr als hex 3F wer hat das Gegenteil behauptet? Sascha
Sascha Weber schrieb: > Wie hast du denn im Debug-Modus festgestellt, dass die Daten nicht in > >> SMCR > >> geschrieben werden? > > im Simulator des AVR-Studio kann man im IO-Window doch den Inhalt aller > > Register betrachten. > Danke, hab's gefunden. Fenster war nicht automatisch eingeblendet. Sascha Weber schrieb: > Die Befehle IN und OUT akzeptieren keine Adressen von mehr als hex 3F > > wer hat das Gegenteil behauptet? Niemand Nochmals recht herzlichen Dank für die Hilfe. Gruss Norbert
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.