How to wake up after sleep mode using the millis() function

Hello i use the millis() function to count a delay, and i want to have a switch for on - off, on time LOW the the millis should be start count, another one time LOW should be stop cound and go for sleep for save energy (because i use battery),

My problem is when the device start and blink the led i press the switch to LOW and the device going to sleep when i press it again then never wakeup, what i am doing wrong ? or what i miss it ?

#include <avr/sleep.h>

int led = 13;
int wakepin = 2;
boolean flag = false;

unsigned long time = 0;


void wakeupnow(){
	flag = true;
}

void setup(){

	pinMode(led,OUTPUT);
	pinMode(wakepin,INPUT);
	attachInterrupt(0,wakeupnow,LOW);
}

void sleepnow(){
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();
	attachInterrupt(0,wakeupnow,LOW);
	sleep_mode();
	
	sleep_disable();
	//detachInterrupt(0);
	delay(1000);
	flag = false;
}

void loop(){
	if (millis() - time > 1000){
		time = millis();
		digitalWrite(led,HIGH);
		delay(500);
		digitalWrite(led,LOW);
	}
	
	if (flag == true) {
		sleepnow();
		flag = false;
	}
}

Thank you in advance.

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

Please post code between code tags using the # button.

One thing I notice is that pin 2 should have a pullup resistor. So I'd enable the internal pullup, unless there is an external pullup. In fact it's a good idea to do this on all unused pins to minimize power consumption (see code below). To reduce power consumption even further during sleep mode, consider turning off the analog-to-digital converter and the brown-out detector.

void makePinsInput()
{
    for (byte i=0; i<20; i++) {
        pinMode(i, INPUT);        //make all pins input pins
        digitalWrite(i, HIGH);    //with pullup resistors to minimize power consumption
    }
    pinMode(13, OUTPUT);          //except the LED pin
    digitalWrite(13, LOW);
}

It sort of works for me. I connected the switch between pin 2 and ground, with an external pullup resistor to +5v. It's hard to get it to sleep because I have to press the switch while the LED is on and release it before the LED goes off, otherwise pin 2 is still low when it enters sleep mode and it wakes up immediately. But when I do get it to sleep, pressing the button wakes it up again.

@dc42, good point. A technique I use is to not enable the interrupt until just before going to sleep. While not sleeping, I just use ordinary techniques to read the switch. The ISR disables further interrupts from the switch.

I have test with the external resistor and the internal but no change does that @dc42 say,i have confuse my self i try so many changes and i am lost ...

This is another situation where delay() can cause trouble, specifically, it will delay the system's ability to respond to the pushbutton. You've got the basic technique to avoid using delay() here:

   if (millis() - time > 1000){
      time = millis();

It just needs to be made to operate to turn the LED both on and off.

Step back and rather than writing code, chart out what needs to be done, e.g.

loop() can just do something like:

Is the button pushed?
If YES, then go to sleep.
If NO, then is it time to turn the LED on or off?

Now have one function for blinking the LED, and one for going to sleep.

gotoSleep():

Wait for the button to be released.
Enable the interrupt.
Go to sleep.
(Wake up)
Disable the interrupt.

blinkLED():

...is left as an exercise for the reader XD

PS: I didn't provide for any switch debouncing. Depending on the switch, YMMV. But in this case we can probably get away with a fairly crude approach. A small delay would be ok in this case, shorter than human perception time but long enough for the switch to stop bouncing, so:

gotoSleep():

Wait for the button to be released.
Delay ~20 ms, else a bounce may wake the MCU immediately after the interrupt is enabled.
Enable the interrupt.
Go to sleep.
(Wake up)
Disable the interrupt.

@Jack I think you give me the light :wink:

I thing now it is working :.

#include <avr/sleep.h>

int led = 13;
int wakepin = 2;
boolean flag = false;

unsigned long time = 0;


void wakeupnow(){
	flag = true;
}

void setup(){
	pinMode(led,OUTPUT);
	pinMode(wakepin,INPUT);
	digitalWrite(wakepin,HIGH);
	attachInterrupt(0,wakeupnow,LOW);

}

void sleepnow(){
	while (digitalRead(wakepin) == LOW)
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();
	attachInterrupt(0,wakeupnow,LOW);
	sleep_mode();
	
	sleep_disable();
	delay(1000);
	//detachInterrupt(0);
	flag = false;
}

void loop(){
	//cli();
	if (millis() - time > 1000){
		time = millis();
		digitalWrite(led,HIGH);
		delay(500);
		digitalWrite(led,LOW);
	}
	
	if (flag == true) {
		sleepnow();
		flag = false;
	}
}

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

After some test i do i see when i press the button when the led it is on the system it is not going always for sleep ...do i miss something ?

Do i have to disable the interrupts ? or do i must use the digitalRead function to check for the pin ?

tasosstr:
After some test i do i see when i press the button when the led it is on the system it is not going always for sleep ...do i miss something ?

See reply #5.

Thank you my friends for the help, i thing now it is working .....

#include <avr/sleep.h>

int led = 13;
int wakepin = 2;
boolean flag = false;

unsigned long time,stay = 0;

void wakeupnow(){
	flag = true;
}

void setup(){
	pinMode(led,OUTPUT);
	pinMode(wakepin,INPUT);
	digitalWrite(wakepin,HIGH);
	attachInterrupt(0,wakeupnow,LOW);
}

void sleepnow(){
	while (digitalRead(wakepin) == LOW)
	digitalWrite(led,LOW);
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();
	attachInterrupt(0,wakeupnow,LOW);
	sleep_mode();
	
	sleep_disable();
	time = millis();
	delay(1000);
	//detachInterrupt(0);
	flag = false;
}

void loop(){
	if (millis() - time > 1000){
		time = millis();
		digitalWrite(led,HIGH);
		//delay(500);
		stay = millis();
	}
		
	if  (millis() - stay > 500)	digitalWrite(led,LOW);
	
	if (flag == true) {
		flag = false;
		sleepnow();
	}
}

The last issue it was when i was press the button when the led it was on (On delay....) i change the delay with millis and now it looks ok
and i use the bellow code to wait the relase of the button :slight_smile:

void sleepnow(){
while (digitalRead(wakepin) == LOW); <-- here is the check.

Moderator edit: ditto.

Good deal. One more thing, when posting code, people like to see it between code tags. This is done with the # button when composing the post.

char msg[] = "So the code ends up in a box like this.";

Thank you my friend i try to do it now :slight_smile:

#include <avr/sleep.h>

int led = 13;
int wakepin = 2;
boolean flag = false;

unsigned long time,stay = 0;

void wakeupnow(){
	flag = true;
}

void setup(){
	pinMode(led,OUTPUT);
	pinMode(wakepin,INPUT);
	digitalWrite(wakepin,HIGH);
	attachInterrupt(0,wakeupnow,LOW);
}

void sleepnow(){
	while (digitalRead(wakepin) == LOW)
	digitalWrite(led,LOW);
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();
	attachInterrupt(0,wakeupnow,LOW);
	sleep_mode();
	
	sleep_disable();
	time = millis();
	while (digitalRead(wakepin) == LOW)
	//delay(1000);
	//detachInterrupt(0);
	flag = false;
}

void loop(){
	if (millis() - time > 1000){
		time = millis();
		digitalWrite(led,HIGH);
		//delay(500);
		stay = millis();
	}
		
	if  (millis() - stay > 500)	digitalWrite(led,LOW);
	
	if (flag == true) {
		flag = false;
		sleepnow();
	}
}