Forum: Mikrocontroller und Digitale Elektronik AVR SLEEP_MODE_IDLE


von Reiner W. (reiner_w)


Lesenswert?

Also die Sleep-Modes kapier ich nicht so recht.
Folgendes Problem:
Programmier gerade für Arduino eine Steuerung für Gardena Bewässerung 
WT1030. Klappt auch dank der Infos hier im Forum recht gut. Nun will ich 
das Ganze batteriefähig machen und quäle mich deshalb mit den 
Sleep_modes rum.
Also Homematic Batterie Autor gibt für die Dauer der Bewässerung einen 
Pegel an den Pin2 des Arduino.
Bei der steigenden Flanke erzeugt der Arduino den Impuls zum öffnen des 
Ventils und bei der fallenden Flanke einen kurzen Schließimpuls.
Jetzt hab ich Folgendes getestet:

Hat der Pin2 High-Pegel erzeuge ich den kurzen Ein-Impuls und rufe dann 
SLEEP_MODE_PWR_DOWN  mit
1
attachInterrupt(interruptNumber, wakeUpNow, LOW)

auf, damit sich der Arduino bis zum LOW an Pin2 schlafen legt. Das 
klappt soweit.
Hat Pin2 LOW-Pegel erzeuge ich den kurzen AUS Impuls und rufe dann
SLEEP_MODE_IDLE auf, weil ich ja nur im IDLE Mode die nächste Flanke 
Triggern kann.
Klapp auch soweit.
In meiner Loop() hab ich so ein bisschen Debug Code um das ganze zu 
testen.
Da steht dann u.a.
1
  ...
2
  delay(100);      
3
  sleepNow();     // wieder schlafen legen
4
5
  Serial.print("Jupp, da bin ich wieder :"); 
6
  Serial.print(zaehler);     //aktueller zaehler (der wievielte Interrupt)
7
  Serial.print(" :"); 
8
  
9
  Serial.println(tasterWert);
10
  ...

Dabei stelle ich fest, dass im SLEEP_MODE_IDLE die Loop() permanent 
durchlaufen werden, natürlich mit konstantem zaehler (der wird in der 
ISR inkrementiert).

Aber wieso loopt er weiter ?? Der sollte doch nach sleepNow() stoppen?

Hoffe, ich hab mich einigermaßen verständlich ausgedrückt und jemand 
kann helfen

Danke Reiner

von Ingo (Gast)


Lesenswert?

Wasn das für ne Syntax?


Ingo

von Reiner W. (reiner_w)


Lesenswert?

Sorry, ist nur ein Auszug aus meinem Arduino Code.

Reiner

von Jonathan S. (joni-st) Benutzerseite


Lesenswert?

Reiner W. schrieb:
> ist nur ein Auszug

Sorry, aber ohne vollständigem Code können wir dir nicht richtig helfen. 
BTW: Du kannst den Controller übrigens auch die ganze Zeit lang im 
Powerdown lassen, wenn Du Pin-Change-Interrupts benutzt. Und manche 
Interrupts auf Low-Level werden die ganze Zeit lang durchgehend 
getriggert (-> ISR wird dauernd aufgerufen + µC wird dauernd 
aufgeweckt).


Gruß
Jonathan

von Reiner W. (reiner_w)


Lesenswert?

OK, hier mein Testcode:
1
//benötigte Libs
2
#include <avr/sleep.h>
3
4
int tasterPin = 2; // Taster-Pin 2
5
int ledPin = 13; // LED-Pin 13
6
int tasterWert = 0; // Variable zur Aufname des Tasterstatus 
7
8
int vorherZaehler = 0; // alter Zählerstand
9
volatile int zaehler = 0; // Zählervariable
10
11
int interruptNumber = 0; //Pin Change Interrupt an Pin 2
12
13
void setup(){
14
  pinMode(tasterPin, INPUT); // Taster-Pin als Eingang
15
  pinMode(ledPin, OUTPUT); // LED-Pin als Ausgang 
16
  
17
  tasterWert = digitalRead(tasterPin);
18
19
  attachInterrupt(interruptNumber, wakeUpNow, CHANGE);  //bei jeder Flanke ISR aufrufen
20
21
  Serial.begin(9600);
22
}
23
24
void sleepNow(){       // here we put the arduino to sleep
25
  
26
   attachInterrupt(interruptNumber, wakeUpNow, CHANGE);  //bei jeder Flanke ISR aufrufen
27
   //wenn  1 -> kann SLEEP_MODE_PWR_DOWN verwendet werden (LOW)
28
   //sonst 0 -> SLEEP_MODE_IDLE  (CHANGE)
29
   //delay(100);
30
   set_sleep_mode(SLEEP_MODE_IDLE);   // sleep mode is set here for pwr_down
31
   sleep_enable();                        // enables the sleep bit in the mcucr register
32
33
     
34
   digitalWrite(ledPin, LOW);  //kann weg
35
   Serial.print("ich geh schlafen"); 
36
37
   sleep_mode();            // here the device is actually put to sleep!!
38
                                   // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
39
 
40
   sleep_disable();         // first thing after waking from sleep:
41
                                 // disable sleep...
42
   detachInterrupt(0);      // disables interrupt 0 on pin 2 so the
43
                                   // wakeUpNow code will not be executed
44
                                  // during normal running time.
45
   Serial.print("Jupp, da bin ich wieder :"); 
46
   digitalWrite(ledPin, HIGH);  //kann weg
47
48
}
49
50
51
void loop(){
52
  
53
  tasterWert = digitalRead(tasterPin);
54
  
55
  if(vorherZaehler != zaehler) {  //da gabs nen Interrupt
56
    
57
     vorherZaehler = zaehler;     //Zaelerstand merken
58
     
59
     Serial.print("Zaehlerstand:");
60
     Serial.println(zaehler);     //aktueller zaehler (der wievielte Interrupt)
61
     
62
     Serial.print("TasterWert ist:"); 
63
     Serial.println(tasterWert);   
64
65
  } 
66
     
67
  delay(100);      // weis der Geier warum???
68
  sleepNow();     // wieder schlafen legen
69
70
  Serial.print("Jupp, da bin ich wieder :"); 
71
  Serial.print(zaehler);     //aktueller zaehler (der wievielte Interrupt)
72
  Serial.print(" :"); 
73
  
74
  Serial.println(tasterWert);
75
76
}
77
78
79
void wakeUpNow(){
80
  //Taster braucht gar nicht mehr abgefragt werden, weil er ja ohne tasterdruck gar nicht hier landet        
81
  zaehler++; // Zähler inkrementieren (+1)
82
}

Offenbar geht er gar nicht in den Sleep_Mode, weil die beiden 
Debugausgaben aus  sleepNow() permanent im Monitor kommen:

ich geh schlafenJupp, da bin ich wieder

?? Was mach ich falsch ? hat jemand einen Tipp?

Reiner

von Jonathan S. (joni-st) Benutzerseite


Lesenswert?

Was genau ist das für ein Controller, auf dem Du da programmierst? Ein 
ATMega328P?

von Jonathan S. (joni-st) Benutzerseite


Lesenswert?

Du kannst übrigens anstatt dem IDLE-Modus auch den POWER-DOWN-Modus 
nehmen. Außerdem hasse ich solche vorgebastelten 
Konfigurations-Funktionen, weil man nie weiß, wie die Funktion die 
Register jetzt wirklich setzt. Da ist mir ein klares, einfaches "SBI 
DDRA, 2" doch lieber als ein "PinMode(2, OUTPUT)"...

Außerdem wird dein Code ganz schön Overhead haben, wenn Du "tasterPin", 
"ledPin" und "interruptNumber" als Variablen deklarierst - falls dein 
Compiler das nicht wegoptimiert. Falls er's nicht wegoptimiert, besteht 
übrigens auch die Wahrscheinlichkeit, dass der Compiler da 
durcheinanderkommt und totalen Müll produziert. Benutz' doch Konstanten 
für solche Konfigurationssachen - dazu wurden sie doch gemacht!

von Reiner W. (reiner_w)


Lesenswert?

Ja, es ist ein Atmega328P.
Mit deinen Bemerkungen hast du natürlich recht. Im endgültigen Code 
sollen nur noch Konstanten drin sein.
Lese mich grad intensiver in die AVR Programmierung ein um direkter 
programmieren zu können.
Den POWER-DOWN Modus hab ich ja problemlos hinbekommen. Das Problem ist, 
dass ich mich da nur per LOW am Eingang wecken lassen kann.
Ich muss aber bei jeder Flanke einen Ausgangsimpuls erzeugen, die auch 
noch unterschiedliche Länge haben.
Dazwischen liegen 0,5-2h, deshalb will ich ihn dazwischen in den Sleep 
Mode schicken.
Wie komme ich beim POWER-DOWN mit ner positiven Flanke wieder zurück?
Deshalb dachte ich, ich Wechsel je nach Eingangslevel den SLEEP-MODE.

Wenn Pin2==HIGH -> aktiviere POWER-DOWN und weckmich mit LOW
Wenn Pin2==LOW  -> aktiviere IDLE Sleep Mode und wecke mich bei der 
nächsten Flanke (CHANGE)

