Hello,
I want to make a power saving watering system with a deep_sleep_mode.
The problem is, that the sleep_cpu() method of the <avr/sleep.h> library somehow resets my whole program each time the watchdogTimer wakes it up.
Thanks in advance for your advice!
#include <avr/sleep.h>
#include <avr/wdt.h>
int led;
int motor; //TODO! Testing value
long timePointer1;
long n;
bool awake;
bool menuOn;
void setup() {
wdt_disable();
attachInterrupt(0, interruptFunction, RISING); //Digital Pin 2 //Not used for testing //always LOW
pinMode(led,OUTPUT);
led=13; //I also tried to assign the values on top of setup() as normal. The program always starts
//from the beginning
motor=12;
timePointer1=1;
n=0;
awake=0;
menuOn=0;
Serial.begin(9600);
Serial.print("Setup ");
Serial.println();
Serial.end();
}
void loop() {
if((digitalRead(2)==HIGH || menuOn==1)&&awake==0){ //Menu // not turned on for testing
menuOn=0;
}
if(digitalRead(2)==LOW && awake==1 ){ //Time controlled event
watering();
}
if(awake==0 && digitalRead(2)==LOW){
longDelayWDT(40);
}
}
void interruptFunction(){ //Not used for testing purpose
//sleep_disable();
//detachInterrupt(0); //turns Interrupts off
}
ISR(WDT_vect){
wdt_disable();
//MCUSR=0; //clear WDT flag (optional)
}
void delayWDT(byte timer){
sleep_enable();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
ADCSRA &= ~(1<<ADEN);
wdt_enable(timer);
wdt_reset();
sleep_cpu(); //Here is the Problem!
sleep_disable();
ADCSRA |= (1<<ADEN);
}
void longDelayWDT(long t){
//t in seconds
//n=(long)(t/8); //To be added later
n=3; //Testing value. To be removed
if(timePointer1>=n-1){
Serial.begin(9600);
Serial.print("TimePointer>=n-1 ");
Serial.println(timePointer1);
Serial.end();
timePointer1=0;
awake=1;
}
if(timePointer1<n && awake==0){
Serial.begin(9600);
Serial.print("TimePointer: ");
Serial.println(timePointer1);
Serial.end();
timePointer1++;
Serial.begin(9600);
Serial.print("TimePointer: ");
Serial.println(timePointer1);
Serial.end();
delayWDT(WDTO_1S); //Testing Value: TODO Change to 8s
}
}
void watering(){
long t;
noInterrupts();
digitalWrite(motor,HIGH);
delay(t*1000);
digitalWrite(motor,LOW);
interrupts();
awake=0;
}
PaulS:
delay() doesn't work with interrupts disabled. It needs for the clock to tick, which means that an interrupt needs to happen.
Thank you for the reply. I changed it in my code.
Do you have any idea, why the program resets itself when i run sleep_cpu()?
It is strange because normally it should just wake up at the same point if you interrupt it.
You’re configuring the WDT to act as a reset source rather than an interrupt source. I don’t know that the wdt library provides a wrapper around configuring it for interrupts - I know that construction just turns it on as a reset source.
DrAzzy:
You’re configuring the WDT to act as a reset source rather than an interrupt source. I don’t know that the wdt library provides a wrapper around configuring it for interrupts - I know that construction just turns it on as a reset source.
Thank you DrAzzy! After your reply I researched for the workaround and found out that the WDT is normally set to reset mode. I changed the WDIE and WDE bits in the WDTCSR – Watchdog Timer Control Register of the ATMEGE328P Microcontroller to enable the interrupt mode and disable the reset mode for the Watchdog timer. I changed it in my code and now it is running as I want it to
Small part of the code, which is relevant to change the register:
void delayWDT(byte timer){
sleep_enable();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
ADCSRA &= ~(1<<ADEN);
wdt_enable(timer);
WDTCSR = (1 <<WDIE) | (0<<WDE); //Interrupt Enable, Reset Disable, This is the solution for my problem
wdt_reset();
sleep_cpu();
sleep_disable();
ADCSRA |= (1<<ADEN);
}
Complete code with some minor debugging changes: (Don’t mind that I always turn on and off the Serial communication. It can eventuelly interfer with the interrupts otherwise.)
#include <avr/sleep.h>
#include <avr/wdt.h>
int led;
int motor; //TODO! Testing value
long timePointer1;
long n;
bool awake;
bool menuOn;
void setup() {
wdt_disable();
attachInterrupt(0, interruptFunction, RISING); //Digital Pin 2
pinMode(led,OUTPUT);
led=13;
motor=12;
timePointer1=0;
n=0;
awake=0;
menuOn=1;
Serial.begin(9600);
Serial.print("Setup ");
Serial.println();
Serial.end();
}
void loop() {
if((digitalRead(2)==HIGH || menuOn==1)&&awake==0){ //Menu
menuOn=0;
Serial.begin(9600);
Serial.println("Menu ");
Serial.end();
delay(500);
}
if(digitalRead(2)==LOW && awake==1 ){ //Time controlled event
watering();
}
if(digitalRead(2)==LOW){ //Test State
Serial.begin(9600);
Serial.println("Power LOW");
Serial.end();
}
if(digitalRead(2)==HIGH){ //Test State
Serial.begin(9600);
Serial.println("Power HIGH");
Serial.end();
attachInterrupt(0, interruptFunction, RISING);
}
if(awake==1){ //Test Blink
Serial.begin(9600);
Serial.println("Awake");
Serial.end();
}
if(awake==0 && digitalRead(2)==LOW){
longDelayWDT(40);
}
}
void interruptFunction(){
sleep_disable();
detachInterrupt(0); //turns Interrupts off
Serial.begin(9600);
Serial.println("Interrupt");
Serial.end();
}
ISR(WDT_vect){
wdt_disable(); //TODO: should it be in the code?
//MCUSR=0; //clear WDT flag (optional)
}
void delayWDT(byte timer){
sleep_enable();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
ADCSRA &= ~(1<<ADEN);
wdt_enable(timer);
WDTCSR = (1 <<WDIE) | (0<<WDE); //Interrupt Enable, Reset Disable
wdt_reset();
sleep_cpu();
sleep_disable();
ADCSRA |= (1<<ADEN);
}
void longDelayWDT(long t){
//t in seconds
n=(long)(t/8); //To be added later
//n=5; //Testing value. To be removed
if(timePointer1>=n){
Serial.begin(9600);
Serial.println("Restarting queue");
//Serial.println(timePointer1);
Serial.end();
timePointer1=0;
awake=1;
}
if(timePointer1<n && awake==0){
Serial.begin(9600);
Serial.print("TimePointer: ");
Serial.println(timePointer1);
Serial.end();
timePointer1++;
delayWDT(WDTO_8S); //Testing Value: TODO Change to 8s
}
}
void watering(){
long t;
digitalWrite(motor,HIGH);
delay(t*1000);
digitalWrite(motor,LOW);
Serial.begin(9600);
Serial.print("Watering");
Serial.println();
Serial.end();
awake=0;
}
From my side the topic is now closed and solved. Thank you all for your effort and help! If you have any more questions don’t hestiate to ask.