mikrocontroller.net

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


Autor: Torsten Wegmann (toto1975)
Datum:

Bewertung
0 lesenswert
nicht 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
// ATMEL ATTINY 25/45/85 / ARDUINO
//
//                  +-\/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//            GND  4|    |5  PB0 (D 0) pwm0
//                  +----+



#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
#include <avr/wdt.h>      // Watchdog timer
#include <VirtualWire.h>

int sensorPin = A1; //zum lesen der Daten
char daten[4];
const int PIN_LED = 4;
const int strom =  1;




ISR (PCINT0_vect) 
 {
 // do something interesting here
 }  // end of PCINT0_vect

 // watchdog interrupt
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // end of WDT_vect

void resetWatchdog ()
  {
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset, clear existing interrupt
  WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  WDTCR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  // pat the dog
  wdt_reset();  
  }  // end of resetWatchdog

  void setup ()
  {
  resetWatchdog ();  // do this first in case WDT fires
   // Transmitter is connected to Arduino Pin #10  
  pinMode(PIN_LED, OUTPUT);
  pinMode(strom, OUTPUT);
  // VirtualWire setup
  vw_setup(1000); // Bits per sec
  vw_set_tx_pin(3);// 
  }

void loop ()
  {
   memset(daten, 0, sizeof daten);                           // Inhalt der Variblen (char) löschen
   digitalWrite(strom, HIGH);
   digitalWrite(PIN_LED, HIGH);
   delay(250);
   sprintf(daten, "%d", analogRead(sensorPin));
   delay(1000);
   vw_send((uint8_t *)daten, strlen(daten));
   vw_wait_tx(); // Wait until the whole message is gone

   //delay(1000);
   digitalWrite(strom, LOW);
   digitalWrite(PIN_LED, LOW);
   //Schlafen gehen
   for (int i=0; i<1 ; i++){  //Hier schläft er jetzt 8 Sekunden
   goToSleep ();
  }
   
  }  // end of loop
  
void goToSleep ()
  {
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  noInterrupts ();       // timed sequence coming up
  resetWatchdog ();      // get watchdog ready
  sleep_enable ();       // ready to sleep
  interrupts ();         // interrupts are required now
  sleep_cpu ();          // sleep                
  sleep_disable ();      // precaution
  power_all_enable ();   // power everything back on
  }  // end of goToSleep 
  

Vielen Dank und Gruß
Torsten

Autor: Carl Drexler (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht ist die erste Messung nach einem sleep() noch nicht perfekt.
   digitalWrite(PIN_LED, HIGH);
   //>>> mehrfach lesen bis was sinnvolles kommt
   int ad;
   for(int n=0; n<100; n++) // max 100mal "anti-Hänger"
   {
      delay(250);
      ad = analogRead(sensorPin);
      if(ad>0) 

         break;
   }
   //<<<
   sprintf(daten, "%d", ad);
   delay(1000);     // wozu warten? Werden die Daten besser?
   vw_send((uint8_t *)daten, strlen(daten));

Autor: Torsten Wegmann (toto1975)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> Vielleicht ist die erste Messung nach einem sleep() noch nicht perfekt.
>
   digitalWrite(PIN_LED, HIGH);
>    //>>> mehrfach lesen bis was sinnvolles kommt
>    int ad;
>    for(int n=0; n<100; n++) // max 100mal "anti-Hänger"
>    {
>       delay(250);
>       ad = analogRead(sensorPin);
>       if(ad>0)
> 
>          break;
>    }
>    //<<<
>    sprintf(daten, "%d", ad);
>    delay(1000);     // wozu warten? Werden die Daten besser?
>    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

Autor: Sascha Weber (sascha-w)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Torsten Wegmann (toto1975)
Datum:

Bewertung
0 lesenswert
nicht 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:
byte adcsra_save = ADCSRA;
ADCSRA = adcsra_save;
delay(250)

Danke und Gruß
Torsten

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

: Bearbeitet durch User
Autor: Sascha Weber (sascha-w)
Datum:

Bewertung
0 lesenswert
nicht 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:
>
>
> byte adcsra_save = ADCSRA;
> ADCSRA = adcsra_save;
> delay(250)
> 
unkonventionell aber wird aber auch funktionieren

Sascha

Autor: Karl M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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*

Autor: Sascha Weber (sascha-w)
Datum:

Bewertung
0 lesenswert
nicht 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

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.