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:
#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();
}
}