Question about sleeping and loop

Hi folks,

I have a head pain due to something that i try to solve. Let me explain the case.

I have my arduino sleeping. It gets up thanks to the alarm from a RTC. Then, it measure by different sensors, save the data into a SD card, and come back to sleep again. It works perfect.

Now, I also want to control my devide sending commands by the serial port (in fact by a bluetooth). So, i connected the Rx pin to the Int0 (the same where is connected the alarm, because i use the other one to do other things.

The problem is that i am doing something wrong because in all cases i send a command, it made the default task, like if didn´t read anything by the serial port, and just only receiving the interrupt... I changed the position of the routine what reads the serial port and decide what task to develop... but i didn´t see where is the problem.

Did you see where is the problem? or what i am doing wrong?

[code] 
// Here goes all the call to libraries, constant and variables. I removed in order to save space in this forum

void setup(){
  // Inicializacion RTC
  RTC.start();
  // Configuración de la alarma
  RTC.enable_interrupt();
  RTC.setSeconds(55);
  RTC.setMinutes(59);
  RTC.setAlarmRepeat(EVERY_HOUR);
  RTC.writeAlarm();
  pinMode(alarma, INPUT);                    // Receptor de alarmas
  digitalWrite(alarma, HIGH);
  // Configuración de pins
  pinMode(power, OUTPUT);                    // Alimentacion de sensores
  // Inicializacion del puerto serie
  Serial.begin(115200);                        // Inicia comunicaciones
  // Comprobación de la tarjeta SD
  pinMode(10, OUTPUT);                        // Configuración de la librería SD
  if (!SD.begin(chipSelect)) {
    Serial.println("WProblemas con la tarjeta de memoria SD");
  }
  else {
    Serial.println("WTarjeta de memoria SD preparada");
  }
}

void loop(){
  // Fin de la medición, Inicio del letargo
  Dormir();
}

// Función tras despertar
void Despertar(){
   c = Serial.read() ;
}


// Realizar las mediciones de los sensores
void Mediciones(){
  // Inicialización de sensores
  sensors.begin();                         // Inicia el sensor de temperatura DS18B20
  sensors2.begin();
  // Alimentación de sensores
  digitalWrite(power, HIGH);
  delay(5000); 
  // Inicio de la medición de parámetros ambientales
  tiempo();                                // Toma la hora
  delay(20);
  readVcc();                               // Lee el voltaje interior
  delay(20);
  midebateria();                           // Mide el voltaje de entrada
  delay(20);
  readTemp();                              // Mide la temperatura interna
  delay(20);
  midegotas();                             // Mide la intensidad de lluvia (disdrómetro)
  delay(20);
  temperatura();                           // Mide la temperatura exterior (DS18B20)
  delay(20);
  sueloH();                                // Mide la humedad del suelo
  delay(20);
  suelotemp();                             // Mide la temperatura del suelo
  delay (20);
  temphumroc();                            // Lee temperatura y humedad (SH15) y calcula el punto de rocío
  delay (20);
  luminosidad();                           // Mide la luminosidad (LDR)
  delay  (20);
  radiacion();                             // Mide la radiación luminosa, irradiancia (TSL235R)
  delay(20);
  velocidadviento();                       // Mide la velocidad del viento (QRD1114)              
  // Grabación de los resultados
  grabar();                              // Graba los datos en formato ascii en un soporte microSD
  delay(5000); 
  contador = contador + 1;                 // Actualiza el contador de medidas
  digitalWrite(power, LOW);
  delay(500);
}

// Configuración del estado de letargo
void Dormir(){
  attachInterrupt(0, Despertar, FALLING);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  RTC.enable_interrupt();
  sleep_mode();
  // -->FASE DE LETARGO DEL DISPOSITIVO<--
  sleep_disable();
  RTC.disable_interrupt();
  detachInterrupt(0);
  Leermensaje();
}

// Procesar mensaje del puerto serie
void Leermensaje() {
  if(Serial.available() >=  0 ){  
    //char c = Serial.read() ;
    if ( c == 'T' ) {
      setuptime();
    }
    else if ( c == 'D'){
      DescargaDatos();;
    }
    else {
      Mediciones();
    }
  }
}

// Actualizar la hora del RTC a través del puerto serie
void setuptime(){
  int pctime = 0;
  for(int i=0; i < TIME_MSG_LEN -1; i++){
    char c = Serial.read();
    if( c >= '0' && c <= '9'){
      pctime = (10 * pctime) + (c - '0') ; // convert digits to a number
    }
  }
  RTC.writeTime(pctime);   // Sync clock to the time received on serial port
  Serial.print('T');
  Serial.print(pctime);
  delay(1000);
}

// Volcado de datos en el puerto serie
void DescargaDatos(){
  Serial.println("WTarjeta SD inicializada");
  File dataFile = SD.open("datos.csv");
  //Serial.println(dataFile.size());
  if (dataFile) {
    Serial.println("WIniciando la descarga de datos");
    while (dataFile.position() < dataFile.size()) {
      Serial.write(dataFile.read());
    }
    dataFile.close();
    Serial.println("@");
    delay(1000);
    Serial.println("WDescarga completa");
  }  
  else {
    Serial.println("WError al abrir datos.csv");
  }
}

// Lee el Reloj de Tiempo Real (DS1337)
void tiempo(){
  // Lee el RTC
  RTC.readTime();
  // Memoriza la fecha actual
  day = RTC.getDays();
  month = RTC.getMonths();
  year = RTC.getYears();
  //Memoriza la hora actual
  hora = RTC.getHours();
  minuto = RTC.getMinutes();
  segundo = RTC.getSeconds();
  return;
} 

// Lee el voltaje de entrada
float midebateria(){
  batt = (analogRead(bateria))*volt;
  return batt;
} 

//Lee el voltaje interno
long readVcc() {
  long readVcc=0;
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2);
  ADCSRA |= _BV(ADSC);
  while (bit_is_set(ADCSRA,ADSC));
  readVcc = ADCL;
  readVcc |= ADCH<<8;
  innerVcc = 1126400L / readVcc; // Back-calculate AVcc in mV
  innerVcc = innerVcc / 1000;
  return innerVcc;
}

