Forum: Mikrocontroller und Digitale Elektronik Problem sleep Mode - Attiny25/45/85


von Michi M. (mutzmutz)


Lesenswert?

Hallo zusammen,

ich baue mir gerade eine art led beleuchtung, akkubetrieben.
das gerät soll nur mit einem taster bedient werden, also gerät ein - und 
ausschalten, modus umschalten (verschiedene helligkeiten und modis der 
leds).
zum einschalten des gerätes drücke ich den taster ca. 3sek, dann wird 
immer ca 0.5 sek. gedrückt, um den led modus zu wechseln. ausschalten 
des gerätes wieder durch drücken des tasters ca 3sek. eigentlich 
funktioniert das ganze auch ziemlich gut, nur wenn ich abgeschaltet habe 
(also eigentlich im power down modus) säufft das teil immernoch 0.78 mA 
!

ich finde den fehler nicht, also an der HW insgesammt sollte es nicht 
liegen, ich habe auch schon eine software draufgeladen wo er sich nach 
zwei dreimal leds blinken korrekt in den schlafmodus gebracht hat, 
verbrauch 0.04 mA.

hoffe kann jemand mal ein auge auf den codeauschnitt werfen :
1
/****************** INIT *************************/
2
void init(){
3
   DDRB = 0b0000001;          // PORTB, OC0A für PWM output
4
  ACSR = 0x80;                // Analogcomparator ausschalten
5
}
6
7
void init_timer(){
8
  TCCR0A |= ((1<<WGM01) | (1<<WGM00));             // fast PWM Mode
9
  TCCR0A |= (1<<COM0A1);                           // clear OC0A on compare Match, set OC0A at BOTTOM (non inverting Mode)
10
  TCCR0B |=( (0<<CS02) | (1<<CS01) |(0<<CS00) ) ;   // set prescaler to 256
11
  OCR0A=0;                                          // set initial value of OCR0A
12
  TCNT0 =0;                                         // reset timer register
13
  TIMSK |= (1<<OCIE0A);                             // enable  timer output compare match
14
  TIMSK |= (1<<TOIE0);                              // overflow interrupt enable
15
  sei();
16
17
}
18
/****************** INIT END**********************/
19
20
/****************** MAIN **********************/
21
int main(void)
22
{
23
    init();
24
  init_timer();
25
26
   while(1){
27
     
28
  if (sw==0){ // sw = 0 wenn taster ca.3 sek gedrückt -> sleep mode
29
30
    GIMSK |= (1 << INT0);    // externen Interrupt freigeben
31
    OCR0A=0;                // anzeige
32
    PRR = 1<<PRUSI;        // power reduce
33
    PRR = 1<<PRADC;        // power reduce , macht ca 0.04 mA
34
35
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
36
    MCUCR = ((0<<ISC01) | (1<<ISC00));       // pin change interrupt enable
37
      sleep_mode();                   // in den Schlafmodus wechseln
38
     OCR0A=0;// hier wachen wir wieder auf
39
        
40
41
  }else{}
42
43
44
  switch(choose){ // Ausfürhungen der verschiedenen Modis
45
46
    case 0: // Helligkeit 0 % 
47
    OCR0A=0;
48
    break;
49
50
    case 1: // Helligkeit stufe 1
51
    OCR0A=10;//(255-(2+1/5)*nLed)/100*30;
52
     break;
53
  
54
    case 2:  // Helligkeit stufe 2
55
    OCR0A=50;//(255-(2+1/5)*nLed)/100*60;
56
    break;
57
    
58
    case 3: // Helligkeit stufe 3
59
60
    OCR0A=255;//-(2+1/5)*nLed;
61
    break;
62
63
64
   }//end switch
65
   }// end for
66
  
67
}

von Avr N. (balze)


Lesenswert?

Hallo Michi,

mir fallen folgende Dinge ein:

- sicherstellen, dass der Brown-out detector abgestellt ist (fuses)
- sicherstellen, dass der analog comperator und der ADC aus sind
   -> interne Spannungsreferenz ist aus.
- sicherstellen, dass der watchdog aus ist

- die Beschalteung des Tasters und die Konfiguration des Pins pruefen.
  -> Ist der interne Pull-up fuer diesen Pin aktiviert? -> Strombedarf

MfG,

Balze aka AVR Noob

von Peter D. (peda)


Lesenswert?

- Interrupt Handler fehlt

- vor Enablen Flag löschen


Peter

von Michi M. (mutzmutz)


Lesenswert?

