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.
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.
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
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); } }
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.
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
(_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).
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
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
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.
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.
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.
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"
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
> 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.
@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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.