Forum: Mikrocontroller und Digitale Elektronik Variablen werden nach aufwachen aus Power Save nicht mehr verändert


von Frank Evers (Gast)


Angehängte Dateien:

Lesenswert?

Hi

Bei meinem ersten AVR-Projekt habe ich ein kleines Problem mit dem 
ATmega8 und dem Power Save Mode.
Nachdem ich den mC  mittels Timer2 und Uhrenquarz aufgeweckt habe, 
bekomme ich keine Variablen mehr geändert. Die Variablen sind global 
deklariert und volatile, vor dem ersten Einschlafen ändert sich der Wert 
auch noch, aber danach tut sich am Variablenwert nix mehr.
Wo denke ich falsch? Die Variablenwerte bleiben stumpf wo soe vor dem 
ersten schlafenlegen waren.

von Rene K. (xdraconix)


Lesenswert?

Entweder enttäuschen mich meine Augen, aber ich finde die Funktion 
Sleep_Mode() nicht in deinem Code?!

von HildeK (Gast)


Lesenswert?

Rene K. schrieb:
> aber ich finde die Funktion
> Sleep_Mode() nicht in deinem Code?!

Vorletztes Statement im Programm.

@TO: du machst den Setup "von Hand", bei mir stehen da immer mit Erfolg 
die Zeilen:
1
// Power-Down Sleep Mode einstellen
2
set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // stromsparend, aufwecken über WD oder INT0
3
sleep_enable();             // Schlafmodus vorbereiten
 und eben dann irgendwo in der Loop das "Sleep_Mode()"

von Frank Evers (Gast)


Lesenswert?

Hi

Doch, ganz unten, vorletzte Anweisung. Das Schlafenlegen und Aufwachen 
klappt auch, nur Variablen kann ich nach dem ersten Schlaf nicht mehr 
verändern.

Gruß, Frank

von Frank Evers (Gast)


Lesenswert?

HildeK, ja, ich hatte mich da am Datenblatt entlanggehangelt und erst 
später die hilfreichen Makros entdeckt, aber ich habs jetzt mal 
geändert, was aber leider keine Verbesserung brachte.

Gruß, Frank

von Oliver S. (oliverso)


Lesenswert?

Um mal die Frage aller Fragen zu stellen: Woran erkennst du, das sich 
die Variablen nicht mehr verändern lassen?

Oliver

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kann es sein, das du evtl. Probleme mit der Variablen 'DoorStatus' hast? 
Würde mich nicht wundern, weil du die etwas inkonsequent behandelst. 
Entweder machst du die zu einer bool'schen oder du benutzt konsequent 
deine OPEN und CLOSED defines, aber sowas hier:
1
// we really don't want door to be anything except 00000000b or 00000001b
2
  doorStatus &= 1;
macht dann nur noch eine 0 oder 1 aus Doorstatus und dann funktioniert
1
if ( doorStatus == CLOSED )
2
  {    
3
    while ( !( PINB & ( 1 << DOOR_CLOSED )))
4
    {
5
      _delay_ms(100);
6
      counter++;
7
      if ( counter > DOOR_TURNOFF_TIME )
8
        break;
9
    }
10
  }
11
  // wait until door is opened
12
  if ( doorStatus == OPEN )
13
  {    
14
    while ( !( PIND & ( 1 << DOOR_OPEN )))
15
    {
16
      _delay_ms(100);
17
      counter++;
18
      if ( counter > DOOR_TURNOFF_TIME )
19
        break;
20
    }
21
  }
natürlich nicht mehr, denn du hattest ja
1
#define OPEN 1
2
#define CLOSED 2
definiert. Ändere das mal lieber zu TRUE und FALSE, dann klappt das 
besser.

: Bearbeitet durch User
von Frank Evers (Gast)


Lesenswert?

Hi

ja, stimmt. OPEN und CLOSED waren ursprünglich mal als 0 und 1 
definiert, das habe ich vergessen anzupassen. Leider schafft mein 
Programm es bisher noch gar nicht bis dahin, da ja auch toggleCounter 
nach dem ersten sleep_mode() nicht mehr verändert wird.