> - sicherstellen, dass der Brown-out detector abgestellt ist (fuses)
ist abgeschaltet
> - sicherstellen, dass der analog comperator und der ADC aus sind
>    -> interne Spannungsreferenz ist aus.
> - sicherstellen, dass der watchdog aus ist
ebenfalls aus
> - die Beschalteung des Tasters und die Konfiguration des Pins pruefen.
habe ein pull down am INT0 eingang, taster auf VCC
>   -> Ist der interne Pull-up fuer diesen Pin aktiviert? -> Strombedarf
wie meinst du das ?

von Michi M. (mutzmutz)


Lesenswert?

Peter Dannegger schrieb:
> - Interrupt Handler fehlt
ist sicherlich nicht optimal geschrieben :)
1
/***********Interrupt Taster******************/
2
3
ISR(INT0_vect)                 // Interrupt Vector
4
{
5
   long_delay(50);           // Entprellung vom Drücken
6
   while((PINB & (1<<PINB2)) ){ 
7
       counter++;_delay_ms(10);
8
    if((counter>200) & (sw==0)){OCR0A=30;choose=1;} // Taster länger 3s gedrückt UND wird der uP gerade geweckt ?  
9
    
10
    else if((counter>200) & (sw==1)){OCR0A=0;_delay_ms(1);}// Taster länger 3s gedrückt UND wird der uP gerade abgeschaltet ?
11
    }//end while
12
    if(counter>200){  // Wird der Taster länger 3sek gedrückt wird eine 
13
      sw = !sw;    // Variable getoggelt damit man weiss ob der uP das nächste mal ein oder ausgeschaltet wird
14
      choose=1;    // beim starten mit Modus 1 beginnen, damit man sieht das die Elektronik läuft
15
      if(sw==0){ }else{ }
16
    }else if(counter>10){choose++;if(choose>7){choose=1;}else{}}else{}// Taster ca. 0.5 sek gedrückt für Moduswechsel ?
17
        
18
  counter=0;  // zähler zurücksetzten
19
  long_delay(10); // 
20
}//end ISR
21
/***********Interrupt Taster End******************/
22
 
23
/***********Interrupt Timer **********************/
24
ISR(TIMER0_OVF_vect){
25
  if(choose==4 | choose==5 ){// fade Modus?
26
    if(up==TRUE){           // aufwärtszähler ?
27
         tmp++;
28
      for(t_up;t_up>2;t_up--){}; // verzögerung
29
      OCR0A =  pgm_read_word(pwmtable_8E+tmp);
30
        //if(tmp>=253){OCR0A=255-(2+1/5)*nLed;
31
        if(tmp>=(255-(2+1/5)*nLed)){
32
          up=FALSE;
33
        }
34
     }else{  
35
         tmp--;
36
       for(t_down;t_down>2;t_down--){}; // verzögerung
37
           OCR0A = pgm_read_word(pwmtable_8E+tmp);
38
           if(tmp<65){
39
        for(t_dark;t_dark>2;t_dark--){};
40
      up=TRUE;
41
        }
42
      }
43
    }//end if
44
  else{}  
45
}//end ISR
46
47
ISR(TIMER0_COMPA_vect){   // leere ISR, muss dastehen, ansonsten funktioniert Globale Variable nicht 
48
}//end ISR
49
/***********Interrupt Timer End*******************/

> - vor Enablen Flag löschen
 welches Flag meinst du ??

von Michael S. (Gast)


Lesenswert?

Hallo,

>    PRR = 1<<PRUSI;        // power reduce
>    PRR = 1<<PRADC;        // power reduce , macht ca 0.04 mA

Die zweite Zeile macht die erste Zeile überflüssig.
Es sollte heißen:

PRR = (1<<PRUSI | 1<<PRADC);

Ausserdem gibt es noch weitere Module, die vermutlich nicht benötigt
werden:

- Timer1, Timer2 etc (siehe Register PRR)
- Analog Comparator Disable (siehe Analog Comparator)

Zum Hinweis von Peter Danegger:
- siehe Stichwort EMPTY_INTERRUPT()

Michael S.

von Michi M. (mutzmutz)


Lesenswert?

>>    PRR = 1<<PRUSI;        // power reduce
>>    PRR = 1<<PRADC;        // power reduce , macht ca 0.04 mA
>
> Die zweite Zeile macht die erste Zeile überflüssig.
> Es sollte heißen:
>
> PRR = (1<<PRUSI | 1<<PRADC);
 danke

> Zum Hinweis von Peter Danegger:
> - siehe Stichwort EMPTY_INTERRUPT()
ich glaube ich versteh nicht ganz, was ich mit dem machen soll. hab ich 
noch nie verwendet. muss ich die leere isr so angeben :
1
#define EMPTY_INTERRUPT (  TIMER0_COMPA_vect);
oder wie soll ich das verstehen ?

