Hello,
My goal is to create code that;
drives a servo to sweep from 0 to 180---->
Goes to sleep for ~ 5 minutes -->
sweep the servo from 180 to 0 --- >
Goes to sleep for 5 minutes ---- >
repeat over and over.
I have the sweep part down- lets not worry about that.
My question is on the terminology of Reset vs, resume.- I am using the following code and it is working 1/2 way----
It will sweep as expected from 0 to 180, ---- but then resets itself quickly back to 0, wait the 8 seconds and star the 0 to 180 sweep at the proper speed.
I was aiming to have the WDT wake up and resume the loop of the code but I feel it is resetting on wakeup.
I am wrong in thinking there would be a way to get the WTD to resume the code?
or
Is there a better mechanism to achieve this. Power consumption is the key here. Also would prefer not adding an external clock if I can get away from it.
Extra credit---- Once I get this working, I want to stretch out the sleep duration to the 5 minutes ( not trying to do that here. Glad to take guidance on that method.
I will also not that there seems to be a few ways of writing this out that I have seen. Confusing for a neophyte such as myself
Thanks
// This is an example how to put an arduino board into deep sleep to save on battery power and
// periodically wake up to run some logic. Ideal for sensor stations like plant moisture sensors.
#include "Arduino.h"
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
#include <Servo.h>
// Blink Before sleeping
#define LED_PIN (13)
Servo myservo; // create servo object to control a servo
int pos = 0; // variable to store the servo position
// This variable is made volatile because it is changed inside
// an interrupt function
volatile int f_wdt = 1;
// Watchdog Interrupt Service. This is executed when watchdog timed out.
ISR(WDT_vect) {
if (f_wdt == 0) {
// here we can implement a counter the can set the f_wdt to true if
// the watchdog cycle needs to run longer than the maximum of eight
// seconds.
f_wdt = 1;
}
}
// Enters the arduino into sleep mode.
void enterSleep(void) {
// There are five different sleep modes in order of power saving:
// SLEEP_MODE_IDLE - the lowest power saving mode
// SLEEP_MODE_ADC
// SLEEP_MODE_PWR_SAVE
// SLEEP_MODE_STANDBY
// SLEEP_MODE_PWR_DOWN - the highest power saving mode
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
// Now enter sleep mode.
sleep_mode();
// The program will continue from here after the WDT timeout
// First thing to do is disable sleep.
sleep_disable();
// Re-enable the peripherals.
power_all_enable();
}
// Setup the Watch Dog Timer (WDT)
void setupWatchDogTimer() {
// The MCU Status Register (MCUSR) is used to tell the cause of the last
// reset, such as brown-out reset, watchdog reset, etc.
// NOTE: for security reasons, there is a timed sequence for clearing the
// WDE and changing the time-out configuration. If you don't use this
// sequence properly, you'll get unexpected results.
// Clear the reset flag on the MCUSR, the WDRF bit (bit 3).
MCUSR &= ~(1 << WDRF);
// Configure the Watchdog timer Control Register (WDTCSR)
// The WDTCSR is used for configuring the time-out, mode of operation, etc
// In order to change WDE or the pre-scaler, we need to set WDCE (This will
// allow updates for 4 clock cycles).
// Set the WDCE bit (bit 4) and the WDE bit (bit 3) of the WDTCSR. The WDCE
// bit must be set in order to change WDE or the watchdog pre-scalers.
// Setting the WDCE bit will allow updates to the pre-scalers and WDE for 4
// clock cycles then it will be reset by hardware.
WDTCSR |= (1 << WDCE) | (1 << WDE);
/**
* Setting the watchdog pre-scaler value with VCC = 5.0V and 16mHZ
* WDP3 WDP2 WDP1 WDP0 | Number of WDT | Typical Time-out at Oscillator Cycles
* 0 0 0 0 | 2K cycles | 16 ms
* 0 0 0 1 | 4K cycles | 32 ms
* 0 0 1 0 | 8K cycles | 64 ms
* 0 0 1 1 | 16K cycles | 0.125 s
* 0 1 0 0 | 32K cycles | 0.25 s
* 0 1 0 1 | 64K cycles | 0.5 s
* 0 1 1 0 | 128K cycles | 1.0 s
* 0 1 1 1 | 256K cycles | 2.0 s
* 1 0 0 0 | 512K cycles | 4.0 s
* 1 0 0 1 | 1024K cycles | 8.0 s
*/
WDTCSR = (1 << WDP3) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0);
// Enable the WD interrupt (note: no reset).
WDTCSR |= _BV(WDIE);
}
// Setup for the serial comms and the other things
void setup() {
Serial.begin(9600);
Serial.println("Initialising...");
delay(100);
pinMode(LED_PIN, OUTPUT);
setupWatchDogTimer();
Serial.println("Initialisation complete.");
delay(100);
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
// main loop
void loop() {
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(80); // waits xxxms for the servo to reach the posit
}
// Wait until the watchdog have triggered a wake up.
if (f_wdt != 1)
return;
// Toggle the LED on
digitalWrite(LED_PIN, 1);
// wait
delay(200);
// Toggle the LED off
digitalWrite(LED_PIN, 0);
// clear the flag so we can run above code again after the MCU wake up
f_wdt = 0;
// Re-enter sleep mode.
enterSleep();
{
for (pos = 180; pos >= 0; pos -= 1) // goes from 180 degrees to 0 degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(80); // waits xxxms for the servo to reach the position
}
// Wait until the watchdog have triggered a wake up.
if (f_wdt != 1) {
return;
}
// Toggle the LED on
digitalWrite(LED_PIN, 1);
// wait
delay(200);
// Toggle the LED off
digitalWrite(LED_PIN, 0);
// clear the flag so we can run above code again after the MCU wake up
f_wdt = 0;
// Re-enter sleep mode.
enterSleep();
}