Gruß, Frank

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Frank Evers schrieb:
> da ja auch toggleCounter
> nach dem ersten sleep_mode() nicht mehr verändert wird.

Grundsätzlich ist es keine gute Idee, 'SetupSleepMode()' schon mal vor 
der Hauptschleife aufzurufen, das wurde aber schon gesagt. Mach das 
direkt vor dem eigentlichen sleep_mode() und sorge dafür, das dann 
später auch keine ISR mehr dazwischen funkt - z.B. der merkwürdige ADC 
Interrupt, den du freigibst und definierst, der aber leer ist?
Übrigens hat avr-libc alle Funktionen, um den Sleep Mode zu setzen, das 
musst du nicht zu Fuss machen. Hier ein kurzer Auszug aus meiner 
Fernbedienung - die Hauptschleife:
1
// poll the PCINT Flags and call accordingly
2
    {
3
    while (RemoteFlags.KeyPressed) {
4
         Flash_IR(PressedKey);
5
         CheckKeys();
6
     }
7
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // set power down mode
8
    sleep_mode();
9
    }

: Bearbeitet durch User
von Frank Evers (Gast)


Lesenswert?

Oliver S. : Ich habe mir in der Hauptschleife den Zählerstand von z.B. 
wakeupCounter oder toggleCounter über Blinken der ERROR_LED anzeigen 
lassen, und auch mal wakeupCounter um 2 inkrementiert und das Ergebnis 
ist jeweils, dass beim ersten Schleifendurchlauf inkrementiert wird und 
danach nichts mehr passiert.
ABER: du hast Recht! Testweise habe ich jetzt mal wakeupCounter mit 9 
initialisiert und hier wird auch inkrementiert und in die if Verzweigung 
gesprungen,
1
       wakeupCounter++;
2
3
      if ( wakeupCounter >= 10  || ( PIND & ( 1 << TEST_JUMPER )) || setNewReferenceValue )
4
      {
5
        wakeupCounter = 0;

aber die Zuweisung wakeupCounter = 0 funktioniert offenbar nicht, denn 
im nächsten Aufruf wird wieder in die if-Verzweigung gesprungen (und in 
allen folgenden). Das Problem scheint also früher als gedacht zu 
beginnen. Irgendwas mit den Gültigkeitsbereichen was ich übersehe? Ich 
deklariere aber ja alles global...

Gruß, Frank

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Frank Evers schrieb:
> setNewReferenceValue

Und auch hier empfehle ich dir dringend, das zu einer bool'schen 
Variable zu machen. Ein TRUE oder FALSE ist eindeutig - ein 0 oder 1 ist 
hier irreführend.

von Peter D. (peda)


Lesenswert?

Matthias S. schrieb:
> Grundsätzlich ist es keine gute Idee, 'SetupSleepMode()' schon mal vor
> der Hauptschleife aufzurufen

Warum denn?
Entweder Du traust dem MC, daß einmal gesetzte Register ihren Wert 
behalten oder der MC ist Schrott.
Code, der einmalig etwas ändert, gehört immer vor die Mainloop.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Frank Evers schrieb:
> aber die Zuweisung wakeupCounter = 0 funktioniert offenbar nicht, denn
> im nächsten Aufruf wird wieder in die if-Verzweigung gesprungen (und in
> allen folgenden).
Dafür gibt es ja noch zwei andere Möglichkeiten. Mach die doch mal 
raus...

Frank Evers schrieb:
> Bei meinem ersten AVR-Projekt
> cli();
> :
> _delay_ms(100);
> :
> sei();
Ich habe da einen offensichtlichen Programmfehler gefunden... ;-)

Allein das delay_ms() im ablauf deutet auf einen unschönen 
Programmierstil hin. Aber solange die Interrupts abzuschalten, das 
grenzt an Verzweiflung. Das ist, wie wenn du den Milchmann nach dem 
Klingeln eine Woche vor der Tür warten lässt. Und dich hinterher über 
die saure Milch beschwerst...