von Avr N. (balze)


Lesenswert?

Michael S. schrieb:
>>    PRR = 1<<PRUSI;        // power reduce
>>    PRR = 1<<PRADC;        // power reduce , macht ca 0.04 mA
>
> Die zweite Zeile macht die erste Zeile überflüssig.
> Es sollte heißen:
>
> PRR = (1<<PRUSI | 1<<PRADC);

Wie blind man manchmal ist.

:)

MfG,

Balze aka AVR Noob

von Michi M. (mutzmutz)


Lesenswert?

also hab jetzt nochmal wirklich alle dinge ausgestellt die nicht 
gebraucht werden, nun habe ich einen verbrauch von 0.7mA.

es muss doch noch irgendetwas falsch eingestellt sein... dass der soviel 
strom braucht ?

von tom (Gast)


Lesenswert?

schaltplan ???

von Thomas E. (thomase)


Lesenswert?

Michi M. schrieb:
> nun habe ich einen verbrauch von 0.7mA.

Benutzt du einen Debugger?
Wenn Debugwire aktiviert ist, ist der hohe Stromverbrauch normal!


Michi M. schrieb:
> #define EMPTY_INTERRUPT (  TIMER0_COMPA_vect);
> oder wie soll ich das verstehen ?

Ohne "#define"

EMPTY_INTERRUPT (  TIMER0_COMPA_vect);


mfg.

von Peter D. (peda)


Lesenswert?

So als Tip, das Vermanschen von Funktion und Sleep ist sehr aufwendig 
und unübersichtlich (wie man sieht).
Mache erstmal nur die Funktion.
Und erst, wenn alles richtig funktioniert, baut man das Sleep ein.


Michi M. schrieb:
> ist sicherlich nicht optimal geschrieben :)

Das kann ich nur zustimmen, ich sehe da nicht durch.
Es gibt fertige Codebeispiele fürs Entprellen mit kurz/lang Erkennung, 
die keine Wünsche offen lassen.

Besser geht das Sleep mit dem Pin-Change-Interrupt.
Der Level-Interrupt ist tricky (Schlafen erst nach Loslassen möglich).

Ob man im Sleep ist, kann man leicht mit einer LED debuggen, die an 
einem PWM-Ausgang sitzt auf etwa 20%. Glimmt sie, ist die CPU aktiv.
Leuchtet sie hell oder ist aus, ist man im Sleep.


Peter

von Michi M. (mutzmutz)


Angehängte Dateien:

Lesenswert?

> Benutzt du einen Debugger?
> Wenn Debugwire aktiviert ist, ist der hohe Stromverbrauch normal!

nein ist nicht programmiert


> Michi M. schrieb:
>> #define EMPTY_INTERRUPT (  TIMER0_COMPA_vect);
>> oder wie soll ich das verstehen ?
>
> Ohne "#define"
>
> EMPTY_INTERRUPT (  TIMER0_COMPA_vect);

ok danke, aber warum genau sollte man das machen ?

>Mache erstmal nur die Funktion.
>Und erst, wenn alles richtig funktioniert, baut man das Sleep ein.

es funktioniert alles, ein - und ausschalten, modis durchschalten, alles 
wunderbar, nur eben im sleep mode braucht er zuviel strom

>Ob man im Sleep ist, kann man leicht mit einer LED debuggen, die an
>einem PWM-Ausgang sitzt auf etwa 20%. Glimmt sie, ist die CPU aktiv.
>Leuchtet sie hell oder ist aus, ist man im Sleep.

ich habe soeben den PB0 / OC0A Ausgang im sleep mode mit einem oszi 
gemessen, komischerweise spuckt der im 2ms Takt jeweils 8us lange, 4 V 
signale aus... was läuft denn da schief :) ?

von Thomas E. (thomase)


Lesenswert?

Michi M. schrieb:
>> EMPTY_INTERRUPT (  TIMER0_COMPA_vect);
> ok danke, aber warum genau sollte man das machen ?

Weil es schneller geht als

ISR (TIMER0_COMPA_vect){}

Beim EMPTY_INTERRUPT wird direkt auf den Interruptvektor ein return 
gesetzt. Eine Funktion mit den ganzen Pushs und Pops, wird gar nicht 
erst aufgerufen.


Michi M. schrieb:
> ich habe soeben den PB0 / OC0A Ausgang im sleep mode mit einem oszi
> gemessen, komischerweise spuckt der im 2ms Takt jeweils 8us lange, 4 V
> signale aus... was läuft denn da schief :) ?

