mikrocontroller.net

Forum: Compiler & IDEs Unaktive Schaltung schlafen lassen


Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
HI,

ich würde meine Schaltung gerne nach einer gewissen unaktiven Zeit in 
den Sleep Modus versetzen. Ich benutze einen ATMEGA32 mit 16 MHZ Takt 
und wollte dies über einen Timer realisieren. Also dachte ich mir ich 
nehme den 16Bit Timer und lasse diesen laufen. Bei einem Overflow wird 
eine volatile Variable hochgezählt und wenn diese den Wert 10 erreicht, 
dann wird der Sleep Modus des Atmel eingeschalten.

Nun das mit dem Sleep Modus klappt nur nach ungefähr 10ms schon ;-(. Ich 
hatte mir das so gedacht.

16 000 000 Hz / (1024 * 65536) = 0,238s

Das heisst, ein Interrupt bei einem 1024 Prescaler sollte alle 0,24s 
eintreffen. Lasse ich die Interruptvariable nun bis 45 zählen, dann 
komme ich ungefähr auf 10s.

((16 000 000 Hz) / (1024 * 65536)) * 45 = 10,73s

Leider geht die Schaltung immer sofort in den Sleep Modus. D.h. irgendwo 
programmiere ich Mist. Genug der Erklärung, hier der Code.
void count_unactive_time(void)
{
   countclock = 0;
   TCNT1 = 0;
   TCCR1A = 0;
   TCCR1B = ((1<<CS12) | (1<<CS10));
   TCCR1B &= ~(1<<CS11);
   
   TIMSK |= (1<<TOIE1);
}

ISR(TIMER1_OVF_vect)
{
   countclock++;
   if(countclock == 45)
   {
      go_to_sleep();
      TIMSK &= ~(1<<TOIE1);
   }
}

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
;-)))) Sry im Betreff sollte "schlafen lassen" nicht "schlagen lassen" 
stehen. Dickes Sry

