ATTINY 261 mit timer aufwecken

Hallo,

Ich habe ein erstes kleines Projekt mit einem ATTINY 261 , Button und einer Digital-Anzeige.
Um das ganze an einer Batterie betreiben zu können versuche ich mich gerade
den ATTINY in den SLEEP Modus zu setzen und alle 100 ms mit einem timer interrupt wieder aufzuwecken.

Leider funktioniert das aufwecken nicht.

void setup() 
{
  // Setup Timer0
  cli(); // Disable interrupts
  TCCR0A = 0; // Clear timer control register A
  TCCR0B = 0; // Clear timer control register B
  TIMSK |= (1 << TOIE0); // Enable timer overflow interrupt
  sei(); // Enable interrupts
  // Set prescaler to 64
  TCCR0B |= (1 << CS01) | (1 << CS00);

   // display a 1 in the 1-7 digit display
  showNumber(1);
void loop() 
{ 
  // Put ATtiny261 to sleep
  // set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  set_sleep_mode(SLEEP_MODE_IDLE);
  sleep_enable();
  sleep_cpu();
  sleep_disable();
  
  // Check if 100ms has elapsed (approximately)
  if (timerCounter >= 25) 
  { // Approximately 100ms with prescaler 64
    timerCounter = 0; // Reset counter
    // Display 2 in the 1-7 Digit display
    showNumber(2);
  
volatile uint8_t timerCounter = 0;
// Increment the counter on timer overflow 
ISR(TIM0_OVF_vect) { timerCounter++; }

Der Verbrauch sinkt auf 11 mA (etwa 9mA für die 1 in der Anzeige), leider funktioniert das aufwecken nicht.
Hat mit jemand einen Tipp?

Das aufwecken funktioniert nur über einen externen Interrupt oder einen Interrupt des Watchdogtimers. Der Timer 0 bringt Dir da gar nichts.

Beim überfliegen des Attiny261 Datenblattes scheinen die Register dieselben eines Attiny85 zu sein...

Darum hier ein grobes Raster welches ich bei einem Attiny85 verwendet habe:

#include <avr/wdt.h>
#include <avr/sleep.h>

// time until the watchdog wakes the mc in seconds
constexpr uint8_t WATCHDOG_TIME {8};   // 1, 2, 4 or 8
// after how many watchdog wakeups we should collect and send the data
constexpr uint8_t WATCHDOG_WAKEUPS_TARGET {7};   // 8 * 7 = 56 seconds between each data collection

// watchdog ISR
ISR(WDT_vect) {
  // nothing to do here, just wake up
}

void enableWatchdog() {
  cli();
  MCUSR &= ~(1 << WDRF);               // clear the reset flag
  WDTCR |= (1 << WDCE) | (1 << WDE);   // set WDCE to be able to change/set WDE
#if WATCHDOG_TIME == 1                 // set new watchdog timeout prescaler value
  WDTCR = 1 << WDP1 | 1 << WDP2;
#elif WATCHDOG_TIME == 2
  WDTCR = 1 << WDP0 | 1 << WDP1 | 1 << WDP2;
#elif WATCHDOG_TIME == 4
  WDTCR = 1 << WDP3;
#elif WATCHDOG_TIME == 8
  WDTCR = 1 << WDP0 | 1 << WDP3;
#else
  // #error WATCHDOG_TIME must be 1, 2, 4 or 8!
#endif
  WDTCR |= (1 << WDIE);   // enable the WD interrupt to get an interrupt instead of a reset
  sei();
}

// function to go to sleep
void enterSleep(void) {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption.
  sleep_enable();
  sleep_mode();   // Now enter sleep mode.
  // The program will continue from here after the WDT timeout
  sleep_disable();   // First thing to do is disable sleep.
}

void setup() { enableWatchdog(); }

void loop() {
  // some code

  // sleep
  for (size_t i = 0; i < WATCHDOG_WAKEUPS_TARGET; i++) { enterSleep(); }
}

Danke für die schnelle Hilfe, hat funktioniert.
Die Zeiten musste ich aber um den Faktor 1000 korrigieren,
waren Millisekunden statt Sekunden.

Mit SLEEP_MODE_PWR_DOWN und SLEEP_MODE_ADC
funktioniert das aufwecken nicht.
Aber ich habe schon mal eine gute Grundlage.

Danke

Das mit den Zeiten verstehe ich nicht.

Aus dem Datenblatt vom 261:

Das stimmt doch mit dem Codebeispiel überein. Und demnach müsste der Watchdog alle 8 Sekunden auslösen. Die Schleife wird sieben mal durchlaufen, also müsste etwa alle 56 Sekunden die loop() einmal abgearbeitet werden.

Versteh ich auch nicht.

Zu allem Überfluss habe ich jetzt auch noch mit
clock_prescale_set rumgespielt.
Eigentlich erfolgreich: mit clock_prescale_set(clock_div_8);
hat sich der Verbrauch nochmal halbiert.

Aber nach einem clock_prescale_set(clock_div_256);
scheint das Ding nun für Arduino ISP zu langsam zu sein und ich
kann leider nichts mehr auf den ATTINY hochladen.
Da ich leider auch keinen zweiten ATTINY zur Hand habe,
muss mich also zuerst mal damit beschäftigen wie ich den ATTINY
wieder über ISP ansprechbar mache --> TinyFuses

Lustiges Hobby :wink:

Lass die Fuses erst mal in Ruhe. Versuch mal das Flashen, indem Du avrdude den Parameter -B 1024 mitgibst.

In meinem Beispiel ist noch ein Fehler. Müsst eigentlich aufgefallen sein. Aber trotzdem.

Die Zeile constexpr uint8_t WATCHDOG_TIME {8}; // 1, 2, 4 or 8 ist falsch.
Es muss #define WATCHDOG_TIME 8 lauten. Ansonsten funktionieren die #if Direktiven in der enableWatchdog() Funktion nicht.

Ja, hätte ich eigentlich sehen können, habe mit einem neuen ATTINY den
nicht gefixten code nochmal laufen lassen und statt sleep macht er ein reboot.

Mein nun funktionierender code sieht so aus.

ISR(WDT_vect) { wdt_disable(); };

void enableWatchdog() 
{
  // disable ADC
  ADCSRA = 0;  
  // ADCSRA |= (1 << ADEN); // Setze das ADEN-Bit, um den ADC zu aktivieren

  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCR = bit (WDIE) | bit (WDP2) | bit (WDP0);    // set WDIE, and 0.5 seconds delay
  // WDTCR = bit (WDIE) | bit (WDP2);                    // set WDIE, and 0.25 seconds delay
  wdt_reset();  // pat the dog
  
  set_sleep_mode (SLEEP_MODE_PWR_DOWN); 
  // set_sleep_mode (SLEEP_MODE_IDLE); 
  // set_sleep_mode (SLEEP_MODE_STANDBY);
  noInterrupts ();           // timed sequence follows
  sleep_enable();
 
  // turn off brown-out enable in software
  // MCUCR = bit (BODS) | bit (BODSE);
  // MCUCR = bit (BODS); 
  interrupts ();             // guarantees next instruction executed
  sleep_cpu ();  
  
  // cancel sleep as a precaution
  sleep_disable();
}

void setup() 
{
  clock_prescale_set(clock_div_8);
  for(byte i=0; i<=7; i++)
    pinMode(LED[i],OUTPUT);
  pinMode(PIN_BTN1,INPUT_PULLUP);
  // pinMode(PIN_BUZZER,OUTPUT);
  DDRB |= (1 << PIN_BUZZER); // PWM-fähiger Pin für Buzzer
}

Verbrauch liegt wie erwartet bei etwa 5µA bei ausgeschalteten LEDs.
Werde mich nun mit einer Stromversorgung an einer 9V Block Batterie (mit MCP1602) beschäftigen.

Vielen dank nochmal für deine Hilfe.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.