I am using the Arduino uno and the Catalex SD card reader.
This sketch uses the watchdog timer for a 8 second period, an SD card to write an output file and a print to the serial monitor for troubleshooting. The sketch blinks an LED for about .8 sec, there is a 1.2 sec delay, then the chip is put on low power for 8 seconds. I'm seeing an anomaly between the SD file and the serial printout especially with respect to the loop counter 'j'. On the serial monitor I get a smooth progression in 'j' from 1,2,3,4,...etc. as I expect. But on the SD file, the 'j' counter jumps around, eg, 1,2,1,1,2,1,2,3 before settling down to the expected progression 1,2,3,4,5,6,etc. Sometimes it even starts over again later in the progression. It's almost like the watchdog is doing some sort of timeout reset before settling down but if that's the case why the difference between the SD file and the serial monitor. It's pretty frustrating. I have no idea the cause but I've tried different things to no avail.
Any help would be greatly appreciated. This is my first use of the watchdog timer and an SD card but I'm not sure if it's the problem.
Thanks for any assistance and insight you can give.
// This version builds on the previous CitizenSensing file plus SD card and 12 hour circuit
// In this sketch, the LED's flash every 10 seconds, then at each 12 hour period, the relay is activated
// for 12 seconds (2 times per day).
// The SD card routine based largely on Aaron Lee's Tutorial
// Source: Aaron Lee Youtube: "Arduio Tutorial Lesson 5.1 - SD Card Write"
#include <SD.h>; // Arduino SD card library
#include <SPI.h>; // Although not shown in Aaron's tutorial, it is shown on some others. Will not compile
// without it in this sketch
/*
* This sketch write text data to an SD card
* Our SD card communicatres over the following pins
* MOSI = pin 11 : This pin cannot be changed (SPI protocol requires this pin - assigned by library?)
* MISO = pin 12 : This pin cannot be changed (SPI protocol requires this pin - assigned by library?)
* Clock = pin 13 : This pin cannot be changed (SPI protocol requires this pin - assigned by library?)
* Chip Select = pin 10 : This pin CAN be changed - ie yours may be different
*/
File myFile; // Create a data file for the SD card routine
// Source: citizen-sensing.org/2013/07/arduino-watchdog/ plus added code by JimC for LED routine
// Also I put the Source: code and created a function called sleepNow().
// Check this out for good explanation on the Watchdog timer and code.
// http://www.leonardomiliani.com/en/2013/impariamo-ad-usare-il-watchdog-2/
// SEE NOTE at the end on WDT reset issue
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
int j = 1; // loop counter
int prevJ = 0; // previous j value
float timePass = 0.0; // cummulative time
float hourSet = 12.0; // Set for 1/2 day (every 12 hours) relay activation cycle
float hourSetPrev = 0.0; // Previous hourSet
// Create sleepNow function
void sleepNow() {
wdt_reset();
wdt_disable();
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Selecting the lowest power setting
// Set watchdog parameters
MCUSR &= ~(1<<WDRF); // reset status flag
WDTCSR |= (1<<WDCE) | (1<<WDE); // required to enable configuration changes
WDTCSR = (1<<WDP0) | (1<<WDP3); // set the pre-scalar for 10, ie 8 seconds delay
WDTCSR |= (1<<WDIE); // enable interrupt mode
// Disable the ADC
ADCSRA &= ~(1<<ADEN); // Set bit 7 in ADC register to 1 to disable the ADC - Source Kevin Darrah - the '~' invert symbol flips the bits so after
// setting bit 7 to 1, all the bits are flipped setting all other bits to 1 and bit 7 to 0
// Ready for sleep
sleep_enable(); // Enable sleep function
sleep_mode(); // Go to sleep. Will wake up upon interrupt activation via Watchdog timer in this sketch.
// disable sleep after waking up
sleep_disable(); // Disable sleep for now after Watchdog timer interrupt activation
}
void setup() {
pinMode(4, OUTPUT); // set pin 4 as output for LED
pinMode(7, OUTPUT); // set pin 7 as output for relay
Serial.begin(9600);
Serial.println("Initializing the SD card..."); // Print message so we know where we are at
if (!SD.begin(10)) // if statement to test for SD initialization. The "10" refers to the chip select pin
// and specifies which chip we are talking to. Otherwise program goes to the first chip it finds.
{
Serial.println("Initialization failed!!!"); // ie, if SD.begin(10) not true
return; // stops program here - exits the setup function and doesn't proceed
}
Serial.println("Initialization complete.");
}
void loop() {
myFile = SD.open("pumpLog.txt", FILE_WRITE); // OPEN (create if does not exist already) the file to open it
if (myFile) { // check if opened
Serial.println("SD file opened successfully");
myFile.println("SD File opened successfully"); // print to SD that file opened successfully
myFile.print("J counter = ");
myFile.print(j); // Print j counter to SD file
myFile.print(" - timePass / hourSetPrev / hourSet = ");
myFile.print(timePass);
myFile.print(" / ");
myFile.print(hourSetPrev);
myFile.print(" / ");
myFile.println(hourSet);
// Trouble shooting printout
Serial.print("J counter = ");
Serial.print(j); // Print j counter to SD file
Serial.print(" - timePass / hourSetPrev / hourSet = ");
Serial.print(timePass);
Serial.print(" / ");
Serial.print(hourSetPrev);
Serial.print(" / ");
Serial.println(hourSet);
myFile.close(); // Must close file after writing to it.
} else {
Serial.println("Error in opening file");
}
// LED loop and period counter
for (int i = 0; i < 2; i++) {
digitalWrite(4, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for 0.2 sec
digitalWrite(4, LOW); // turn the LED off by making the voltage LOW
delay(200); // wait for 0.2 second
}
delay(1200); // Total LED flash loop and this delay equals to 2 sec
sleepNow(); // Start sleep/Watchdog routine
timePass = ((2.0 + 8.0)*j)/3600.; // 2 seconds per LED flash loop + 8 second watchdog low power setting. timePass is the cummulative fraction of 1 hour
// ie, 10 seconds occurs 6 times a minute x 60 minutes per hour
// Trouble shooting printout
Serial.print("Time passed = ");
Serial.println(timePass);
prevJ = j;
j = prevJ + 1; // 'j' is the multiplier counter used to increment the cummulative timePass period. It never resets to zero.
// Trouble shooting printout
Serial.print("The values of prevJ and j are ");
Serial.print(prevJ);
Serial.print(" and ");
Serial.println(j);
if (timePass > hourSet) { // When timePass exceeds each 12 hour period, sketch then activates the relay for 12 seconds
digitalWrite(7, HIGH); // Turn on relay
delay(12000); // Activate relay for 12 seconds
digitalWrite(7,LOW);
hourSetPrev = hourSet;
hourSet = hourSetPrev + 12.0; // Reset for next 12 hours
// Trouble shooting printout
Serial.print("hourSet / hourSetPrev = ");
Serial.print(hourSet);
Serial.print(" / ");
Serial.println(hourSetPrev);
}
}
ISR (WDT_vect) {
}
// The problem is that a RESET does not turn off the watchdog timer once it has been turned on, and neither does the bootloader. So you set
// things up to have the watchdog cause a reset in 15ms, and the reset occurs. Now the bootloader starts up, and starts its LED-flashing, and
// OOPS another 15ms has gone by with no one feeding the watchdog, and it resets again. This repeats until a power cycle turns off the watchdog.
// (This behavior is explicitly described in the ATmega datasheet...)