Hallo Leute,
ich würde gerne einen an meinem ATmega32 angeschlossenen RFM12B in den
sleep mode bringen und anschließend auch den ATmega32 schlafen lassen.
Wenn dann der wakeup Timer des RFM12B anschlägt, sollen beide wieder
aufwachen, kurz etwas machen und wieder schlafen.
Ich habe nun schon etliche Beispiele gefunden, aber irgendwie will da
nichts so richtig laufen.
Meine Funktion um schlafen zu gehen:
1
2
3
// Function to set the microcontroller to sleep to save energy and wait for request for temperature
4
voidgoToSleep(void)
5
{
6
// Disable AC
7
ACSR=(1<<ADC);
8
// Set RFM12B to sleep with wake-up timer
9
RFM12_sleep();
10
// Select power down sleep mode
11
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
12
// Go to sleep
13
sleep_mode();
14
}
Die Funktion um den wakeup Timer zu aktivieren (aus einem
Forumsbeitrag):
1
voidRFM12_sleep(void)
2
{
3
RF12_WRT_CMD(0xE000|0x0A00|2);
4
RF12_WRT_CMD(0x8201);
5
RF12_WRT_CMD(0x8203);
6
}
Und die Initialisierung des INT0-Interrupts:
1
// Enable INT0
2
GICR|=(1<<INT0);
3
MCUCR|=(1<<ISC01);
4
MCUCR&=~(1<<ISC00);
Danach dann noch sei().
Könnte mir das mal einer von euch vernünftig erklären. Also wie ich was
setzen muss und was was bewirkt. Aus dem Datenblatt werde ich da auch
nicht so richtig schlau.
"Only an External Reset, a Watchdog Reset, a Brown-out Reset, a Two-wire
Serial Interface address match interrupt, an External level interrupt on
INT0 or INT1, or an External interrupt on INT2 can wake up the MCU."
Flankenerkennung an INT0 und INT1 geht wohl nicht.
ISC01 und ISC00 müssen 0 sein, damit der AVR über INT0 aufwachen kann.
Sind die Interrupts korrekt aktiviert und vor allem auch per sei()
eingeschaltet?
Bei mir läuft folgende Sequenz erfolgreich, um einen ATtiny85 mit RFM12
schlafen zu legen:
1
// Pin change interrupt einschalten
2
PCMSK|=1<<PCINT4;
3
GIMSK|=1<<PCIE;
4
5
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
6
7
// Alles am RFM ausschalten
8
rfm_cmd(0x8201);
9
10
// Mode einstellen (868 MHz)
11
rfm_cmd(0x8067);
12
13
// nIRQ auf 'high' zwingen
14
while(!(NIRQ_PIN&(1<<NIRQ))){
15
if(rfm_cmd(0x0000);&(1<<15)){
16
rfm_cmd(0xB8AA);
17
rfm_cmd(0xB000);
18
}
19
}
20
21
rfm_cmd(0xEB01);// Wake-up in 2,048 Sekunden
22
rfm_cmd(0x8201);// Alles aus
23
rfm_cmd(0x8203);// Wake-up ein
24
25
// Interrupt-Flag löschen
26
while(GIFR&(1<<PCIF)){
27
GIFR=1<<PCIF;
28
}
29
30
sleep_enable();
31
sleep_bod_disable();
32
sei();
33
sleep_cpu();
34
35
// Jetzt sind wir im Sleep mode und warten auf den Interrupt
Jens K. schrieb:> Was bewirkt der Befehl " Mode einstellen ( 868MHz )"?
Man deaktiviert das Tx-Register (Bit 7), indem man Bit 7 auf 0 setzt -
das ist genau das, was Stefan gemeint hat.
Jetzt aber noch eine andere Frage: Wenn ich den ATMEGA32 und den RFM12B
schlafen schicke (30s), dann werden immernoch 5,5mA gezogen. Ich habe
mal nur den ATMEGA32 laufen lassen (mit dem kompletten Programm) und
musste feststellen, dass dieser im Sleep Mode nicht unter 5mA geht. Kann
ich da noch was einsparen? AC ist aus, SPI auch, interne pullups
deaktiviert.
Wie versorgst du die Schaltung? Direkt über Batterien oder per Regler?
Viele Spannungsregler benötigen eine Mindestlast, welche einen Strom im
Bereich dieser 5 mA zieht.
In meinem Fall verwende ich den LP2951, dessen Ruhestrom ist deutlich
niedriger und ich messe etwa 120 µA im Deep-Sleep-Modus bei meinen
Messstationen mit ATtiny85, RFM12 und DHT22.
Ich verwende einen LM317. Aber wie gesagt, wenn ich nur den ATMEGA32 aus
der Schaltung nehme, das Programm drauf spiele und ihn aus einem
Netzteil direkt mit 3,3V versorge, dann zeigt mir das Messgerät zwischen
Netzteil und VCC des uC trotzdem 5mA an.
Jens K. schrieb:> Jetzt aber noch eine andere Frage: Wenn ich den ATMEGA32 und den RFM12B> schlafen schicke (30s), dann werden immernoch 5,5mA gezogen. Ich habe> mal nur den ATMEGA32 laufen lassen (mit dem kompletten Programm) und> musste feststellen, dass dieser im Sleep Mode nicht unter 5mA geht. Kann> ich da noch was einsparen?
Ganz sicher, aber schon die Analyse erfordert zwingend das vollständige
Verständnis der kompletten Außenbeschaltung des Controllers,
einschließlich der Stromversorgung.
D.h.: Für reine Nachbauer von Schaltungen ist hier schon Ende der
Fahnenstange...
Bei der Behebung der Mißstände ist dann zusätzlich zu den
Elektronikkenntnissen meist auch noch umfassende Kenntnis des
Datenblatts des Controllers und der genauen Funktion der verwendeten
Softwaremodule erforderlich, um entscheiden zu können, ob ein Problem
per Softwareänderung gelöst werden kann, oder ob die Hardware geändert
werden muß.
D.h.: für die meisten C-ler (die C nur benutzen, weil es dafür so viele
Vorlagen für's Copy&Paste gibt) ist dann spätestens hier Ende der
Fahnenstange...
Naja, und für den kleine Rest, der die Fahenstange überfliegt, ist so
eine Optimierung immerhin noch viel Arbeit. Insbesondere eine, die eine
vollständige Dokumentation von Hard- und Software als unbedingte
Voraussetzung erfordert. Mindestens vollständiger Schaltplan und
vollständiger Quelltext sind das absolute Minimum, was hier nötig ist,
ansonsten braucht man erst garnicht anfangen...
Jens K. schrieb:> Ich verwende einen LM317.
Der gehört zur zitierten Gattung, welche eine Mindestlast (Minimum Load
Current) im Bereich von 5mA ausweisen.
Jens K. schrieb:> Aber wie gesagt, wenn ich nur den ATMEGA32 aus> der Schaltung nehme, das Programm drauf spiele und ihn aus einem> Netzteil direkt mit 3,3V versorge, dann zeigt mir das Messgerät zwischen> Netzteil und VCC des uC trotzdem 5mA an.
Wie ist der ATMEGA32 in diesem Szenario genau beschaltet? Sind sowohl
VCC als auch AVCC verbunden, ebenso alle GNDs und was ist mit dem
Reset-Pin?
Zur Beschaltung: VCC und beide GND sind verbunden AVCC nicht. AVCC muss
doch auch nur für den ADC beschaltet werden.
Ich dachte eher daran, ob es interne Module gibt, die noch weiter laufen
und welche man zum Stromsparen abschalten könnte. Es ist mein erstes,
bei dem ich mit Sleep arbeite um Strom zu sparen, daher kenne ich mich
da noch nicht so aus und wäre dankbar für ein paar Tipps ;-)
Dazu steht einiges ab Seite 34 im Datenblatt. Unter anderem: Der
Analog-Digital-Converter sollte vor dem Aktivieren des Sleep-Modes
ausgeschaltet werden (ADEN-Bit in ACSRA auf 0).
Auch der Hinweis von N.G. ist richtig. Du meinst bestimmt das ACD-Bit
(Analog Comparator Disable), welches du auf 1 setzen willst, ADC ist das
16-bit-Pseudo-Register mit den ADC-Ergebnissen.
Okay, danke für den Tipp. Ich habe jetzt folgenden Code zum abschalten
der Peripherie geschrieben:
1
voiddisable_Peripherals(void)
2
{
3
// Disable pull-up on INT0
4
PORTD&=~(1<<PD2);
5
6
// SPI-Ports as inputs
7
DDRB&=~((1<<PB4)|(1<<PB5)|(1<<PB7));
8
9
// Disable SPI
10
SPCR&=~(1<<SPE);
11
12
// Disable ADC
13
ACSR&=~(1<<ADEN);
14
}
Die Fuses für Brown-Out Detector und JTAG sind ebenfalls deaktiviert.
Leider gibt es keine Änderung.
Nochmal genauer zur aktuellen Beschaltung:
- VCC mit 100nF an VCC
- GNDs mit GND verbunden
- 8MHz Quarz mit 22pF Kondensatoren am entsprechenden Eingang
- 10k nach VCC und 100nF nach GND an Reset
Ansonsten ist nichts mit dem Mikrocontroller verbunden. Versorgt wird
er, wie bereits erwähnt, aus einem Netzteil mit 3,3V und ich messe den
Strom zwischen dem Netzteil und dem Spannungseingang des Steckboards,
auf welchem der Mikrocontroller aktuell steckt.
Jens K. schrieb:> Okay, danke für den Tipp. Ich habe jetzt folgenden Code zum abschalten> der Peripherie geschrieben:>>
1
>voiddisable_Peripherals(void)
2
>{
3
>// Disable pull-up on INT0
4
>PORTD&=~(1<<PD2);
5
>
6
>// SPI-Ports as inputs
7
>DDRB&=~((1<<PB4)|(1<<PB5)|(1<<PB7));
8
>
9
>// Disable SPI
10
>SPCR&=~(1<<SPE);
11
>
12
>// Disable ADC
13
>ACSR&=~(1<<ADEN);
14
>}
15
>
>> Die Fuses für Brown-Out Detector und JTAG sind ebenfalls deaktiviert.> Leider gibt es keine Änderung.>> Nochmal genauer zur aktuellen Beschaltung:> - VCC mit 100nF an VCC> - GNDs mit GND verbunden> - 8MHz Quarz mit 22pF Kondensatoren am entsprechenden Eingang> - 10k nach VCC und 100nF nach GND an Reset>> Ansonsten ist nichts mit dem Mikrocontroller verbunden. Versorgt wird> er, wie bereits erwähnt, aus einem Netzteil mit 3,3V und ich messe den> Strom zwischen dem Netzteil und dem Spannungseingang des Steckboards,> auf welchem der Mikrocontroller aktuell steckt.
In ACSR gibt es kein Bit ADEN. ACSR enthält Einstellungen für den
Komparator. Den schaltet man ab mit:
1
ACSR|=(1<<ACD);
ADEN schaltet den ADC ein und aus und befindet sich im Register ADCSRA
(das D hatte ich oben vergessen, daher wohl die Verwirrung!). Hier ist
die Ausschalt-Einstellung:
1
ADCSRA&=~(1<<ADEN);
Da ACD und ADEN beide nur Makros sind, die gleichbedeutend für die Zahl
7 stehen, und man den Komparator durch das Setzen eines Bits, den ADC
aber durch das Löschen eines Bits ausschaltet, bewirkt deine bisherige
Einstellung genau das Gegenteil des gewünschten Effekts, nämlich dass
der Komparator eingeschaltet wird/bleibt, während für den ADC keine
Änderung vorgenommen wird.
AVCC sollte man immer anschließen, damit wird nicht nur der ADC
gespeist, sondern grundsätzlich PORTA (Datenblatt S. 5 unten). Hier
ebenfalls einen 100nF-Kondensator nahe am Pin vorsehen, genauso von AREF
(bleibt ansonsten unbeschaltet) nach GND.
Den Pullup am Interrupt-Pin solltest du in deiner Testschaltung nicht
deaktivieren - oder hast du irgendeine Quelle bzw. einen externen Pullup
dran hängen, um den Pin fest auf einem bestimmten Pegel zu halten? Der
Zustand eines offenen Eingangs ist nicht definiert und irgendwelche im
Raum befindlichen Felder können ihn dann nach Herzenslust zwischen den
verschiedenen Potentialen her und her wackeln lassen, was zum Aufwachen
führen kann.
Figure 150 im Datenblatt zeigt, dass der Controller bei 8 MHz und 3,3 V
im aktiven Zustand in etwa die von dir gemessenen 5 mA ziehen sollte. Es
sieht für mich also ganz so aus, als ob er nicht wirklich schlafen geht.
Im Power Down Mode liegt die Stromaufnahme typischerweise unter 1 µA
(Figure 160) also Faktor 5000 darunter.
Okay, ich habe nun mal ein Programm geschrieben, welches eine LED
blinken lässt und den ATmega32 dann in den Sleep Mode schickt und siehe
da... 15µA. Es scheint also irgendein Fehler im Programm zu sein, denn
den Aufbau habe ich beibehalten.
Jens K. schrieb:> Okay, ich habe nun mal ein Programm geschrieben, welches eine LED> blinken lässt und den ATmega32 dann in den Sleep Mode schickt und siehe> da... 15µA. Es scheint also irgendein Fehler im Programm zu sein, denn> den Aufbau habe ich beibehalten.
Das ist doch mal ein schönes Zwischenresultat. Dann lade doch mal deinen
aktuellen Programmcode hoch, irgendwo in der Konfiguration wird sich der
Bug schon versteckt haben.
Ja, und ich habe ihn gefunden. Hatte den Sleep Mode vom RFM12B falsch
eingestellt. Als zweite Fehlerursache bin ich nun tatsächlich auf den
Spannungsregler gestoßen (also bei der richtigen Schaltung, nicht auf
dem Steckbrett). Auf dem Steckbrett, ohne Spannungsregler, komme ich
nämlich auch auf 15µA und bei meinem Aufbau immer noch nur auf 5mA. Gehe
ich mit der Spannung runter, also statt 9V mal auf 4V, so sinkt der
Strom auf 3mA. Ich denke ich werde das mal mit dem Spannungsregler
versuchen, den du vorgeschlagen hattest