// Obtiene la temperatura interna de dispositivo Arduino
long readTemp() {
  long readTemp=0;
  ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);
  delay(20);
  ADCSRA |= _BV(ADSC);
  while (bit_is_set(ADCSRA,ADSC));
  readTemp = ADCL;
  readTemp |= ADCH<<8;
  innertemp = (readTemp - 125) * 1075; // temp in x10^-4 degC
  innertemp = innertemp / 10000; // temp in degC
  return innertemp;
} 

// Mide la temperatura y humedad ambiental y calcula el punto de rocío
void temphumroc(){
  SH15.measure(&ambtemp, &humedad, &TRocio);
}

// Lee la irradiancia (TSL235R)
void radiacion(){
  volatile long pulsos = 0;
  for (int i=0; i <= 10; i++){
    FreqCounter::f_comp = 10;
    FreqCounter::start(periodo1);  
    while (FreqCounter::f_ready == 0)
    pulsos=FreqCounter::f_freq;
    delay(20);
  }
  irrad = (pulsos*1000)/(periodo1*area1*1000);
  return;
}

// Lee la temperatura superficial (DS18B20)
float temperatura() {
  sensors.requestTemperatures();
  tempext=sensors.getTempCByIndex(0);
  return tempext;
}

// Mide la humedad del suelo
int sueloH(){
  suelohum=analogRead(suelo);                // Read the sensor
  suelohum=(suelohum*0.1904761905);          // Calculate soil moisture from the lecture*100/525
  return suelohum;
}

// Mide la temperatura del suelo (DS18B20)
void suelotemp() {
  sensors2.requestTemperatures();
  TSAr=sensors2.getTempCByIndex(0);
  TSAb=sensors2.getTempCByIndex(1);  
  return;
}

