Forum: Mikrocontroller und Digitale Elektronik Fehler durch den Sleep Modus Attiny85


von Torsten W. (toto1975)


Lesenswert?

Hallo in die Runde,

ich möchte gerne mit Hilfe eines Attiny85 die Feuchtigkeit messsen. Da 
ich den Wert nur 2x mal am Tag benötige würde ich gerne den Attiny nach 
der Messung gerne "schlafen legen". Mein Problem ist nun folgendes:

Wenn ich die void goToSleep() aufrufe geht er zwar schlafen und wird 
auch wieder wach (die prüf- LED leuchtet) allerdings erfolgt keine 
korrekte Messung. Als Ergebnis wird mir immer nur "0" angezeigt.

Rufe ich die goToSleep nicht auf erfolgt die Messung korrekt. Was habe 
ich in der goToSleep falsch gemacht?

Als Anfänger kann ich hier leider keinen Fehler finden.

Anbei noch mein Code
1
// ATMEL ATTINY 25/45/85 / ARDUINO
2
//
3
//                  +-\/-+
4
// Ain0 (D 5) PB5  1|    |8  Vcc
5
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1
6
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
7
//            GND  4|    |5  PB0 (D 0) pwm0
8
//                  +----+
9
10
11
12
#include <avr/sleep.h>    // Sleep Modes
13
#include <avr/power.h>    // Power management
14
#include <avr/wdt.h>      // Watchdog timer
15
#include <VirtualWire.h>
16
17
int sensorPin = A1; //zum lesen der Daten
18
char daten[4];
19
const int PIN_LED = 4;
20
const int strom =  1;
21
22
23
24
25
ISR (PCINT0_vect) 
26
 {
27
 // do something interesting here
28
 }  // end of PCINT0_vect
29
30
 // watchdog interrupt
31
ISR (WDT_vect) 
32
{
33
   wdt_disable();  // disable watchdog
34
}  // end of WDT_vect
35
36
void resetWatchdog ()
37
  {
38
  // clear various "reset" flags
39
  MCUSR = 0;     
40
  // allow changes, disable reset, clear existing interrupt
41
  WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF);
42
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
43
  WDTCR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
44
  // pat the dog
45
  wdt_reset();  
46
  }  // end of resetWatchdog
47
48
  void setup ()
49
  {
50
  resetWatchdog ();  // do this first in case WDT fires
51
   // Transmitter is connected to Arduino Pin #10  
52
  pinMode(PIN_LED, OUTPUT);
53
  pinMode(strom, OUTPUT);
54
  // VirtualWire setup
55
  vw_setup(1000); // Bits per sec
56
  vw_set_tx_pin(3);// 
57
  }
58
59
void loop ()
60
  {
61
   memset(daten, 0, sizeof daten);                           // Inhalt der Variblen (char) löschen
62
   digitalWrite(strom, HIGH);
63
   digitalWrite(PIN_LED, HIGH);
64
   delay(250);
65
   sprintf(daten, "%d", analogRead(sensorPin));
66
   delay(1000);
67
   vw_send((uint8_t *)daten, strlen(daten));
68
   vw_wait_tx(); // Wait until the whole message is gone
69
70
   //delay(1000);
71
   digitalWrite(strom, LOW);
72
   digitalWrite(PIN_LED, LOW);
73
   //Schlafen gehen
74
   for (int i=0; i<1 ; i++){  //Hier schläft er jetzt 8 Sekunden
75
   goToSleep ();
76
  }
77
   
78
  }  // end of loop
79
  
80
void goToSleep ()
81
  {
82
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
83
  ADCSRA = 0;            // turn off ADC
84
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
85
  noInterrupts ();       // timed sequence coming up
86
  resetWatchdog ();      // get watchdog ready
87
  sleep_enable ();       // ready to sleep
88
  interrupts ();         // interrupts are required now
89
  sleep_cpu ();          // sleep                
90
  sleep_disable ();      // precaution
91
  power_all_enable ();   // power everything back on
92
  }  // end of goToSleep

Vielen Dank und Gruß
Torsten

von Carl D. (jcw2)


Lesenswert?

Vielleicht ist die erste Messung nach einem sleep() noch nicht perfekt.
1
   digitalWrite(PIN_LED, HIGH);
