Go Down

Topic: SD Card and Watchdog Timer (Read 319 times) previous topic - next topic

christian_n

Dear all,

I am in the process of building a solar powered beehive scale. In order to save power, I want to put the Arduino to sleep for most of the time and only wake it when needed for measurements. I'm doing this using watchdog interrupts as described by Nick Gammon here Power Saving Techniques and here Extend Watchdog Timer beyond 8s.

I'm saving the weight measurement data on a micro SD card using a code provided by Paul McWhorter here logging data on SD card. Unfortunately, I only get one log on the SD card. If I comment the watchdog interrupts out, all weight measurements are logged onto the SD card. So the problem is clearly with the watchdog interrupts. I've already checked whether connection to the SD card is lost after sleep mode - that does not seem to be the case.

Any ideas how to solve this problem?

Here's the code I'm using:

Code: [Select]
#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
#include <avr/wdt.h>      // Watchdog timer
#include "HX711.h"
#include <SPI.h>
#include <SD.h>


#define calibration_factor 27830 //This value is obtained using the SparkFun_HX711_Calibration sketch
//#define zero_factor 8421804 /* This large value is obtained using the SparkFun_HX711_Calibration sketch. Brauche ich nicht, weil ich den zero factor im setup neu bestimme */


#define DOUT  3
#define CLK  4
HX711 scale(DOUT, CLK);

#include <TimeLib.h>
#include <DS1302RTC.h>
tmElements_t tm;

// Set pins:  CE, IO,CLK
DS1302RTC RTC(8, 7, 6);

// brauche ich, um RTC, HX711 und SD-Modul nur dann mit Spannung zu versorgen, wenn sie gebraucht werden.
#define VCC_PIN 5

int i;
int h; //variable used to save hours from RTC module
float weight;

int chipSelect=10; // CS pin of SD-Module
File mySensorData; //variable for working with file data

// watchdog interrupt
ISR(WDT_vect)
  {
  wdt_disable();  // disable watchdog
  }


// function for sleep mode and watchdog interrupt
void myWatchdogEnable(const byte interval)
  { 
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  set_sleep_mode (SLEEP_MODE_PWR_DOWN); 
  ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  sleep_enable ();       // ready to sleep
  sleep_mode();            // now goes to Sleep and waits for the interrupt
  sleep_cpu ();          // sleep
  }

//function for time conversion:

void print2digits(int number) {
  if (number >= 0 && number < 10)
    mySensorData.write('0');
  mySensorData.print(number);
}

void setup() {
 
  pinMode(VCC_PIN, OUTPUT);
  digitalWrite(VCC_PIN, HIGH); //power up the modules such as precautionary measure in case that is required for setup
 
 //Serial.begin(9600);

  SD.begin(chipSelect); //initialize the SD card

  pinMode(chipSelect, OUTPUT); //Pin 10 always has to be put to "output", otherwise the SD-card module doesn't work (required by SD library)

  delay(500);

  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch

  long zero_factor = scale.read_average(); //Get a baseline reading
  delay(500); //allow time for scale baseline reading to determine zero_factor --> maybe make it longer
  scale.set_offset(zero_factor); //Zero out the scale using a previously known zero_factor
  i=0;
  h=0;

  digitalWrite(VCC_PIN, LOW); //power down modules to save power. They will now only be powered up when needed.
 
}

//put the arduino to sleep for the night (12 h)
void night() {
  for (i = 0; i <=4319; i++)
  { 
    myWatchdogEnable (0b100001);  // 8 seconds
    myWatchdogEnable (0b000111);  // 2 seconds
    //myWatchdogEnable (0b000110);  // 1 second
  }

  i=0;
  sleep_disable ();      // precaution
  power_all_enable ();   // power everything back on
}

//wake the arduino every 0.5h for measurement during the day
void daytime() {
  for (i = 0; i <=179; i++)
  { 
    myWatchdogEnable (0b100001);  // 8 seconds
    myWatchdogEnable (0b000111);  // 2 seconds
    //myWatchdogEnable (0b000110);  // 1 second
  }

  i=0;
  sleep_disable ();      // precaution
  power_all_enable ();   // power everything back on
}

void loop() {
 // measurements occur here:
 //power up the RTC, HX711 and SD-Module and give some time to settle
 
 
  h=0; //reset variable h
 
  digitalWrite(VCC_PIN, HIGH);
  delay(1000);

//Wake the HX711, give some time to settle and then print weight:
  //Serial.println("Powering up...");
  //scale.power_up();
 
  //get the weight from the scale
 
  weight=scale.get_units(), 2; //scale.get_units() returns a float
 
  /*
  Serial.print("Reading: ");
  Serial.print(scale.get_units(), 2); //scale.get_units() returns a float
  Serial.print(" kg");
  Serial.println();
  */

//Put the HX711 back to sleep mode
  //Serial.println("Powering down...");
  //scale.power_down();
  //Serial.println();
  //delay(2000);


  //here we print the time from the RTC module:
  //Serial.print("UNIX Time: ");
  //Serial.print(RTC.get());
  //Serial.print(tm.Day);

mySensorData=SD.open("data.txt", FILE_WRITE); //create file "data.txt" as a file to write to
 
//print the weight to the SD card
mySensorData.print(weight);
mySensorData.print(" kg,");

//print the time to the SD card
  if (! RTC.read(tm)) {
    mySensorData.print("Time = ");
    print2digits(tm.Hour);
    mySensorData.write(':');
    print2digits(tm.Minute);
    mySensorData.write(':');
    print2digits(tm.Second);
    mySensorData.print(", Date (D/M/Y) = ");
    mySensorData.print(tm.Day);
    mySensorData.write('/');
    mySensorData.print(tm.Month);
    mySensorData.write('/');
    mySensorData.print(tmYearToCalendar(tm.Year));
    //Serial.print(", DoW = ");
    //Serial.print(tm.Wday);
    mySensorData.println();
  }

mySensorData.close(); //close the file

//now the power is cut from the RTC, HX711 and SD-Module:
  digitalWrite(VCC_PIN, LOW);

//set the variable h to the present hour
  h=tm.Hour;
 
// sleep for 1h provided time is between 6h and 18h
  if(h<=17 && h>=6){
    daytime();
  }
 
// sleep for the night
  else{
    night();
  }


}



PaulS

Quote
So the problem is clearly with the watchdog interrupts.
No. The problem is that when you wake up, you don't restore everything properly.

Code: [Select]
  weight=scale.get_units(), 2; //scale.get_units() returns a float
You are abusing the comma operator. weight will ALWAYS be 2, with this code.

Just because Serial.print(scale.get_units(), 2) does something does NOT mean that weight=scale.get_units(), 2 will do the same thing.

You probably need to initialize the SD card when you need to write to it again after your nap.
The art of getting good answers lies in asking good questions.

Go Up