Sleep Mode con RTC e Xbee

Salve ragazzi, ho arduino uno con a bordo xbee s1, ho collegato le due resistenze come da link http://sensor-networks.org/index.php?page=0820520514 provando lo sketch, riesco fare funzionare lo sleep mode. Ora il mio problema è che vorrei collegare anche un RTC http://www.ladyada.net/learn/breakoutplus/ds1307rtc.html, in modo tale da utilizzare lo sleep mode in funzione dell'ora e dei minuti dell'RTC. Così facendo vorrei per esempio, che ogni ora il mio arduino si svegli e comunichi dati (es. la lettura di un sensore). Avete idee in merito o link da segnalarmi ?

L'RTC non ti serve, anche perché un DS1307 non mi pare mandi un segnale di interrupt allo scoccare dell'allarme. usa il timer2 interno per risvegliare il micro dallo sleep. Programmandolo come contatore puoi mandare in overflow il registro e risvegliare il micro dopo un certo periodo di tempo. Di per sé il timer non arriva a 1 ora perché è solo a 8 bit però puoi aggiornare una variabile interna come contasecondi e fare l'azione desiderata.

Allora dato per certo che non posso svegliare il nodo fissando l’orario, ho fatto come mi hai suggerito utilizzando timer2.
Io vorrei leggere la data e l’ora ogni 20 secondi. Il codice che ho scritto e’ il seguente:

#include <Wire.h>
#include <RTClib.h>

#include <avr/interrupt.h>   
#include <avr/io.h> 
#include <avr/sleep.h>
#define INIT_TIMER_COUNT 0
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT

int int_counter = 0;      
int second = 0;
int counter = 0;
int XBee_pin = 7;          // this pins wake up xbee and put it to sleep
int seconds = 10;         // time sleeping (aprox seconds) MINIMUM VALUE = 5
int time = 2*seconds;      // aux. time

RTC_DS1307 RTC;

// Aruino runs at 16 Mhz, so we have 61 Overflows per second? 1/ ((16000000 / 1024) / 256) = 1 / 61
ISR(TIMER2_OVF_vect) {                // this subroutine is executed 61 times per second
 int_counter ++;
 if (int_counter == 15) { 
  second++;               
  int_counter = 0;        
 }
 if (second == time - 1) {           
  digitalWrite(XBee_pin, LOW);
 }
 if (second == time) {
  second = 0;
  Date();
  digitalWrite(XBee_pin, HIGH);
 }
}

void Xbee_Setup(){
 pinMode(XBee_pin, OUTPUT);
 digitalWrite(XBee_pin,HIGH);
 //Timer2 Settings:  Timer Prescaler /1024
 TCCR2B |= ((1 << CS22) | (1 << CS21) | (1 << CS20));
 //Timer2 Overflow Interrupt Enable
 TIMSK2 |= (1 << TOIE2);
 RESET_TIMER2;
 sei();
 digitalWrite(XBee_pin, LOW);
 delay(20);
 Date();
 digitalWrite(XBee_pin,HIGH);
}

void Rtc_Setup(){
 Wire.begin();
 RTC.begin();
 if (! RTC.isrunning()) {
  Serial.println("RTC is NOT running!");
  // RTC.adjust(DateTime(__DATE__, __TIME__));
 }
}

void setup(){  
 Serial.begin(19200); 
 Rtc_Setup();
 Xbee_Setup(); 
}

void SleepNow(){
 set_sleep_mode(SLEEP_MODE_PWR_SAVE);   // sleep mode is set here
 sleep_enable();          // enables the sleep bit in the mcucr register
 sleep_mode();            // here the device is actually put to sleep!! THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
 sleep_disable();         // first thing after waking from sleep: disable sleep...
}

void Date() {
 DateTime now = RTC.now();
 Serial.print(now.day(), DEC);
 Serial.print('/');
 Serial.print(now.month(), DEC);
 Serial.print('/');
 Serial.print(now.year(), DEC);
 Serial.print(' ');
 Serial.print(now.hour(), DEC);
 Serial.print(':');
 Serial.print(now.minute(), DEC);
 Serial.print(':');
 Serial.print(now.second(), DEC);
 Serial.print(' ');
}