Oder gibt es dafür einfacherer Lösungen?

Reiner

von avion23 (Gast)


Lesenswert?

Hallo Reiner,

ich habe nur ueberflogen.

- idle wacht auf bei allem moeglichen und die instruction danach wird 
noch ausgefuehrt. Alles moegliche sind z.b. interrupts von timern oder 
rs232 oder pinchange.
- in c muss man erst den modus einstellen, dann sleep_enable(); 
aufrufen.

- theoretisch kannst du auch pollen: watchdog timeout auf 250ms 
einstellen. In der watchdog ISR
* watchdog interrupt reaktivieren
* taster abfragen
* je nach ergebnis in der main wieder schlafen schicken
* oder wach bleiben und wichtiges tun
Das kannst du alles im power down modus. Der braucht vergleichsweise 
lange zum wachwerden. Das ist aber egal, weil er danach nur sehr wenig 
Strom verbraucht.

- Diese ganzen Stromsparsachen sind sehr frickelig. Aktivier unbedingt 
den brownout. Statische Elektrizitaet reicht sonst schon aus, um den 
ausgeschalteten controller zu starten und im power down bleiben zu 
lassen. Und dort natuerlich abgestuerzt.

- Teste den Stromverbrauch. ADC verbraucht z.b. 200uA. Steht auch im 
Datenblatt, nur sehr versteckt. Strom teste ich ueber einen 1k ohm shunt 
in Reihe. D.h. booten, idlen, 1k in Versorgungsspannung parallel 
einschleifen, Versorgungsspannung trennen.

von Peter D. (peda)


Lesenswert?

Man macht zuerst nur die Applikation.
Und wenn alles einwandfrei läuft, erst dann fügt man den Sleepmode 
hinzu:

Beitrag "AVR Sleep Mode / Knight Rider"


Peter

von Jonathan S. (joni-st) Benutzerseite


Lesenswert?

Reiner W. schrieb:
> Den POWER-DOWN Modus hab ich ja problemlos hinbekommen. Das Problem ist,
> dass ich mich da nur per LOW am Eingang wecken lassen kann.

Stimmt, hatte die Fußnote im Datenblatt nicht gelesen.


Reiner W. schrieb:
> Oder gibt es dafür einfacherer Lösungen?

Per Monoflop bei jedem Wechsel einen kurzen Low-Impuls auf den Int-Pin 
geben? Oder das Signal auf einen Int-Pin nichtinvertiert und auf einen 
anderen invertiert geben?

Oder vielleicht die Arduino-Entwicklungsumgebung in die Tonne treten und 
was gescheites nehmen? ^^
Nimm doch einfach den GCC, such dir die entsprechenden 
Konfigurations-Register aus dem Datenblatt zusammen und schreib das 
alles ohne diese ganzen Black Boxes von Konfigurationsroutinen. Das kann 
man viel besser debuggen und man weiß wenigstens, was der Controller 
denn jetzt wirklich macht.

Und wie Peter Dannegger schon schrieb: Erst das Programm, danach die 
Stromsparmaßnahmen.


Gruß
Jonathan

von Reiner W. (reiner_w)


Lesenswert?

Jonathan Strobl schrieb:
> Per Monoflop bei jedem Wechsel einen kurzen Low-Impuls auf den Int-Pin
> geben?

Ja, daran hab ich gedacht, obwohl es mir widerstrebt, Hardware zu 
nehmen, wenn es Software auch tun könnte.

Oder das Signal auf einen Int-Pin nichtinvertiert und auf einen
> anderen invertiert geben?

Ja, genug Pins sind ja da. Ich könnte im POWER_DOWN bleiben und müßte 
mit jedem Impuls nur den Int-Pin wechseln. Bleibt ein Inverter übrig, 
den ich basteln muss.

>Oder vielleicht die Arduino-Entwicklungsumgebung in die Tonne treten und
>was gescheites nehmen? ^^

Ja, da hätte ich noch einige andere Teile rumliegen;-) Aber so leicht 
aufgeben wollte ich auch nicht.

>Nimm doch einfach den GCC, such dir die entsprechenden
>Konfigurations-Register aus dem Datenblatt zusammen und schreib das
>alles ohne diese ganzen Black Boxes von Konfigurationsroutinen. Das kann
>man viel besser debuggen und man weiß wenigstens, was der Controller
>denn jetzt wirklich macht.

An dem Punkt bin ich gerade;-)

@Peter
Na ja, das läuft eigentlich ganz gut. Halt nur mit Pin_Change_Int.
Der Link ist klasse. Das acker ich gleich mal durch.

Reiner

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.