attiny85 sleep mode

hallo,

ich komme mit folgendem sketch leider nur auf 350µA, es sollen aber erheblich weniger möglich sein:

#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
.
.
.
.

power_all_disable();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
sleep_disable();

woran kann das liegen bzw was fehlt noch ?

auf dem ic steht attiny85 20pu

und unten
ac2 hqa
b 1p
1448 e3

Versuch es mal so:

#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
.
.
.
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
ADCSRA = 0;            // ADC ausschalten
power_all_disable ();  
sleep_enable();
sleep_cpu();             // µC schläft                
.
.
.

Die Frage ist auch, wie der ATtiny wieder aufwacht. Interrups wären eine Möglichkeit. Bei deinem Code ist zwar <avr/interrupt.h> eingebunden, aber ich sehe keine ISR. Es ist ja auch nicht der gesamte Code (übrigens: verwende bitte Code Tags - klick auf </> über dem :slight_smile: ).

Einen interessanten Artikel (engl.) zum Thema “Stromsparen” und Sleep gibt es hier :
http://www.gammon.com.au/power

Und Spezielles für ATtiny:
ATtiny85 sleep mode and wake on pin change (0,5 µA)
http://www.gammon.com.au/forum/?id=11488&reply=9#reply9

ATtiny85 sleep mode, wake on pin change interrupt or watchdog timer (6,66 µA)
http://gammon.com.au/forum/?id=11497&reply=6#reply6

danke schön ! werds mir mal durchlesen......

ne ist nicht der ganze code....... ist jetzt nur zum ausprobieren.... aufwachen soll der später mit hilfe von watchdog.

ich wollte nur wissen, ob die befehle, die ich verwende ausreichend/richtig sind ?

weil ich hab mein amperemeter in reihe zum vcc und komme damit nur auf 350µA und nicht auf die 6,6µA oder gar 0,5µA von denen ich öffters lese......

noch mal eine frage nebenbei zu den möglichkeiten: die power.h beinhaltet etliche funktionen des µC, die man seperat an/abstellen kann oder alle mit "power_all_disable (); "

die sleep.h hat die drei funktionen (hab dann noch 350µA): sleep_enable(); sleep_cpu(); sleep_disable(); da hab ich aber nicht so ganz verstanden, was die machen (hatte schon was darüber gelesen). nur wird anscheinend oft enable und disable zum abschalten verwendet ?

dann kann man noch die BOD abstellen? (hat mir aber keine (für mich) messbare ersparnis gebracht): sleep_bod_disable(); funktioniert aber nicht bei allen attiny versionen ?