[Moderator note: ich hab's geändert -- jw.]

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du den Idle Modus verwendest, dann würde ich den µC immer in diesen 
Modus versetzen und periodisch per Timer wieder aufwecken, um 
nachzuschauen ob es was zu tun gibt.

Ansonsten sehe ich in dem Code jetzt eigentlich auch keinen Fehler.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Aufwecken geschieht derzeit über einen Interrupt an INT0

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also er geht nach 5 sek plötzlich aus. Kann nicht wieder eingeschaltet 
werden und die rote LED die an PIN D7 hängt geht an. Das check ich 
überhaupt nicht.

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab doch noch einen Fehler gefunden, und zwar in deiner Rechnung:
Die Frequenz des Timers beträgt 0,238Hz und nicht 0,238s ! Sind sind 
etwa 4,2s.
Der Controller müsste sich also nach 189s schlafen legen.

Autor: Peter P. (bonsaibaum)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo!

bitte poste mal den vollständigen code ... variablendeklaration, 
go_to_sleep-methode, usw ....

kristallkugel ist leider noch aus ...

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also mein Timer geht jetzt. Lag daran, dass ich die interrupt.h in 
dieser c file nicht eingebunden hatte. In meiner go_to_sleep steht 
folgendes
void go_to_sleep(void)
{
   LCDCls();
   LCDWrite("Standbye Mode aktiv");
   set_sleep_mode(SLEEP_MODE_IDLE);
   sleep_mode();
}

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also eigetnlich klappt jetzt alles nur das Aufwecken nicht. Ich will mit 
INT0 aufwecken.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Matthias wrote:

> Ich will mit
> INT0 aufwecken.

Du denkst aber dran, dass auf einem ATmega32 das Aufwecken durch
einen Externinterrupt ausschließlich durch (low-)pegelgesteuerten
Interrupt möglich ist, ja?  Die Varianten mit der Flankensteuerung
brauchen für die Erkennung der Flanke einen laufenden IO clock.

Der Pin-Change-Interrupt der neueren AVRs funktioniert meiner
Erinnerung nach dagegen auch ohne IO clock.  Du könntest also ggf.
einen Upgrade auf einen ATmega324P erwägen.

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Jörg
Er verwendet den Idle Modus, da läuft der IO Takt weiter.

@ Matthias

Poste doch mal deine Initialisierung, vom Interrupt und die 
Interruptroutine, dann kann man dir vielleicht weiterhelfen.
Wie Jörg schon angedeutet hat: Es gibt noch andere Sleep Modi, die 
effektiver sind als der Idle Modus. Der Power Down Modus könnte für dich 
interessant sein, dann wird der AVR aber komplett stillgelegt und kann 
eben nur durch den Leven Interrupt geweckt werden.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das zusammenspiel dieser Funktionen soll das Auswachen und Einschlafen 
gestalten:
//****************************************************************
void count_unactive_time(void)
{
  countclock=0;
  TCNT1 = 0;
  TCCR1A=0; // keine PWM Optionen
  TCCR1B = ((1<<CS12) | (1<<CS10) ); // prescaler 
  TCCR1B &= ~(1<<CS11);      // 1024 => 16MHz/1024 = 1,6 MHz

  TIMSK|=(1<<TOIE1);   // enable timer1 int
}

//****************************************************************
void stop_counting_time(void)
{
  TIMSK &= ~(1<<TOIE1);     // disable timer1 int
  countclock = 0;      // Zähler rücksetzen
  TCNT1 = 0;      // Counterregister rücksetzen
  IN_SLEEP = 0;      // System ist wach
}


//****************************************************************
void camera_go_to_sleep(void)
{
  camera_send_command(SYNC_power_down);
}

//****************************************************************
void atmel_go_to_sleep(void)
{
  LCDCls();
  LCDWrite("Standbye Mode active");
  IN_SLEEP = 1;
  GREEN_OFF();
  RED_OFF();
  MCUCR = 0x83;
  while(IN_SLEEP == 1);
}

//****************************************************************
void camera_system_wake_up(void)
{
  GREEN_ON();
  IN_SLEEP=0;
  while(!camera_send_SYNC());  // Zum Aufwachen zwingen
          // Atmel is bis dahin eh wach 
}

//****************************************************************
ISR(TIMER1_OVF_vect) 
{
  countclock++;
  if(countclock == 4)
  {
    TIMSK &= ~(1<<TOIE1);   // disable timer1 int
    //camera_go_to_sleep();
    atmel_go_to_sleep();
  }
}


  
//****************************************************************
unsigned char volatile DO_PICTURE=0;

//****************************************************************
ISR(INT0_vect)
{
  if(IN_SLEEP)
  {
    LCDCls();
    LCDWrite("Wake UP...");
    MCUCR = 0x03;
    camera_system_wake_up();
  }  
  else
  {
    stop_counting_time();    
  }

  DO_PICTURE = 1;
}

//****************************************************************
void sensor_Init(void)
{
  MCUCR = ((1<<ISC01) | (1<<ISC00));   
  GICR  = (1<<INT0);      // INT0 Interrupt enabled
}

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube ich habe den Fehler: Du setzt den AVR in einem Interrupt in 
den Schlafmodus. Und im Interrupt sind andere Interrupts ausgeschaltet 
-> Kein Externer Interrupt, kein Aufwachen.
Was lernen wir daraus: Nicht alles einfach in den Interrupt paken, 
sondern im Interrupt Flags setzen die in der Main Schleife dann 
abgearbeitet werden.
Daher wird while (IN_SLEEP == 1); auch nie verlassen. Diese Zeile kannst 
du dir sparen, denn wenn der Controller schläft, kann er nicht 
überprüfen ob er schläft.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ich nicht verstehe, wenn ich die Zeile

GREEN_OFF();
  RED_OFF();
  MCUCR = 0x83;

nehme, hört dann der uC ab MCUCR = 0x83; auf und macht an dieser Stelle 
bei einem Interrupt dann weiter oder was macht der im Schlafmodus, wo 
fängt er wieder an ?

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also erstens dass mit den Interrupts im Interrupt war der Hauptfehler 
und du hattest natürlich vollkommen recht.

Zweitens fehlte bei mir ein sleep_cpu(); bzw. ein asm("sleep") dann geht 
das

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Matthias wrote:
> nehme, hört dann der uC ab MCUCR = 0x83; auf und macht an dieser Stelle
> bei einem Interrupt dann weiter oder was macht der im Schlafmodus, wo
> fängt er wieder an ?
Nö. Der hört da gar nicht auf. Das "MCUCR = 0x83;" setzt lediglich das 
Sleep-Enable (und konfiguriert nebenbei den externen Interrupt 0 auf 
"steigende Flanke"). Geschlafen wird erst dann, wenn der Befehl "sleep" 
ausgeführt wird.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Genau das habe ich gerade gesagt ;-) und "für mich" festgestellt

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Matthias wrote:
> Genau das habe ich gerade gesagt ;-) und "für mich" festgestellt
Schön... Und wenn ich vor dem Absenden aktualisiert hätte, hätte ich mir 
das ganze glatt sparen können.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sag auf jeden Fall Danke allen Hilfestellern

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke übrigens, dass du durchaus auch aus einer IRQ heraus den
sleep mode anwerfen kannst (auch wenn ich es unästhetisch finde :).
Das Aufwachen hängt nicht davon ab, ob der Interupt gerade wirklich
in eine ISR gehen kann oder nicht, die CPU fängt trotzdem wieder
an zu arbeiten.  Danach wird die alte ISR zu Ende abgearbeitet, und
gleich nach der Rückkehr aus dieser die ISR für den Externinterrupt.

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Ich denke übrigens, dass du durchaus auch aus einer IRQ heraus den
> sleep mode anwerfen kannst (auch wenn ich es unästhetisch finde :).
> Das Aufwachen hängt nicht davon ab, ob der Interupt gerade wirklich
> in eine ISR gehen kann oder nicht, die CPU fängt trotzdem wieder
> an zu arbeiten.