2
   //>>> mehrfach lesen bis was sinnvolles kommt
3
   int ad;
4
   for(int n=0; n<100; n++) // max 100mal "anti-Hänger"
5
   {
6
      delay(250);
7
      ad = analogRead(sensorPin);
8
      if(ad>0) 
9
10
         break;
11
   }
12
   //<<<
13
   sprintf(daten, "%d", ad);
14
   delay(1000);     // wozu warten? Werden die Daten besser?
15
   vw_send((uint8_t *)daten, strlen(daten));

von Torsten W. (toto1975)


Lesenswert?

Carl D. schrieb:
> Vielleicht ist die erste Messung nach einem sleep() noch nicht perfekt.
>
1
   digitalWrite(PIN_LED, HIGH);
2
>    //>>> mehrfach lesen bis was sinnvolles kommt
3
>    int ad;
4
>    for(int n=0; n<100; n++) // max 100mal "anti-Hänger"
5
>    {
6
>       delay(250);
7
>       ad = analogRead(sensorPin);
8
>       if(ad>0)
9
> 
10
>          break;
11
>    }
12
>    //<<<
13
>    sprintf(daten, "%d", ad);
14
>    delay(1000);     // wozu warten? Werden die Daten besser?
15
>    vw_send((uint8_t *)daten, strlen(daten));

Hallo,

leider ist dies auch nicht die Lösung als Ergebnis wird mir weiterhin 
die "0" angezeigt bzw. gesendet.

Las ich wie gesagt die sleep() weg werden mir Daten angezeigt. Kann es 
sein das durch den sleep() die Analogen Eingänge deaktiviert werden? 
Zeit hat er ja nun mehr wie genug.

Gruß
Torsten

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

mit ADCSRA=0 wird der ADC deaktiviert, wenn du nach dem Spleep wieder 
messen willst must du den erst einschalten. Bei Verwendung der internen 
Referenz auch erst noch paar ms s. DB (mit externem C an ARef noch 
länger) warten bis Spannung stabil.

Sascha

von Torsten W. (toto1975)


Lesenswert?

Super, vielen Dank! Ich habe jetzt dies

//ADCSRA = 0;            // turn off ADC

auskommentiert und es funktioniert ;-)

Nur zum besseren Verständnis: Wenn ich diesen wieder einschalten möchte 
wo und wie mache ich dies?

Könnte dies eine Lösung sein:
1
byte adcsra_save = ADCSRA;
2
ADCSRA = adcsra_save;
3
delay(250)

Danke und Gruß
Torsten

PS: Ich werde aus den Datenblatt leider nicht schlau :-(

: Bearbeitet durch User
von Sascha W. (sascha-w)


Lesenswert?

Torsten W. schrieb:
> Super, vielen Dank! Ich habe jetzt dies
>
> //ADCSRA = 0;            // turn off ADC
>
> auskommentiert und es funktioniert ;-)
was nicht so gut ist, denn dann steigt der Stromverbrauch im Sleep ganz 
ordentlich!

> Nur zum besseren Verständnis: Wenn ich diesen wieder einschalten möchte
> wo und wie mache ich dies?
du must ihn doch auch sonst irgendwo initialisiert haben, nach dem Reset 
ist das Register ja auch 0.

> Könnte dies eine Lösung sein:
>
>
1
> byte adcsra_save = ADCSRA;
2
> ADCSRA = adcsra_save;
3
> delay(250)
4
>
unkonventionell aber wird aber auch funktionieren

Sascha

von Karl M. (Gast)


Lesenswert?

Hallo Thorsten,

so ein Datenblatt für den attiny85 ist kein Hexenwerk und nach 10 
maligem kompletten Lesen sollte man auch einige Erkenntnisse daraus 
ziehen könnten.

Mein Tipp:
Seite 38f
*7.5.2 PRR – Power Reduction Register*

von Sascha W. (sascha-w)


Lesenswert?

Karl M. schrieb:
> Mein Tipp:
> Seite 38f
> *7.5.2 PRR – Power Reduction Register*
macht seine Routine ja schon, power_all_disable(), nützt aber beim ADC 
nichts, wenn man den vorher nicht abschaltet - bin ich selbst schon 
drüber gestolpert und hab mich über den zu hohen Verbrauch gewundert.

Sascha

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.