und dann habe ich auch noch den befehl gefunden, bei dme ich nicht weiß, was er macht(ich vermute er schaltet interrupts an und ab?: GIMSK |= _BV(INT0); //enable INT0 GIMSK = 0x00; //disable INT0

und du hast auch noch den ADC abgeschaltet: ADCSRA = 0; // ADC ausschalten ist der nicht auch in der power.h enthalten ?

wenn ich den ADC ausschalte spare ich 320µA ! (der attiny verbaucht dann nur noch strom im (für mich) nicht mehr messbaren bereich (: ) nur bekomme ich den ADC im laufenden program nicht wieder angeschaltet.... mit ADCSRA = 1; ?

und welche sachen kann ich während des normalen betriebs abschalten um energie zu sparen ? wenn ich nur einen dht22 (oder einen ic2 sensor) und ein 433mhz sender am atiny hab ? den ADC brauche ich doch nur, wenn ich die analogen eingänge oder pwm nutze oder ? die BOD brauche ich doch auch nicht ?

nur bekomme ich den ADC im laufenden program nicht wieder angeschaltet.... mit ADCSRA = 1; ?

Vor dem Abschalten des ADC muss geprüft werden, ob die Wandlung abgeschlossen ist. Wird er mitten in der Wandlung abgeschaltet, ist er meist tot bis zum nächsten Stromausfall.

hmmm und wie macht man das ?

also ich hab grad emal nachgesehen. in der power.h ist der ADC auch enthalten, ich kann ihn über diese aber nicht abstellen...

funktioniert nur mit

"cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter "

oder

ADCSRA = 0; // ADC ausschalten

Hallo,

was macht denn

<avr/power.h>

zusätzlich oder anders?

Ich verwende nur

<avr/sleep.h>

und habe mich daran gehalten. http://playground.arduino.cc/Learning/ArduinoSleepCode
mit set_sleep_mode(SLEEP_MODE_PWR_DOWN);
setze ich auch den tiefsten Modus.

die power.h soll wohl so einiges machen:

http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html

allerdings hab ich nicht so das gefühl, das die viel bringt.....

die soll wie gesagt auch den ADC abstellen, aber irgendwie klappts mit ihr nicht......

ich hab aber auch noch das gefunden:

ACSR = B10000000; // Analogen Comparator abschalten, ACD bit7 zu 1
DIDR0 = DIDR0 | B00111111; // Digitale Eingangspuffer ausschalten, analoge Eingangs Pins 0-5 auf 1

ich hätte da aber noch eine frage.... und zwar versetze ich den tiny in schlafmodus und lasse ihn dann durch den watchdog aufwecken.... der watchdog kann aber nur bis zu 8sec. also kommt der tiny sofrt wieder in schlafmodus, durch ein counter usw.

wenn ich jetzt zB möchte, das der tiny 10sec schläft gibt es jetzt zB folgende möglichkeiten:

  1. ich wecke ihn mit dem watchdog einmal nach 8sec und dann gehts wieder in sleep-modus und dann wecke ich ihn wieder nach 2sec = 10sec..

  2. oder ich stelle den watchdog auf 1sec ein und er wird nach eienr sec wache und fällt direkt wieder in sleep-modus. das dann 10 mal.

ich frage mich, ob die zweite methode "spührbar" mehr akkukapazität aufbraucht, als die erste oder ob es kein bzw kaum ein unterschied macht ?? weil die zweite finde ich programmiertechnisch angenehmer, wenn man mit variablen zeiten arbeitet.... bei der zweiten wäre der tiny doch dann immer für den bruchteil einer sekunde wach und geht dann wieder schlafen ? mein messgerät zeigt über die gesamte dauer 0,01mA an..... aber messgeräte sind auch träge und das ist das kleinst mögliche, das mein messgerät anzeigen kann (;

Warum nicht einfach immer das vielfache von 8 nehmen? (8, 16, ...). Einfach bei jedem Aufwecken durch den WDT eine Variable hochsetzen. Wenn die Variable bei 2 angekommen ist, wieder auf 0 setzen und Aktion ausführen (bei 16s). Spürbar verbraucht keine der Methoden Akkukapazität.

Da bringt es deutlich mehr, denn Attiny auf 1MHz zu takten. Die Messungen mit deinem Multimeter kannst in dem Bereich nicht zwingend mehr gebrauchen. Mein Fluke179 hat eine Auflösung von 0,01mA, weniger macht es nicht. Das ist für sowas viel zu ungenau, vorallem wenn du wirklich im µA Bereich runterwillst. Vermutlich braucht die externe Beschaltung das xFache an Strom.

ACSR = B10000000; // Analogen Comparator abschalten, ACD bit7 zu 1

Lesbarer wird es wenn man die Namen der Bits verwendet. Worauf es im ACSR Register ankommt ist das ACD Bit (Analog Comparator Disable)

Also:

ACSR = _BV(ACD);

oder

ACSR = (1 << ACD);

Bewirkt das gleiche, aber man muss sich nicht wundern welches Bit man da jetzt gesetzt hat. Wobei der Komparator standardmäßig ausgeschaltet sein sollte.

Aber das gleiche gilt für das ADC Status Register ADCSRA und das ADEN Bit. Mit ADCSRA = _BV(ADEN) setzt man das Bit. So hat man den Namen des Registers und des Bits in der Anweisung.

Die Register-Beschreibung gibt es im Datenblatt:

Seite 120 für das Komparator Status Register. 136 für den ADC

Hallo,

Du kannst doch zwischen 16ms, 32ms, 64ms, 125ms, 250ms, 500ms, 1sec. 2sec, 4sec und 8sec. wählen. Wenn Du unbedingt im 10sec. Rhythmus was tun möchtest, wäre der kleinste Nenner 2 Sekunden. Und dieses kurze aufwachen, Variable hochzählen und wieder schlafen legen ist die übliche Methode. Das passiert alles innerhalb von "paar Takten", fältt absolut nicht ins Gewicht. Da mußte Dir keinen Kopf machen.

@ alle: danke schön !

@serenifly: stimmt…diese verschiedenen schreibweisen haben mich anfangs auch etwas verwirrt…
ich hab mich jetzt auf (1<< …) festgelegt.

das: DIDR0 = DIDR0 | B00111111;
geht ja auch so: DIDR0 = (1 << ADC0D) | (1 << ADC2D) | (1 << ADC3D) | (1 << ADC1D) | (1 << AIN1D) | (1 << AIN0D);

@ sschultewolter und doc:
wenn es wirklich nur einen bruchteil mehr “verbraucht” (sagen wir mal 1-2tage bei 100tagen).
dann ist mir das lieber den watchdog auf 1sec festzulegen, weil ich eventuell den schlafinterval mit einem 3er dip-schalter festlegen möchte keine pause, 5sec, 10sec, 30sec, 60sec, 5min, 10min, 30min, 1std oder so, mal sehen und da läßt sich mit einer watchdog-sekunde super rechnen, ohne viel programmieraufwand (;
5 watchdog sec wären auch noch gut, aber die gibts ja nicht (;
2 ging auch noch, wenn ich statt 5sec 4 nehme, aber bei 4 und 8 watchdogsekunden wirds eng…

Vermutlich wird dein größtes Problem die Spannungsregelung/Batterieladung in Bezug auf Selbstentladung ein.

das denke ich auch (; oder der co2-sensor, der dauerhaft geheizt werden muss.... bzw die "aufwärmphase" die ja beim dht22 3sec beträgt ? ich glaub, da muss ich mich nach was sparsamerem umsehen (;

ich hab wo gelesen, das es auch etwas einsparen soll, alle ports auf INPUT zu stellen...... ich hab mal was rumgespielt und mit INPUT hatte ich da keine wirkliche einsparung, aber wenn ich alle ports auf OUTPUT gestellt hatte, hat das ca 2ma ausgemacht, im aufgeweckten zustand.

Auf der Nick Gammon Seite wird gezeigt was wie viel bringt. Viele dieser Details sind im µA Bereich. Das misst du wie gesagt mit einem normalen Multimeter nicht mehr richtig.

ok, danke ! habs soweit ans laufen bekommen bzw wieder was gelernt (;

eins hab ich aber noch nicht verstanden und zwar das heir: |=

ich hab im sketch zb einmal sowas hier stehen:
ADCSRA = (1 << ADEN); // ADC ausschalten

und einmal sowas:
ADCSRA |= (1<<ADSC); // Start conversion

das erste setzt ADEN doch auf 1 bit oder ?

und das zweite ? was macht dieser strich vor dem = ?
eine alternative schreibweise ist es nicht oder ? weil ich hab schon versucht den wegzulassen, was dazu geführt hat, dass das program nicht mehr läuft…

Schau dir mal das Thema Bitmanipulation an.

= setzt ein Bit auf 1, alle anderen auf 0 |= setzt ein Bit auf 1, alle anderen werden nicht umgeschrieben.

Und noch was:

magictrips:
ich hab im sketch zb einmal sowas hier stehen:
ADCSRA = (1 << ADEN); // ADC ausschalten

Das aktiviert den ADC (das ist ein Enable Bit). Um das Bit zu löschen macht man UND mit dem Inversen:

ADCSRA &= ~(1 << ADEN);

vielen dank an euch !

das mit dem &, wäre nämlich auch noch so eine offene frage gewesen (;

mit ADCSRA = (0 << ADEN);
hats auch geklappt.

ist daran was falsch oder hat das sonstige auswirkungen ?

also “&= ~” löscht ein bit dann einfach nur ?

auch umgedreht, wenn es ein disablebit ist ?

ADCSRA = (0 << ADEN); 
hats auch geklappt.

Nur durch Zufall, weil du = verwendet hast und damit das gesamte Register auf 0 gesetzt wird. Ansonsten ist das völliger Unsinn. Mit |= hätte sich da nichts geändert. Das Schieben soll erst mal ein bestimmtest Bit im Masken-Byte setzen. Wenn du 0 x mal nach links schiebst kommt natürlich nur 0 heraus.

Wenn du das nicht verstehst verwende die Arduino Makros bitSet() und bitClear(). Damit bist du sicher.

Hallo zusammen

Für die Implementation eines elektronischen Würfels benutze ich einen ATtiny85, den ich mit einem Arduino Uno programmiere.

Die Schaltung ist dauerhaft mit einer Batterie verbunden. Um den Batterieverbrauch zu minimieren benutze ich den Sleep Mode.

Wird der uC neu programmiert oder die Speisung kurz getrennt, funktioniert alles wie es soll. Wenn der uC jedoch das erste Mal in den Sleep Mode versetzt wird, wird nach dem Aufwachen ein if-Statement (überprüft Flag-Variable) konsequent ignoriert.

Muss man beim "Aufwachen" etwas bestimmtes beachten? Zur Sicherheit weise ich sämtlichen Variablen wieder ihre Default-Werte zu, was leider auch keine Besserung gebracht hat.

Danke schon im Voraus für jeden Tipp! :)