Forum: Mikrocontroller und Digitale Elektronik Attiny13A Stromverbrauch im Standby vermindern - wie?


von Frank S. (hobbyist)


Lesenswert?

Ich habe eine kleine akkubetriebene Schaltung mit einem Attiny13A 
aufgebaut. Die Fuses stehen unverändert bei FF (hfuse) und 6A (lfuse). 
Es gibt zwei Eingänge, die entweder LOW oder HIGH sind und einen 
Ausgang, der ein (in etwa) Rechtecksignal ausgibt, wenn einer (oder 
beide) Eingänge auf HIGH stehen. Die Genauigkeit des Rechtecks ist nicht 
so relevant, da damit nur ein LED-Treiber angesteuert wird.

Der Tiny wird sich überwiegend im Tiefschlaf befinden. Daher soll der 
Stromverbrauch so niedrig wie möglich sein. Er soll aufwachen, sobald 
sich der Zustand einer der beiden Eingänge verändert. Also von LOW nach 
HIGH wechselt (oder umgekehrt). Die beiden Eingänge stehen während der 
Nichtnutzung der Schaltung auf LOW.

Da mir sowohl Wissen als auch Fähigkeit für diese Thematik fehlen, 
brauche ich jetzt eure Hilfe. Den eigentlichen Sketch (ich oute mich als 
Arduino-User) habe ich selber geschrieben. Die void sleep() habe ich 
aber nur kopiert und an meine Pins angepasst.

Soweit funktioniert das, aber in einer Testschaltung (nur Tiny + KerKo + 
10k-Reset-Pullup) liegt der Verbrauch trotzdem noch bei rund 10µA. Im 
Datenblatt und im Netz finde ich Werte, die zum Teil deutlich darunter 
liegen.

Meine Frage wäre, ob und wie ich noch etwas Strom sparen kann.

von Peter D. (peda)


Lesenswert?

Frank S. schrieb:
> Soweit funktioniert das, aber in einer Testschaltung (nur Tiny + KerKo +
> 10k-Reset-Pullup) liegt der Verbrauch trotzdem noch bei rund 10µA.

Das reicht völlig, die Selbstentladung von Akkus ist deutlich höher.

von Einer K. (Gast)


Lesenswert?

Frank S. schrieb:
> Standby ... Tiefschlaf
Was denn jetzt?

Aus meiner Sicht ist es geradezu genial, bei einem Problem mit einer µC 
Schaltung sowohl Code also auch Schaltplan geheim zu halten.
Denn so hat KEINER die Chance mit dem Finger auf das Problem zu zeigen.

Mir sagt es:
Frank S. schrieb:
> Ich bin nicht wirklich an einer Lösung interessiert.
> Ich möchte mich hier nur ausheulen.


Der einzige Tipp, welcher mir einfällt:
Sorge für stabile Pegel der Pins im Schlaf.
Gerade auch der unbenutzten Pins

von Frank S. (hobbyist)


Lesenswert?

Ups, sorry. Den Sketch wollte ich, wie man dem Text entnehmen kann, 
anhängen, habe es aber vergessen, weil das Telefon ging. Die Schaltung 
ist genau so, wie ich sie beschrieben habe. KerKo zwischen GND und Vcc 
(3V3), Pullup an Reset. Das wars.

Hier der Sketch:

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

#define IN0 3
#define IN1 1
#define OUT1 4

byte Zustand_IN0;
byte Zustand_IN1;

int Frequenz1 = 100; // ms
int Frequenz2 = 3000;
int Frequenz3 = 100;


void setup() {
  pinMode(IN0, INPUT);
  pinMode(IN1, INPUT);
  pinMode(OUT1, OUTPUT);
}