Als Tipp: dieses Programm wäre besser und einfacher, wenn es nur mit 1 
Timerinterrupt für die Zeit und ohne delay() programmiert wäre. 
Allerdings brauchst du da einen etwas anderen Programmierstil.

von Thomas E. (thomase)


Lesenswert?

1
  
2
  // set Timer2 Pescaler ( CS22 - CS20) to 1024 and turn on CTC mode ( WGM21, WGM20 )
3
  TCCR2 &= ~(( 1 << WGM20 ) | ( 1 << WGM21 ));
Das ist kein CTC, sondern Normal Mode.



1
  TIFR &= ~(( 1 << OCF2 ) | ( 1 << TOV2 ));
So löscht man keine Interrupt Flags.



1
 
2
 TIMSK |= (( 1 << OCIE2 ) | ( 1 << TOIE2 ));
Wo ist die Compare-ISR?


Auch wenn der CTC-Mode nicht eingestellt ist, wird das Compare-Flag in 
jedem TCNT-Umlauf gesetzt und der entsprechende Interrupt ausgeführt. Da 
du keine ISR dafür hast, fängt dein Programm dann wieder von vorne an.

von Frank Evers (Gast)


Lesenswert?

Hi

@Thomas Eckmann:
Im Verlauf der Fehlersuche habe ich schon das eine oder andere probiert 
und in dem Zuge CTC in Normal Mode geändert, dabei aber (da hast du 
Recht) vergessen den Interrupt dafür auszuschalten und die Kommentare 
geändert. ja, alles etwas verzweifelt.

Wie löscht man Interrupt-Flags?

JIPPEE, das ungenutzte Compare-Interrupt rausgenommen und es scheint auf 
den ersten Blick zu funktionieren :) Mal schauen ob jetzt auch der Rest 
tut.

@Lothar Miller:

Die beiden anderen Möglichkeiten für die if-Verzweigung hatte ich 
natürlich vorher schon testweise rausgenommen.
Die Interrupts deaktiviere ich, weil ich während des Türöffnens, bzw. 
Türschließens keine Zustandsänderung will. Sollte zugegebenermaßen auch 
so nicht passieren, das war das Codeäquivalent zum Angstblech ;) Ich 
fange ja erst an mit der MC-Programmierung.

das delay_ms ist nicht schön, das war mir auch beim Schreiben schon 
klar, ich habe da eine schnelle und dreckige Lösung gesucht mit Ambition 
das später schöner zu machen, nur warum ist das ein Programmfehler? 
Sollte das an der Stelle nicht trotzdem wie gewünscht klappen?

Nur 1 Timerinterrupt: Meinst du den TIMER2 auch rausnehmen? Wie kriege 
ich den MC dann aus dem Power Save Mode? Oder zusätzlich einen Timer für 
die Zeitsteuerung? TIMER2 wollte ich eigentlich so lassen, sonst ist die 
Batterie so schnell leer...

Gruß, Frank

von Thomas E. (thomase)


Lesenswert?

Frank Evers schrieb:
> Wie löscht man Interrupt-Flags?

Indem man eine 1 an die entsprechende Stelle schreibt.
Im einfachsten Fall TIFR = TIFR.

Du solltest dich allerdings dringend intensiv mit dem Datenblatt 
befassen.

von Frank Evers (Gast)


Lesenswert?

Hi

Thomas E. schrieb:
> Indem man eine 1 an die entsprechende Stelle schreibt.
> Im einfachsten Fall TIFR = TIFR.

Hmm, ja, ich lösche also ein gesetztes Bit indem ich es nochmal setze...
Ja, steht so im Datenblatt, wenn auch etwas verklausoliert

> Du solltest dich allerdings dringend intensiv mit dem Datenblatt
> befassen.

Hatte ich eigentlich, dachte ich, aber diese Passage hatte ich falsch 
gelesen.

Gruß, Frank

von Frank Evers (Gast)