Sicher ? Ich habe mich das auch gefragt, und nichts dazu im Datenblatt 
gefunden. Dann habe ich mir das überlegt:
Sobald ein Interrupt eintritt, wird automatisch das globale Interrupt 
Enable Flag gelöscht, demzufolge alle Interrupts deaktiviert. Erst beim 
reti (=ret + sei in einem) werden die Interrupts wieder freigeschaltet.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nö, ihr habt Recht.  Die Interrupts müssen global freigeschaltet sein,
damit das Aufwachen funktioniert.

Wieder was dazu gelernt. ;-)

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Doch noch eine kleine Frage zum Abschluss. Wenn ich wie oben beschrieben 
den Sleep Modus durch einen externen Interrupt an INT0 verlasse, wie 
weit kann ich dann den Stromverbrauch meines Atmels senken. Ich würde in 
dieser Hinsicht gerne das absolute Maximum rausholen.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit nem externen Level-Interrupt kannst Du ihn aus jedem beliebigen 
Sleep-Modus zurückholen.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jo so lese ich das auch nur leider wacht der so gar nicht auf ;-(

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sicher, dass Du den Interrupt als Level-Interrupt konfiguriert hast? 
Oben war er nämlich noch auf "steigende Flanke" gesetzt, wenn ich mich 
recht erinnere...

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Außerdem kannst du ihn auch mit einem flankengesteuerten Interrupt an
INT2 (aber nur an diesem) aus dem Sleep befördern:

`` ... Low level interrupts on INT0/INT1 and the edge interrupt on
INT2 are detected asynchronously. This implies that these interrupts
can be used for waking the part also from sleep modes other than Idle
mode. The I/O clock is halted in all sleep modes except Idle mode.''

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
You are the Best :-)
Genau das war es. Ich habe die angewohnheit nicht zwischen den Zeilen zu 
lesen und deshalb solche die wie "LEVEL" Interrupt mal schnell zu 
überlesen. Jetzt geht es einwandfrei und ich sag mal wieder: Danke dir !

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bzw. Euch

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Krieg meine Schaltung mit dem Power-down Mode jetzt von 162 mA auf 68 
mA. Mehr geht wahrscheinlich am Atmel selbst nicht oder ?

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Würde die ganze Schaltung nämlich gerne über eine Solarzelle betreiben, 
habe allerdings keine Ahnung von Solarzellen. Vielleicht weiss jemand ob 
man bei so einem Nennstrom eine Versorgung über z.B. 2 Batterien mit 
Solarzellenanbindung hinkriegt. Kennt ihr da Projekte ?

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
68 mA ist viel zu viel. Das liegt nicht am Atmel sondern an dem 
drumherum, wie spannungsregler, pull-up widerstände ...
vielleicht solltest du deine schaltung auch mal posten

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für stromsparenden Betrieb solltest du dir auch einen moderneren
Prozessor zulegen.  Den ATmega324P hatte ich ja schon einmal genannt.
Der Grundverbrauch im aktiven Betrieb würde dadurch von 23 mA auf
13 mA sinken.  Im Powerdown sinkt der Strom von 1 µA auf 0,6 µA, das
wirst du aber kaum merken. ;-)