void sleep()
{
    GIMSK |= _BV(PCIE);                     // Enable Pin Change 
Interrupts
    PCMSK |= _BV(PCINT3);                   // Use PB3 as interrupt pin
    PCMSK |= _BV(PCINT1);                   // Use PB1 as interrupt pin
//    ADCSRA &= ~_BV(ADEN);                   // ADC off
//ACSR = (1<<ACD);
    ADCSRA &= ~(1<<ADEN);                   // Testweise ADC off Befehl 
von anderer Webseite
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement
    sleep_enable();                         // Sets the Sleep Enable bit 
in the MCUCR Register (SE BIT)
    sei();                                  // Enable interrupts
    sleep_cpu();                            // sleep
    cli();                                  // Disable interrupts
    PCMSK &= ~_BV(PCINT3);                  // Turn off PB3 as interrupt 
pin
    PCMSK &= ~_BV(PCINT1);                  // Turn off PB1 as interrupt 
pin
    sleep_disable();                        // Clear SE bit
//    ADCSRA |= _BV(ADEN);                    // ADC on
//ACSR |= (1 << ACD);
    ADCSRA |= (1 << ADSC);                  // Testweise ADC off Befehl 
von anderer Webseite
    sei();                                  // Enable interrupts
} // sleep
ISR(PCINT0_vect)
{
// This is called when the interrupt occurs, but I don't need to do 
anything in it
}

void loop() {

  Zustand_IN0 = digitalRead(IN0);
  Zustand_IN1 = digitalRead(IN1);

  if ((Zustand_IN0 == HIGH) && (Zustand_IN1 == LOW)) {digitalWrite 
(OUT1, HIGH);}
  if ((Zustand_IN0 == LOW) && (Zustand_IN1 == LOW)) {digitalWrite (OUT1, 
LOW); sleep();}

  if ((Zustand_IN0 == LOW) && (Zustand_IN1 == HIGH)) {
    digitalWrite (OUT1, HIGH);
    delay (Frequenz1);
    digitalWrite (OUT1, LOW);
    delay (Frequenz1);
    }

  if ((Zustand_IN0 == HIGH) && (Zustand_IN1 == HIGH)) {
    digitalWrite (OUT1, HIGH);
    delay (Frequenz3);
    digitalWrite (OUT1, LOW);
    delay (Frequenz2);
    }

}

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


Lesenswert?

Wenn du eh alles zu Fuss machst, warum dann überhaupt noch das Arduino 
Framework?
Setze PB2 und PB3 auf definierte Pegel, am besten auf Output.
Achte darauf, das die Ausgänge im Sleep Modus keinen Strom ziehen 
dürfen.
Schalte ADC, AC, BOD (per Fuse) und den Watchdog ab.
Folge den Empfehlungen des ATTiny13 Datenblattes unter 'Minimizing Power 
Consumption'.

Habe hier einen Tiny44, der gerade mal 300nA im Sleep zieht, geht also.

von Martin S. (docmartin)


Lesenswert?

Da dein Tiny schlafen geht, wenn beide Eingänge low sind:
Welcher Strom fließt denn durch die (internen?) PullUp Widerstände?

Ansonsten: unbenutzte Eingänge nicht offen lassen!

Ahoi, Martin

von äxl (Gast)


Lesenswert?

(_BV) oder (1<<)? Was bedeutet _BV? Ist doch sicher ein Makro - 
oderso...
Du könntest im Datenblatt des ATTiny13 nachschauen, was das 
PowerReductionRegister (Seite 34 im Datenblatt) anbietet.
1
PRR= (1<<PRTIM0)|(1<<PRADC);
wäre schonmal was.
Brownout kann man evtl. abschalten. Spart auch Strom.
Lies bitte das Datenblatt, beschäftige dich damit, statt nur alles 
zusammenzukopieren...
Wenn Du im laufenden Betrieb den Strom etwas senken musst/möchtest, 
kannst Du auf Seite 28 dir gern das CLKPR-Register ansehen. Damit kannst 
Du den Systemtakt herunterteilen (aber darum ging es gerade nicht).

von äxl (Gast)


Lesenswert?