Lesenswert?

Dank eurer Hilfe funktioniert meine Hühnerklappe jetzt erstmal wie sie 
soll. In der Schaltung waren noch ein paar Korrekturen nötig. Was mich 
dabei überrascht hat: Ich wollte einen Spannungsteiler aus LDR und 10k 
Festwiderstand direkt über MC-Pin betreiben, aber die 
Ausgangsspannungpannung brach massiv ein, obwohl rechnerisch maximal 
rund 300uA drüber gehen sollten - Ich dachte das schafft der ATmega. Mit 
einem Transistor drin geht es jetzt sehr gut.

Der INT0-Interrupt funktionierte so noch nicht, ein Blick ins Datenblatt 
verriet mir dann, dass der in allen Schlafzuständen außer Idle nur mit 
Low-Pegel oder Pegeländerung funktioniert, nicht aber mit Signalflanken.

Für den Ersatz der Delays habe ich mir mittlerweile was ausgedacht, das 
muss aber bis nach dem Urlaub warten. Das bemängelte Ausschalten der 
Interrupts war in der Tat unnötig und ist jetzt raus.

Wie auch immer: Erstes Mikrocontrollerprojekt erfolgreich und eine Menge 
dabei gelernt :)

Gruß, Frank

von Einer K. (Gast)


Lesenswert?

Frank Evers schrieb:
> Ausgangsspannungpannung brach massiv ein, obwohl rechnerisch maximal
> rund 300uA drüber gehen sollten - Ich dachte das schafft der ATmega. Mit
> einem Transistor drin geht es jetzt sehr gut.

Dann hast du den Pin nicht als Ausgang gesetzt, sondern nur den Pullup 
aktiviert.

Tipp:
Ein bisschen mehr Sorgfalt, dann klappts auch mit den AVR.

von Frank Evers (Gast)


Lesenswert?

Arduino F. schrieb:
>> Ausgangsspannungpannung brach massiv ein, obwohl rechnerisch maximal
>> rund 300uA drüber gehen sollten - Ich dachte das schafft der ATmega. Mit
>> einem Transistor drin geht es jetzt sehr gut.
>
> Dann hast du den Pin nicht als Ausgang gesetzt, sondern nur den Pullup
> aktiviert.

Nö, der ist schon als Ausgang gesetzt, siehe setupIOs():
1
  /* set optputs */
2
  // L293 enable, 1A, 2A, Sensor supply
3
  DDRC |= ( 1 << DDC5 ) | ( 1 << DDC4 ) | ( 1 << DDC3 ) | ( 1 << DDC1 );

Ich habe die Schaltung auch dreimal durchgemessen. Der ADC ist ja auch 
als Eingang beschaltet und somit hochohmig. Ich werde es mir im Zuge des 
nächsten Upgrades nochmal anschauen.
Da die Schaltung batteriebetrieben ist sind da noch große 
Einsparpotentiale auszuschöpfen :)

>
> Tipp:
> Ein bisschen mehr Sorgfalt, dann klappts auch mit den AVR.

Naja, ist halt ziemlich viel Info auf einmal. 300 Seiten Datenblatt 
bleiben nicht mit einem mal lesen hängen. Und es klappt ja. Ich habe nur 
vorher keinerlei Erfahrung mit den Biestern gehabt, insoweit bin ich 
eigentlich ganz zufrieden mit dem Ergebnis. Was mir fehlt ist in erster 
Linie Erfahrung, aber daran arbeite ich ja :)

Gruß, Frank

von Einer K. (Gast)


Lesenswert?

Frank Evers schrieb:
> Nö, der ist schon als Ausgang gesetzt, siehe setupIOs():
Tut mir leid, daran kann ich nicht sehen, welchen Pin du dafür benutzt 
hast.
Und schon gar nicht, kann ich das im Zusammenhang prüfen.

Ein High geschalteter Ausgang sollte min. 20mA liefern können.
Wenn er das nicht kann, liegt irgendwas ganz arg daneben.

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.