Sieht nach Reset aus. Sicher, daß der Watchdog(Fuse) aus ist?

mfg.

von Peter D. (peda)


Lesenswert?

Thomas Eckmann schrieb:
> Weil es schneller geht als
>
> ISR (TIMER0_COMPA_vect){}

Noch schneller geht, den Interrupt garnicht erst zu enablen.


Peter

von Stone (Gast)


Lesenswert?

Ist der Programmer dran?

Der fürt auch zu mehr Verbrauch.

Gruß Matthias

von Thomas E. (thomase)


Lesenswert?

Peter Dannegger schrieb:
> Noch schneller geht, den Interrupt garnicht erst zu enablen.

Stimmt in diesem Fall.

mfg.

von Michi M. (mutzmutz)


Angehängte Dateien:

Lesenswert?

Thomas Eckmann schrieb:
> Michi M. schrieb:
>>> EMPTY_INTERRUPT (  TIMER0_COMPA_vect);
>> ok danke, aber warum genau sollte man das machen ?
>
> Weil es schneller geht als
>
> ISR (TIMER0_COMPA_vect){}

jetzt hab ich erst verstanden dass es als ersatz gelten soll :)


> Michi M. schrieb:
>> ich habe soeben den PB0 / OC0A Ausgang im sleep mode mit einem oszi
>> gemessen, komischerweise spuckt der im 2ms Takt jeweils 8us lange, 4 V
>> signale aus... was läuft denn da schief :) ?
>
> Sieht nach Reset aus. Sicher, daß der Watchdog(Fuse) aus ist?

hab den watchdog in der SW ausgeschalten
1
 WDTCR = 0<<WDIE; // turn off watchdog
 als auch das fusebit gesetzt, siehe angehängtes bild...

>Ist der Programmer dran?
>Der fürt auch zu mehr Verbrauch.

ISP nehm ich nach dem programmieren ab um den strom am akku zu messen..

von Peter D. (peda)


Lesenswert?

Hier mal ein Sleep-Beispiel für den ATTiny13:

Beitrag "Re: attiny13 aufwecken aus power down modus"


Peter

von Michi M. (mutzmutz)


Lesenswert?

so hab jetzt, um zeit und nerven zu schonen, von vorne begonnen :)
sleep funktioniert, also ist der fehler irgendwo in der sw...
baue nun schritt für schritt wieder auf, obwohl ich das vorhin 
eigentlich auch schon gemacht habe :), hoffe aber diesmal den fehler zu 
finden...

@ Peter Dannegger
>Das kann ich nur zustimmen, ich sehe da nicht durch.
>Es gibt fertige Codebeispiele fürs Entprellen mit kurz/lang Erkennung,
>die keine Wünsche offen lassen.

wo finde ich denn solche codebeispiele ?

von Michael S. (Gast)


Lesenswert?

@ Michi,

Nun - ich würde das Thema "Entprellen" an dieser Stelle vertagen, das 
ist eine andere/neue Baustelle.
Das Entprellen kann vorerst ein RC-Glied an Pin INT0 erledigen.

Statt dessen auf die wesentlichen Fragen konzentrieren.

Die da sind:
- wie schicke ich den Controller in einen stromsparenden Modus,
- wie wecke ich ihn wieder daraus und
- wie minimiere ich den Stromverbrauch im Sleep-Modus.

1.)
In den Sleep-Modus zu verfallen ist offensichtlich gelöst.

2.)
Das Wecken ist problematischer, da nicht jeder Interrupt im 
Power-Down-Modus aktiv ist.
So etwa der PC_INT wohl eher nicht.
Funktionieren sollte der INT0 als low-level-Interrupt:
Der feuert, wenn der Pin INT0 von High auf low gezogen wird (etwa durch 
einen Taster).

Solange der Taster aber gedrückt ist und der Interrupt aktiviert ist, 
löst er ständig neu aus.
Das ist dumm.

Daher muss er nach dem Sleep sofort deaktiviert werden.

Damit ist der Sleep-Modus verlassen.

Jetzt kommt anwendungsspezifisches:
- Der Timer/Counter wird zurückgesetzt und gestartet.
- Der INT0 wird auf einen geeigneten Modus umgeschaltet (damit er
  feuert, wenn der Pin wieder losgelassen wird)
- Wird nun der INT0 ausgelöst, dann wird der Couter ausgelesen
  und anschließend in switch case verzeigt.

3.)
Der hohe Stromverbrauch wird an externen Verbraucher, Pullups etc. 
liegen.
Oder am falschen Sleep-Modus.

