Будить по кнопке на прерывание _И_ по WDT

std
Offline
Зарегистрирован: 05.01.2012

Такая задача: в спящем режиме раз в 4 сек. кратковременно загорается светодиод. Ессно, раз в 4 секунды надо проснуться, мигнуть светиком, уснуть. Также есть кнопка, допустим на INT0 (D2) - если нажали кнопку, надо проснуться на некоторое время (допустим 3 секунды), в течение которого светик включен постоянно.

По отдельности работает. Вместе может очнуться только с WDT, жму кнопку а ничё не происходит. Что может быть?

#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
int seconds=0;
volatile boolean f_wdt=true,
               bActive=true;

void pin2Interrupt(void){
  detachInterrupt(0);
  digitalWrite(A0,HIGH);
  bActive=true;
}

ISR(WDT_vect){
  if(!bActive && !f_wdt) f_wdt=true;
}

void enterSleep(void){
  if(bActive){
    attachInterrupt(0, pin2Interrupt, LOW);
    digitalWrite(A0,LOW);
    bActive=false;
  }
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();
  sleep_disable(); /* First thing to do is disable sleep. */

  power_all_enable();
}

void setup(){
  pinMode(A0,OUTPUT);
  /* Clear the reset flag. */
  MCUSR &= ~(1<<WDRF);  
  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).*/
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  /* set new watchdog timeout prescaler value */
  WDTCSR = 1<<WDP3; /* 4.0 seconds */
  /* Enable the WDT interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);
}

void loop(){
  if(f_wdt && !bActive){ // waked by WDT
    /* Toggle the LED */
    digitalWrite(A0,HIGH);
    delay(50);
    digitalWrite(A0,LOW);
    f_wdt = false;
    enterSleep();
  }
  if(bActive){ // waked from btn
    delay(1000);
    seconds++;
    if(seconds == 3){
      seconds = 0;
      enterSleep();
    }    
  }
}
fot
Offline
Зарегистрирован: 23.10.2011

Посмотри пост №9  http://cyber-place.ru/showthread.php?t=325

Там в автономном устройстве есть кнопка , IR датчик на прерываниях и программный таймер .

Всё просыпается по кнопке или по сигналу с IR.

( ... void wakeupFunction() ... )

 

std
Offline
Зарегистрирован: 05.01.2012

Я так понимаю, там два прерывания - D2 (ИК приёмник) и D3 (кнопка), то есть внутри самого МК никакого прерывания не происходит. неужто это возможно только снаружи? неохота городить внешний генератор на 4 секунды, я думал можно заставить заниматься этим watchdog.

std
Offline
Зарегистрирован: 05.01.2012

fot таки предложил просто два прерывания. А тем временем мне всё же удалось замоделить; выкладываю, может кому понадобится.

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

#define LED_PIN (A0)
#define BTN_PIN (2)

volatile boolean WDTflag=true,    // WDT delay expired
                 ISRflag=false,   // the interrupt routine is set
                 ONflag=true;     // state
int seconds=0;

void pin2Interrupt(void){
  if(ISRflag){
    ONflag=true;
    ISRflag=false;
    detachInterrupt(0);
  }
}

ISR(WDT_vect){
  if(!WDTflag) WDTflag=true;
}

void enterSleep(void){
  ONflag=false;
  if(!ISRflag){
    attachInterrupt(0,pin2Interrupt,LOW);
    ISRflag=true;
  }
  delay(100);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();
  sleep_disable(); 
  power_all_enable();
}

void setup(){
  pinMode(BTN_PIN,INPUT_PULLUP);
  pinMode(LED_PIN,OUTPUT);
  MCUSR &= ~(1<<WDRF);
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  WDTCSR = 1<<WDP0 | 1<<WDP3;        // WDT interval
  WDTCSR |= _BV(WDIE);
}

void loop(){
  if(WDTflag && !ONflag){
    digitalWrite(LED_PIN,HIGH);
    delay(50);
    digitalWrite(LED_PIN,LOW);
    WDTflag=false;
    enterSleep();
  }
  if(ONflag){
    digitalWrite(LED_PIN,HIGH);
    delay(1000);
    seconds++;
    if(seconds == 5){        // time to keep ON state
      seconds = 0;
      digitalWrite(LED_PIN,LOW);
      enterSleep();
    }  
  }
}

WDTCSR = 1<<WDP0 | 1<<WDP3; // WDT interval - интервал просыпания (смотреть тут)
if(seconds == 5) // time to keep ON state - время, которое следует выждать перед тем как заснуть