Будить по кнопке на прерывание _И_ по WDT
- Войдите на сайт для отправки комментариев
Втр, 27/08/2013 - 20:01
Такая задача: в спящем режиме раз в 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();
}
}
}
Посмотри пост №9 http://cyber-place.ru/showthread.php?t=325
Там в автономном устройстве есть кнопка , IR датчик на прерываниях и программный таймер .
Всё просыпается по кнопке или по сигналу с IR.
( ... void wakeupFunction() ... )
Я так понимаю, там два прерывания - D2 (ИК приёмник) и D3 (кнопка), то есть внутри самого МК никакого прерывания не происходит. неужто это возможно только снаружи? неохота городить внешний генератор на 4 секунды, я думал можно заставить заниматься этим watchdog.
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 - время, которое следует выждать перед тем как заснуть