Wegen den PullUps: bekommst Du dein LOW/HIGH von aussen "angeboten" oder 
nur n Schalter nach Masse? ( Dann geht das nicht, sonst köntest Du die 
PullUps ausschalten, wenn "pinMode(IN1, INPUT)" das nicht schon Hause 
aus macht, kannst Du zur Sicherheit noch einen digitalWrite 
hinterherschicken.
1
void setup() {
2
  pinMode(IN0, INPUT);
3
  pinMode(IN1, INPUT);
4
  digitalWrite (IN0, LOW);
5
  digitalWrite (IN1, LOW);
6
  pinMode(OUT1, OUTPUT);
7
}
Die Online-Hilfe kennst Du aber?
https://www.arduino.cc/en/Tutorial/DigitalPins

von M. K. (sylaina)


Lesenswert?

Den ADC brauchst du nicht, also kann man den auch ausschalten im PRR mit
1
PRR |= (1 << ADC);

Den Analog Comparator brauchst du auch nicht, also auch abschalten
1
ACSR |= (1 << ACD);

Das spart auch noch mal ne Menge Strom. Ist im obigen Code nur im 
Kommentar drin.

Auch habe ich oben ein
1
ADCSRA |= (1 << ADSC);

gesehen an dem im Kommentar stand "Testweise ADC off Befehl" aber diese 
Zeile startet eigentlich den ADC (und ADC != ACD ;)).

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Minimale Stromaufnahme erreichst du so:

- ADC Abschalten
- Keinen Watchdog verwenden (oder abschalten)
- Keinen Brown-Out Detektor verwenden (fuses)
- Alle I/O Pins auf einen definierten HIGH oder LOW Pegel bringen (z.B. 
mit den internen Pull-Up Widerständen oderals Ausgang konfigurieren)
- Keine wechselnden Signalpegel an irgendwelche Pins anlegen
- Temperatur senken (Zimmertemperatur reicht)

Die Stromaufnahme sollte dann unter 0,5µA sinken.

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


Lesenswert?

M. K. schrieb:
> Den ADC brauchst du nicht, also kann man den auch ausschalten im PRR mit
> PRR |= (1 << ADC);

Sowas gibts beim Tiny13(A) nicht.

von Peter D. (peda)


Lesenswert?

Frank S. schrieb:
> Hier der Sketch:

Was meinst Du, wozu der Punkt "Dateianhang" da ist?

von Frank S. (hobbyist)


Lesenswert?

Vielen Dank für die vielen konstruktiven Tipps!
Der wichtigste Hinweis scheint gewesen zu sein, dass beide Eingänge auf 
Masse gezogen werden müssen. Wenn ich das mache, habe ich einen 
Stromverbrauch von rund 2,5µA mit folgenden Befehlen:

void sleep()
{
    GIMSK |= _BV(PCIE);                     // Enable Pin Change 
Interrupts
    PCMSK |= _BV(PCINT3);                   // Use PB3 as interrupt pin
    PCMSK |= _BV(PCINT1);                   // Use PB1 as interrupt pin
//    ADCSRA &= ~_BV(ADEN);                   // ADC off
//PRR = (1 << ADC);    // ADC aus - aus µC Forum
ACSR = (1<<ACD);
    ADCSRA &= ~(1<<ADEN);                   // Testweise ADC off Befehl 
von anderer Webseite
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement
    sleep_enable();                         // Sets the Sleep Enable bit 
in the MCUCR Register (SE BIT)
    sei();                                  // Enable interrupts
    sleep_cpu();                            // sleep
    cli();                                  // Disable interrupts
    PCMSK &= ~_BV(PCINT3);                  // Turn off PB3 as interrupt 
pin
    PCMSK &= ~_BV(PCINT1);                  // Turn off PB1 as interrupt 
pin
    sleep_disable();                        // Clear SE bit
//    ADCSRA |= _BV(ADEN);                    // ADC on
//PRR |= (1 << ADC);
ACSR |= (1 << ACD);
    ADCSRA |= (1 << ADSC);                  // Testweise ADC on Befehl 
von anderer Webseite
    sei();                                  // Enable interrupts
} // sleep
ISR(PCINT0_vect)
{
// This is called when the interrupt occurs, but I don't need to do 
anything in it
}