void loop(){
 SleepNow(); 
}

Accade che leggendo da seriale stampa la prima data e ora, va in sleep dopo 60 (time=2*30) secondi si sveglia non stampa nulla e non si riaddormenta.
Dove sto sbagliando?

Perché da loop() richiami solo la funzione per metterlo a nanna ma la funzione per stampare è dentro ad un'altra funzione.

No leo72 come puoi vedere dal codice, ho cambiato la funzione Date() in ISR(TIMER2_OVF_vect) con Serial.println(“funzione ISR”) e in Xbee_Setup() con Serial.println(“funzione xbee_setup”).
Il risultato e’ che ho questo output:
funzione xbee_setup
funzione ISR
funzione ISR
funzione ISR
[ … ]
Dove la stringa “funzione ISR” viene stampata ogni volta che si sveglia. Invece perche’ se richiamo la funzione Date() sia su ISR(TIMER2_OVF_vect) che Xbee_Setup() non ottengo lo stesso risultato? =( =( =(

#include <Wire.h>
#include <RTClib.h>

#include <avr/interrupt.h>   
#include <avr/io.h> 
#include <avr/sleep.h>
#define INIT_TIMER_COUNT 0
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT

int int_counter = 0;      
int second = 0;
int counter = 0;
int XBee_pin = 7;          // this pins wake up xbee and put it to sleep
int seconds = 10;         // time sleeping (aprox seconds) MINIMUM VALUE = 5
int time = 2*seconds;      // aux. time

RTC_DS1307 RTC;

// Aruino runs at 16 Mhz, so we have 61 Overflows per second? 1/ ((16000000 / 1024) / 256) = 1 / 61
ISR(TIMER2_OVF_vect) {                // this subroutine is executed 61 times per second
 int_counter ++;
 if (int_counter == 15) { 
  second++;               
  int_counter = 0;        
 }
 if (second == time - 1) {           
  digitalWrite(XBee_pin, LOW);
 }
 if (second == time) {
  second = 0;
  Serial.println("funzione ISR");
  digitalWrite(XBee_pin, HIGH);
 }
}

void Xbee_Setup(){
 pinMode(XBee_pin, OUTPUT);
 digitalWrite(XBee_pin,HIGH);
 //Timer2 Settings:  Timer Prescaler /1024
 TCCR2B |= ((1 << CS22) | (1 << CS21) | (1 << CS20));
 //Timer2 Overflow Interrupt Enable
 TIMSK2 |= (1 << TOIE2);
 RESET_TIMER2;
 sei();
 digitalWrite(XBee_pin, LOW);
 delay(20);
 Serial.println("funzione xbee_setup");
 digitalWrite(XBee_pin,HIGH);
}

void Rtc_Setup(){
 Wire.begin();
 RTC.begin();
 if (! RTC.isrunning()) {
  Serial.println("RTC is NOT running!");
  // RTC.adjust(DateTime(__DATE__, __TIME__));
 }
}

void setup(){  
 Serial.begin(19200); 
 Rtc_Setup();
 Xbee_Setup(); 
}

void SleepNow(){
 set_sleep_mode(SLEEP_MODE_PWR_SAVE);   // sleep mode is set here
 sleep_enable();          // enables the sleep bit in the mcucr register
 sleep_mode();            // here the device is actually put to sleep!! THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
 sleep_disable();         // first thing after waking from sleep: disable sleep...
}

void Date() {
 DateTime now = RTC.now();
 Serial.print(now.day(), DEC);
 Serial.print('/');
 Serial.print(now.month(), DEC);
 Serial.print('/');
 Serial.print(now.year(), DEC);
 Serial.print(' ');
 Serial.print(now.hour(), DEC);
 Serial.print(':');
 Serial.print(now.minute(), DEC);
 Serial.print(':');
 Serial.print(now.second(), DEC);
 Serial.print(' ');
}

void loop(){
  SleepNow(); 
}

Mi sa che dipende dal fatto che chiami funzioni esterne all'interrupt che potrebbe usare altri interrupt. La funzione Date legge la data dall'RTC usando l'I2C. Per temporizzare il segnale e per ricevere i dati mi pare sia usato un interrupt. Ma dentro ad un interrupt tutti gli interrupt esterni sono bloccati. Ed il tuo codice muore lì.

Secondo me il tuo codice sarebbe tutto da riscrivere perché devi solo svegliare il micro quando è l'ora di stampare l'orario e questa cosa NON devi farla da dentro l'interrupt ma dal loop principale del programma. Vale a dire che nel loop devi: 1) mettere in sleep il micro 2) dopo lo sleep metti il controllo per vedere se è stato attivato un flag da dentro l'interrupt al raggiungimento di 15 conteggi 3) se il flag c'è, leggi l'ora e resetti il flag 4) se non c'è o dopo il punto 3), torni al punto 1)

Ottimo leo con il tuo consiglio sono riuscito a sistemare tutto XD. Ecco il codice:

#include <Wire.h>
#include <RTClib.h>

#include <avr/interrupt.h>   
#include <avr/io.h> 
#include <avr/sleep.h>
#define INIT_TIMER_COUNT 0
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT

int int_counter = 0;      
int second = 0;
int counter = 0;
int XBee_pin = 7;          // This pins wake up xbee and put it to sleep
int seconds = 20;          // Time sleeping (aprox seconds) MINIMUM VALUE = 5
int time = 2*seconds;      
boolean flag = false;

RTC_DS1307 RTC;
unsigned int giorno, mese, anno, ora, minuti, secondi;

// Aruino runs at 16 Mhz, so we have 61 Overflows per secondi 1/ ((16000000 / 1024) / 256) = 1 / 61 this subroutine is executed 61 times per second
ISR(TIMER2_OVF_vect) {                
 int_counter ++;
 if (int_counter == 15) { 
  second++;               
  int_counter = 0;        
 }
 if (second == time - 1) {           
  digitalWrite(XBee_pin, LOW);
 }
 if (second == time) {
  second = 0; 
  Print_Date();
  Serial.println(" sono nella funzione ISR");
  flag = true; 
  digitalWrite(XBee_pin, HIGH);
 }
}

void Xbee_Setup(){
 pinMode(XBee_pin, OUTPUT);
 digitalWrite(XBee_pin,HIGH);
 //Timer2 Settings:  Timer Prescaler /1024
 TCCR2B |= ((1 << CS22) | (1 << CS21) | (1 << CS20));
 //Timer2 Overflow Interrupt Enable
 TIMSK2 |= (1 << TOIE2);
 RESET_TIMER2;
 sei();
 digitalWrite(XBee_pin, LOW);
 //delay(20);
 //Serial.println("sono nella funzione xbee setup");
 digitalWrite(XBee_pin,HIGH);
}

void Rtc_Setup(){
 Wire.begin();
 RTC.begin();
 if (! RTC.isrunning()) {
  Serial.println("RTC is NOT running!");
  //RTC.adjust(DateTime(__DATE__, __TIME__));
 }
}

void setup(){  
 Serial.begin(19200);    
 Rtc_Setup();
 Date_Setup();
 Xbee_Setup(); 
}

void SleepNow(){
 set_sleep_mode(SLEEP_MODE_PWR_SAVE);   // sleep mode is set here
 sleep_enable();          // enables the sleep bit in the mcucr register
 sleep_mode();            // here the device is actually put to sleep!! THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
 sleep_disable();         // first thing after waking from sleep: disable sleep...
}

void Print_Date() {
 Serial.print(giorno);
 Serial.print("/");
 Serial.print(mese);
 Serial.print("/");
 Serial.print(anno);
 Serial.print(" ");
 Serial.print(ora);
 Serial.print(":");
 Serial.print(minuti);
 Serial.print(":");
 Serial.print(secondi);
}

void Date_Setup() {
 DateTime now = RTC.now();
 giorno = now.day();
 mese = now.month();
 anno = now.year();
 ora = now.hour();
 minuti = now.minute();
 secondi = now.second();
}

void loop(){
 if(flag == true){
  Date_Setup();
  flag=false;
 }
 if(flag == false){ 
  SleepNow();
 }
}

Adesso vorrei dei consigli, link, doc, esempi su come fare un interrupt con l’RTC (DS1307) secondo una determinata ora, es. alle ore xx:yy:zz voglio che il mio nodo si svegli. Come posso fare ? :roll_eyes: