Go Down

Topic: Question about sleeping and loop (Read 760 times) previous topic - next topic

madepablo

Jun 12, 2012, 08:27 pm Last Edit: Jun 12, 2012, 08:30 pm by madepablo Reason: 1
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: [Select]
[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]

madepablo

#1
Jun 13, 2012, 09:34 am Last Edit: Jun 13, 2012, 09:36 am by madepablo Reason: 1
okay, i made it simpler...

I have this pseu-docode:
Code: [Select]


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.

PeterH

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.
I only provide help via the forum - please do not contact me for private consultancy.

madepablo

#3
Jun 13, 2012, 04:31 pm Last Edit: Jun 13, 2012, 04:49 pm by madepablo Reason: 1
Ok. Thanks PeterH,

I will try somethig like this (in pseudo-code):
Code: [Select]
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!

Go Up