Die auskommentierten Befehle brachten keine weitere Stromersparnis. 
Heute fehlt mir die Zeit, um noch das Datenblatt zu studieren. Ich hoffe 
es am kommenden Wochenende zu schaffen. Dann verstehe ich vielleicht 
auch besser, was mit den einzelnen Befehlen bewirkt wird.

von Falk B. (falk)


Lesenswert?

Frank S. schrieb:
> Die auskommentierten Befehle brachten keine weitere Stromersparnis.
> Heute fehlt mir die Zeit, um noch das Datenblatt zu studieren. Ich hoffe
> es am kommenden Wochenende zu schaffen. Dann verstehe ich vielleicht
> auch besser, was mit den einzelnen Befehlen bewirkt wird.

Wie süß, mal wieder Copy&Paste "Programmierer"

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Matthias S. schrieb:
> M. K. schrieb:
>> Den ADC brauchst du nicht, also kann man den auch ausschalten im PRR mit
>> PRR |= (1 << ADC);
>
> Sowas gibts beim Tiny13(A) nicht.

Stimmt, PRADC ist das Flag.
Datasheet Seite 34, vgl. Anhang ;)

: Bearbeitet durch User
von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

> M. K. schrieb:
>> Den ADC brauchst du nicht, also kann man den auch ausschalten im PRR mit
>> PRR |= (1 << ADC);

Matthias S. schrieb:
> Sowas gibts beim Tiny13(A) nicht.

Ich habe mal eine Seite vom Datenblatt des ATTiny13A angehängt. Soweit 
ich weiß, hat der ATtiny13 das Bit nicht, und der ATTiny13A hat es.

von Mutluit M. (mutluit)


Lesenswert?

@Frank S., hier ein Tip für dich:

du kannst dein Code zwischen [Xcode] und [/Xcode] kopieren (das X 
löschen :-), dann wird das Original-Format beibehalten. Probiere es aus.

: Bearbeitet durch User
von Einer K. (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe das Programm mal durchgefegt.
Die Logik in loop() allerdings nicht geprüft
Und, ob es Stromsparender geworden ist, auch nicht...
Da kein Tiny13a zur Hand.
Also: Alles ohne Gewähr


Klar, scheint es etwas übertrieben, mit der Arduino C++ Kanone, auf den 
Tiny zu zielen.
Immerhin ist der MicroCore erheblich Flasheinsparender, als das original 
Arduino Gedönse für die ATMegas.

> Der Sketch verwendet 194 Bytes (18%) des Programmspeicherplatzes.
> Globale Variablen verwenden 0 Bytes (0%)

Nachtrag:
Die Zeile
> PRR = _BV(PRTIM0)|_BV(PRADC);
Könnte man noch irgendwo unterbringen
Weder Timer0 noch der ADC werden in dem Programm benötgigt

von Einer K. (Gast)


Lesenswert?

Keine Hilfe per PM!

Die Operatoren ! |= und &= werden dir in jedem C++ Buch beschrieben.

Tipp:
Ein C Buch hilft dir in der Arduinowelt nur begrenzt weiter.
z.Z. nutzt Arduino den C++11 Standard.
Auch bis C++17 ist konfigurierbar, wenn man ernstlich will


> Aber an welcher Stelle werden die Funktionen des µC,
> die abgeschaltet wurden wieder aktiviert?
Weder Timer0, ADC noch AC werden in deinem Programm benötigt.
Es gibt also keinen Grund diese wieder zu aktivieren.
BOD wird automatisch nach dem Sleep wieder auf din von den Fuses 
bestimmten Wert gesetzt.
Nutze <avr/power.h>, evtl. wirds damit übersichtlicher

> Ist es evtl. so, dass das Ausrufezeichen eine "Negierung" ist,
> also in diesem Fall für LOW steht und kein Ausrufezeichen
> automatisch HIGH bedeutet?
Ja, kann man schon so sehen....
Mir tut es schon fast weh, wenn ich solche Vergleiche sehe (irgendwas == 
true)

Auch wenn digitalRead() in deinem Fall ein uint8_t liefert ist der 
implizite Cast nach bool schon ok.

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.