Forum: Compiler & IDEs Unaktive Schaltung schlafen lassen


von Matthias (Gast)


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.
1
void count_unactive_time(void)
2
{
3
   countclock = 0;
4
   TCNT1 = 0;
5
   TCCR1A = 0;
6
   TCCR1B = ((1<<CS12) | (1<<CS10));
7
   TCCR1B &= ~(1<<CS11);
8
   
9
   TIMSK |= (1<<TOIE1);
10
}
11
12
ISR(TIMER1_OVF_vect)
13
{
14
   countclock++;
15
   if(countclock == 45)
16
   {
17
      go_to_sleep();
18
      TIMSK &= ~(1<<TOIE1);
19
   }
20
}

von Matthias (Gast)


Lesenswert?

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

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

von Benedikt K. (benedikt)


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.

von Matthias (Gast)


Lesenswert?

Das Aufwecken geschieht derzeit über einen Interrupt an INT0

von Matthias (Gast)


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.

von Benedikt K. (benedikt)


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.

von Peter P. (bonsaibaum)


Lesenswert?

hallo!

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

kristallkugel ist leider noch aus ...

von Matthias (Gast)


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
1
void go_to_sleep(void)
2
{
3
   LCDCls();
4
   LCDWrite("Standbye Mode aktiv");
5
   set_sleep_mode(SLEEP_MODE_IDLE);
6
   sleep_mode();
7
}

von Matthias (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Benedikt K. (benedikt)


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.

von Matthias (Gast)


Lesenswert?

Das zusammenspiel dieser Funktionen soll das Auswachen und Einschlafen 
gestalten:
1
//****************************************************************
2
void count_unactive_time(void)
3
{
4
  countclock=0;
5
  TCNT1 = 0;
6
  TCCR1A=0; // keine PWM Optionen
7
  TCCR1B = ((1<<CS12) | (1<<CS10) ); // prescaler 
8
  TCCR1B &= ~(1<<CS11);      // 1024 => 16MHz/1024 = 1,6 MHz
9
10
  TIMSK|=(1<<TOIE1);   // enable timer1 int
11
}
12
13
//****************************************************************
14
void stop_counting_time(void)
15
{
16
  TIMSK &= ~(1<<TOIE1);     // disable timer1 int
17
  countclock = 0;      // Zähler rücksetzen
18
  TCNT1 = 0;      // Counterregister rücksetzen
19
  IN_SLEEP = 0;      // System ist wach
20
}
21
22
23
//****************************************************************
24
void camera_go_to_sleep(void)
25
{
26
  camera_send_command(SYNC_power_down);
27
}
28
29
//****************************************************************
30
void atmel_go_to_sleep(void)
31
{
32
  LCDCls();
33
  LCDWrite("Standbye Mode active");
34
  IN_SLEEP = 1;
35
  GREEN_OFF();
36
  RED_OFF();
37
  MCUCR = 0x83;
38
  while(IN_SLEEP == 1);
39
}
40
41
//****************************************************************
42
void camera_system_wake_up(void)
43
{
44
  GREEN_ON();
45
  IN_SLEEP=0;
46
  while(!camera_send_SYNC());  // Zum Aufwachen zwingen
47
          // Atmel is bis dahin eh wach 
48
}
49
50
//****************************************************************
51
ISR(TIMER1_OVF_vect) 
52
{
53
  countclock++;
54
  if(countclock == 4)
55
  {
56
    TIMSK &= ~(1<<TOIE1);   // disable timer1 int
57
    //camera_go_to_sleep();
58
    atmel_go_to_sleep();
59
  }
60
}
61
62
63
  
64
//****************************************************************
65
unsigned char volatile DO_PICTURE=0;
66
67
//****************************************************************
68
ISR(INT0_vect)
69
{
70
  if(IN_SLEEP)
71
  {
72
    LCDCls();
73
    LCDWrite("Wake UP...");
74
    MCUCR = 0x03;
75
    camera_system_wake_up();
76
  }  
77
  else
78
  {
79
    stop_counting_time();    
80
  }
81
82
  DO_PICTURE = 1;
83
}
84
85
//****************************************************************
86
void sensor_Init(void)
87
{
88
  MCUCR = ((1<<ISC01) | (1<<ISC00));   
89
  GICR  = (1<<INT0);      // INT0 Interrupt enabled
90
}

von Benedikt K. (benedikt)


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.

von Matthias (Gast)


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 ?

von Matthias (Gast)


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

von Johannes M. (johnny-m)


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.

von Matthias (Gast)


Lesenswert?

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

von Johannes M. (johnny-m)


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.

von Matthias (Gast)


Lesenswert?

Ich sag auf jeden Fall Danke allen Hilfestellern

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Benedikt K. (benedikt)


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

Wieder was dazu gelernt. ;-)

von Matthias (Gast)


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.

von Johannes M. (johnny-m)


Lesenswert?

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

von Matthias (Gast)


Lesenswert?

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

von Johannes M. (johnny-m)


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...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.''

von Matthias (Gast)


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 !

von Matthias (Gast)


Lesenswert?

Bzw. Euch

von Matthias (Gast)


Lesenswert?

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

von Matthias (Gast)


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 ?

von Werner (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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...

von Falk B. (falk)


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

von Matthias (Gast)


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).

von Matthias (Gast)


Lesenswert?

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

von Simon K. (simon) Benutzerseite


Lesenswert?

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

von Matthias (Gast)


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.

von Matthias (Gast)


Lesenswert?

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

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.