// Mide la luminosidad (LDR)
unsigned int luminosidad(){
  float photocellReading0 = analogRead(luz);        // Read the analogue pin
  float Vout0=photocellReading0*0.0048828125;       // calculate the voltage
  lux=500/(10*((5-Vout0)/Vout0));                   // calculate the Lux 
  return lux;
}

// Mide la intensidad de lluvia (disdrómetro)
unsigned long midegotas() {
  volatile unsigned long gotas=0;
  unsigned long millis();
  long startTime = millis();                        // mide el numero de gotas en 30 segundos
  while(millis() < startTime + 30000) {
     int sensorReading = analogRead(lluvia);
     if (sensorReading >= sensibilidad) {
         gotas=gotas+1;    
     }
  }
  intensidad = ((gotas / area2) / 30);              // calcula la intensidad de la lluvia en gotas/m2/sec
}

// Mide la velocidad del viento
void velocidadviento(){
  BWCounter = 0;  
  attachInterrupt(1, addcount, CHANGE);
  unsigned long millis();                     
  long startTime = millis();
  while(millis() < startTime + periodo2) {
  }
  detachInterrupt(1);
  unsigned int RPM=((BWCounter/2)*60)/(periodo2/1000);  // Calculate revolutions per minute (RPM)
  velviento = ((pi * diametro * RPM)/60) / 1000;      // Calculate wind speed on m/s
}

// Contaje de pulsos anemómetro
void addcount(){
  BWCounter++;
}

// Graba los datos en formato ASCII en una memoria flash SD
void grabar(){ 
  // It works... i removed to save space in the forum
  // Muestra los datos en el puerto serie
  Serial.print(message);
  return;
}

Excuse to paste here all the code, but in this way you have all the information and not only the partial one...
Thanks![/code]

okay, i made it simpler...

I have this pseu-docode:

Libraries, constants and variables go here

setup
configure everything

Loop{
sleep()
}


sleep(){
active interrupt
go to sleep
here is sleeping until to receive an alarm or to receive data from the serial port
get up()
stop the interrupt
tasks()
}

get up(){
copy what receives from serial to a char variable
}

tasks(){
if chart starts by "M": do measurements from all sensors and show it in the serial port
if chart starts by "T": adjust the RTC time and date
If chart starts by "D": dump file stored in the SD card and send it by the serial port
in any other case, measure from all sensor, show result in the serial port, and save the data into an SD card.
}

Here goes the other processes to do M, T and D tasks

So, the question is if this configuration (where the processes that read what arrive through the serial port and to decide what task must be done are located) is correct.

I don't know whether that use of the interrupt will interfere with the serial port driver. It might be OK, but would be worth checking.

What may be going wrong is that the interrupt is triggering on the first bit received and your handler executes before there are whole bytes available.

Perhaps after the interrupt fires you could wake your sketch and then wait for serial input with a short timeout before deciding which action to take.

Ok. Thanks PeterH,

I will try somethig like this (in pseudo-code):

Libraries, constants and variables go here

setup
configure everything

Loop{
sleep()
}


sleep(){
active interrupt
go to sleep
here is sleeping until to receive an alarm or to receive data from the serial port
get up()
stop the interrupt
Listen the serial port()
}

get up(){
do nothing
}

listen the serial port(){
  for (int i=o; int<5000; i++){    (about 5 seconds?)
     c = Serial.read();
  }
 if chart starts by "M": do measurements from all sensors and show it in the serial port
 if chart starts by "T": adjust the RTC time and date
 If chart starts by "D": dump file stored in the SD card and send it by the serial port in any other case, measure from all sensor, show result in the serial port, and save the data into an SD card.
}

Then, i must send a byte by the serial port to wake arduino up, and then i have 5 seconds to send the command to request to arduino do develop a specific task. If in that time does not receive news (bytes) from the serial port then, comes to measure and sleep again...

I will try and report here the results. Thanks again!