Der Reset deiner Schaltung braucht vermutlich tatsächlich ein
Redesign...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Matthias (Gast)

>Krieg meine Schaltung mit dem Power-down Mode jetzt von 162 mA auf 68
>mA. Mehr geht wahrscheinlich am Atmel selbst nicht oder ?

???
Der AVR braucht im tiefsten Sleep Modus (Power down) 1-2uA 
(MIKROAmpere).

MFG
Falk

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja ja ja :-) is ja schon gut ich weiss das es nicht der Atmel ist. Also 
zu meiner Schaltung:

Bisher noch auf der Platine jedoch bald draussen sind:

1 x MAX232
1 x poti 150 Ohm

Dazu kommt allerdings ein PIR Sensor der jedoch auch so gut wie nix 
ziehen soll. Ich frag mich nur ob der LM1086 3,3 soviel zieht. Das kann 
ich mir nicht vorstellen und Pull-ups verwende ich keine.

Ich habe noch eine SD-Karte und eine UART Camera dranhängen. Die Cam 
versetze ich in den Sleep Modus und dann zieht die nur noch 100 uA. Alsp 
geh ich jetzt gleich nochmal an den Lötkolben und bau oben genannte 
Teile weg, da sie keinen nutzen haben (ist ja nur ne Testplatine).

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ausserdem werde ich die L Version umsteigen, dass wird zusätzlich 
nocheinmal was einsparen.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein 150 Ohm Poti? Wofür das und wie verschaltet? An 5V zieht das ja 
schon I = U/R = 5000mV/150Ohm = 33mA

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So nu bin ich bei ca. 27 mA was immer noch zu viel ist, allerdings sieht 
es auf der Testplatine echt wüst aus und bevor ich da weitermache, mach 
ich ne neue mit dem MEGA(L).

Meine letzte Frage wäre nur noch: Kennt jemand eine Beschaltung, wo ein 
Akku per Solarzelle geladen wird, jedoch die Schaltung sich gleichzeitig 
von diesem versorgt. Ich bin auf dem Gebiet vollkommen unerfahren und 
würde mich mit Ladeschaltungen von Akkus über Solarzellen gerne mal 
informieren.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Müsste doch über einen Akku Laderegler z.B. bei Conrad leicht gehen ?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.