Michael S.

von Thomas E. (thomase)


Lesenswert?

Michael S. schrieb:
> So etwa der PC_INT wohl eher nicht.

Doch gerade der. Und der drängt sich auch auf, da nämlich, solange der 
Taster gehalten wird, gar nichts passiert.
Und das fehlerträchtige INT0-Um- und abgeschalte kann man sich sparen.

Michael S. schrieb:
> Oder am falschen Sleep-Modus.
Der ist genau richtig.

@Michi M. (mutzmutz)
Entwickle deine Schaltung, bzw. Software komplett fertig, inkl. 
vernünftigem Entprellen. Die Taste fragst du nicht per Interrupt ab, 
sondern in der main oder evtl. in einer der Timer-ISRs. Irgendwas mit 
dem Timer musst du ja sowieso zum Entprellen machen. Das mit den Delays 
in der INT0-ISR ist ja nun nicht besonders schön. PB2, das ist der Port 
auf dem auch der INT0 liegt, initialisierst du als PC_INT.

Wenn alles fertig ist fügst du an geeigneter Stelle den Aufruf des 
Sleep-Mode ein.
Jetzt kommt wieder der EMPTY_INTERRUPT ins Spiel. Den benutzt du für den 
PC_INT nur zum Aufwecken aus dem Sleepmode. Wenn er jetzt jetzt munter 
prellt, wird zwar der Interrupt ein paar Mal ausgelöst, das stört aber 
nicht weiter.

Nachdem das Programm jetzt wieder in der main läuft, kannst du den 
Taster wieder ganz normal benutzen.

mfg.

von Peter D. (peda)


Lesenswert?

Michael S. schrieb:
> Nun - ich würde das Thema "Entprellen" an dieser Stelle vertagen, das
> ist eine andere/neue Baustelle.
> Das Entprellen kann vorerst ein RC-Glied an Pin INT0 erledigen.

Warum?
Es bringt nur zusätzliche Arbeit und zusätzlichen Frust, wenn man erst 
mit ner Krücke anfängt.

Ein Häuslebauer rammt ja auch nicht 4 Pfähle in die Erde und fängt mit 
dem Dach zuerst an. Er fängt natürlich mit dem Fundament an.
Und da fast jede Schaltung eine Nutzereingabe benötigt, kann man das 
Tasten einlesen ruhig als Fundament ansehen.


Peter

von Peter D. (peda)


Lesenswert?

Thomas Eckmann schrieb:
> Wenn alles fertig ist fügst du an geeigneter Stelle den Aufruf des
> Sleep-Mode ein.
> Jetzt kommt wieder der EMPTY_INTERRUPT ins Spiel. Den benutzt du für den
> PC_INT nur zum Aufwecken aus dem Sleepmode. Wenn er jetzt jetzt munter
> prellt, wird zwar der Interrupt ein paar Mal ausgelöst, das stört aber
> nicht weiter.

Du hast damit die Funktion meines obigen Beispiels (Link) wirklich sehr 
schön beschrieben.


Peter

von Thomas E. (thomase)


Lesenswert?

Peter Dannegger schrieb:
> Du hast damit die Funktion meines obigen Beispiels (Link) wirklich sehr
> schön beschrieben.

Das hab' ich gar nicht gelesen.

mfg.

von Michi M. (mutzmutz)


Lesenswert?

vielen dank für die vielen tips, werde mich nun daran machen, das gerüst 
neu aufzubauen sowie systematisch wie beschrieben vorzugehen :)

eine verständnissfrage hab ich noch. ich hab am int0 eingang ein pull 
down und den taster nach vcc verschaltet. im sleep modus kann ich doch 
so mit dem pin change interrupt den controller aufwecken, oder sehe ich 
das falsch ?

von Michi M. (mutzmutz)


Lesenswert?

>eine verständnissfrage hab ich noch. ich hab am int0 eingang ein pull
>down und den taster nach vcc verschaltet. im sleep modus kann ich doch
>so mit dem pin change interrupt den controller aufwecken, oder sehe ich
>das falsch ?

sorry habs gerade bemerkt, dass der pin change int an PB0 liegt, kommt 
also nicht in frage... aber kann ich mit der tasterbeschaltung ein 
lowlevel int im sleep mode betreiben ? das problem ist eben, dass die 
schaltung auf einer fertigen platine so realisiert ist...

von Peter D. (peda)


Lesenswert?

PCINT geht für alle Pins, kann man im PCMSK auswählen.


Peter

von Peter D. (peda)


Lesenswert?


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.