Help with Programming Arduino Uno to sleep and wakeup with FSR sensor

Hello Everyone, I m a newbie, and i m working on a small project using arduino Uno. I want my arduino to be on Idle mode to save power since i will be recharging my battery from time to time. I would also want to write a program that will put my arduino to sleep and then activate it with FSR sensor. Based on all my readings and research from this site, i came across with the code at below, but i did not fully understand the code and i hopping that someone will take a look at the code and tell me if the code is what i needed or if i need more code to add into it for it serve my purpose. I would also like to use LED to show the interrupt . For example; i would like my code to show LED red light on when it is on IDLE mode and when FSR sensor is pressed, the green LED will be on showing that arduino is fully active. I also understand that the code uses Interrupt on Pin 2 to wake up.

#include <avr/sleep.h> // powerdown library
#include <avr/interrupt.h> // interrupts library

//***************************************************
// * Name: pin2Interrupt, "ISR" to run when interrupted in Sleep Mode
void pin2Interrupt()
{
/* This brings us back from sleep. /
}
//
**************************************************

//***************************************************
// * Name: enterSleep
void enterSleep()
{
/* Setup pin2 as an interrupt and attach handler. /
attachInterrupt(0, pin2Interrupt, LOW); // << LOW, HIGH, FALLING, RISING I think are valid
delay(50); // need this?
/
the sleep modes
SLEEP_MODE_IDLE - the least power savings
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_STANDBY
SLEEP_MODE_PWR_DOWN - the most power savings
*/
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // setting up for sleep ...
sleep_enable(); // setting up for sleep ...
sleep_mode(); // now goes to Sleep and waits for the interrupt

/* The program will continue from here after the interrupt. */
detachInterrupt(0); //disable interrupts while we get ready to read the keypad

/* First thing to do is disable sleep. */
sleep_disable();

// then go to the void Loop()
}
//***************************************************

//***************************************************
// within void loop() call this ...

enterSleep(); // call Sleep function to put us out
// THE PROGRAM CONTINUEs FROM HERE after waking up in enterSleep()

You can't use an analog device, like an FSR, to generate an input that wakes the Arduino. A digital device, yes.

PaulS:
You can't use an analog device, like an FSR, to generate an input that wakes the Arduino. A digital device, yes.

Thanks for your input, but how can generate an input that wakes the Arduino through digital device?

Exactly how depends on a number of factors. Generating a RISING, FALLING, or LOW interrupt all can be done, depending on how the switch is wired. Which type(s) of interrupt wake the Arduino is the question.

Hi zajebiscie,

That's a cool project you got there. Well first I agree with PaulS, you should first convert the analog signal into a digital one,a simple comparator with a defined threshold may be used. If you want to avoid debouncing a Schmidt trigger or a latch are very useful. Regarding to your code it seems so be very complete, but I would rather prefer to call sleep_disable() before detachInterrupt(0). This way you can assure that your system will be awake and the CPU clock cycles will be running, and after the processor is awake then you call the detachinterrupt(0). Detaching the interrupt after it awakes is a good idea, this way the interrupt won't be called until your Arduino is sleeping. Nowtalking about you LED indicator you can set it as an output and modify it in your enterSleep() function. Set it LOW before it goes to sleep and set it HIGH when it wakes up. By the way,you can also use CHANGE for generating the interrupt. Here below I add the modificationes I would recommend for your code:

#include <avr/sleep.h> // powerdown library
#include <avr/interrupt.h> // interrupts library

//***************************************************
void setup(){
pinMode(13,OUTPUT); //The LED indicator is in pin 13, change it to your needs
}

// * Name: pin2Interrupt, "ISR" to run when interrupted in Sleep Mode
void pin2Interrupt()
{
/* This brings us back from sleep. /
}
//
**************************************************

//***************************************************
// * Name: enterSleep
void enterSleep()
{
/* Setup pin2 as an interrupt and attach handler. /
attachInterrupt(0, pin2Interrupt, LOW); // << LOW, HIGH, FALLING, RISING I think are valid. Here you can also use GHANGE that it is a
//combination of FALLING OR RISING (activated in both cases)
delay(50); // need this? This depends how you want to deal with your sleep times
/
the sleep modes
SLEEP_MODE_IDLE - the least power savings
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_STANDBY
SLEEP_MODE_PWR_DOWN - the most power savings
*/
digitalWrite(13,LOW); // LED is turned off when it goes to sleep
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // setting up for sleep ...
sleep_enable(); // setting up for sleep ...
sleep_mode(); // now goes to Sleep and waits for the interrupt

/* First thing to do is disable sleep. */
sleep_disable();

/* The program will continue from here after the interrupt. */
detachInterrupt(0); //disable interrupts while we get ready to read the keypad

digitalWrite(13,HIGH); //LED is turned off when it wakes up and it's fully active

// then go to the void Loop()
}
//***************************************************

//***************************************************
// within void loop() call this ...

enterSleep(); // call Sleep function to put us out
// THE PROGRAM CONTINUES FROM HERE after waking up in enterSleep()

PaulS:
Exactly how depends on a number of factors. Generating a RISING, FALLING, or LOW interrupt all can be done, depending on how the switch is wired. Which type(s) of interrupt wake the Arduino is the question.

Thanks for your help. There is no clock associated with the project, but all i wanted my arduino to do is to go to sleep (idle) when not in use, and i want to use FSR sensor to interrupt by waking up the arduino while pressing the FSR sensor, and as soon as FSR sensor is release, it will go back to sleep(idle) and move a motor to clockwise. Below is a code i have been working on for the past two days, please could you take a look at it and see if i m missing anything. thanks

#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/io.h>
//
void setup(void)
{
DDRD &= B00000011; // set Arduino pins 2 to 7 as inputs, leaves 0 & 1 (RX & TX) as is
DDRB = B00000000; // set pins 8 to 13 as inputs
PORTD |= B11111100; // enable pullups on pins 2 to 7
PORTB |= B11111111; // enable pullups on pins 8 to 13
pinMode(13,OUTPUT); // set pin 13 as an output so we can use LED to monitor
digitalWrite(13,HIGH); // turn pin 13 LED on

}
//
void loop(void)
{
// Stay awake for 1 second, then sleep.
// LED turns off when sleeping, then back on upon wake.
delay(100);
sleepNow();
}
//
void sleepNow(void)
{

/* Now is the time to set the sleep mode. In the Atmega8 datasheet
* http://www.atmel.com/dyn/resources/prod ... oc2486.pdf on page 35
* there is a list of sleep modes which explains which clocks and
* wake up sources are available in which sleep modus.
*
* In the avr/sleep.h file, the call names of these sleep modus are to be found:
*
* The 5 different modes are:
* SLEEP_MODE_IDLE -the least power savings
* SLEEP_MODE_ADC
* SLEEP_MODE_PWR_SAVE
* SLEEP_MODE_STANDBY
* SLEEP_MODE_PWR_DOWN -the most power savings
*
* the power reduction management <avr/power.h> is described in
* http://www.nongnu.org/avr-libc/user-man ... power.html
*/
// Set pin 2 as interrupt and attach handler:
attachInterrupt(0, pinInterrupt, LOW);
delay(100);
//
// Choose our preferred sleep mode:
set_sleep_mode(SLEEP_MODE_IDLE);
//
// Set sleep enable (SE) bit:
sleep_enable();
power_adc_disable();
power_spi_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();
power_twi_disable();
//
// Put the device to sleep:
digitalWrite(13,LOW); // turn LED off to indicate sleep

sleep_mode();
//
// Upon waking up, sketch continues from this point.
sleep_disable();
digitalWrite(13,HIGH); // turn LED on to indicate awake

}
//
void pinInterrupt(void)
{
detachInterrupt(0);
}

Stuff about sleep:

And interrupts:

... could you take a look at it ...

Can you use the auto-format tool to indent things please?

Next time please post your code inside code tags. Select the code and hit the # button above the posting area.

// Stay awake for 1 second, then sleep.
// LED turns off when sleeping, then back on upon wake.
delay(100);

One second is 1000 mS not 100.

Thanks very much for the correction. I posted my code as you said. So, please can you or another person take look and see if i m on right track with the code at the below...thanks.

#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/io.h>
//
void setup(void)
{
DDRD &= B00000011; // set Arduino pins 2 to 7 as inputs, leaves 0 & 1 (RX & TX) as is
DDRB = B00000000; // set pins 8 to 13 as inputs
PORTD |= B11111100; // enable pullups on pins 2 to 7
PORTB |= B11111111; // enable pullups on pins 8 to 13
pinMode(13,OUTPUT); // set pin 13 as an output so we can use LED to monitor
digitalWrite(13,HIGH); // turn pin 13 LED on

}
//
void loop(void)
{
// Stay awake for 1 second, then sleep.
// LED turns off when sleeping, then back on upon wake.
delay(100);
sleepNow();
}
//
void sleepNow(void)
{

/* Now is the time to set the sleep mode. In the Atmega8 datasheet
* http://www.atmel.com/dyn/resources/prod ... oc2486.pdf on page 35
* there is a list of sleep modes which explains which clocks and
* wake up sources are available in which sleep modus.
*
* In the avr/sleep.h file, the call names of these sleep modus are to be found:
*
* The 5 different modes are:
* SLEEP_MODE_IDLE -the least power savings
* SLEEP_MODE_ADC
* SLEEP_MODE_PWR_SAVE
* SLEEP_MODE_STANDBY
* SLEEP_MODE_PWR_DOWN -the most power savings
*
* the power reduction management <avr/power.h> is described in
* http://www.nongnu.org/avr-libc/user-man ... power.html
*/
// Set pin 2 as interrupt and attach handler:
attachInterrupt(0, pinInterrupt, LOW);
delay(100);
//
// Choose our preferred sleep mode:
set_sleep_mode(SLEEP_MODE_IDLE);
//
// Set sleep enable (SE) bit:
sleep_enable();
power_adc_disable();
power_spi_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();
power_twi_disable();
//
// Put the device to sleep:
digitalWrite(13,LOW); // turn LED off to indicate sleep

sleep_mode();
//
// Upon waking up, sketch continues from this point.
sleep_disable();
digitalWrite(13,HIGH); // turn LED on to indicate awake

}
//
void pinInterrupt(void)
{
detachInterrupt(0);
}

What is attached to the interrupt pin? What is generating the interrupt? Your not still trying to use an FSR, are you?

I posted my code as you said.

No
you
did
not!

Thank you very much for the site. Based on the example code from that site, i put together a code that will work for my small project, but i m not sure if i m on the right track. Please could you take a look at the code and see if i m doing it correct way. I m planning to use FSR sensor to interrupt from pin2 and it will stays on while someone is holding the sensor, and then arduino will go back to idle as soon as the FSR sensor is realeas.

#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/io.h>

const byte LED = 9;
  
void wake ()
{
  // cancel sleep as a precaution
  sleep_disable();
}  // end of wake

void setup () 
  {
  digitalWrite (2, HIGH);  // enable pull-up
  }  // end of setup

void loop () 
{
 
  pinMode (LED, OUTPUT);
  digitalWrite (LED, HIGH);
  delay (50);
  digitalWrite (LED, LOW);
  delay (50);
  pinMode (LED, INPUT);
  
  // disable ADC
  ADCSRA = 0;  

  // turn off various modules
  PRR = 0xFF; 
  
  set_sleep_mode (SLEEP_MODE_IDLE);   
  sleep_enable();

  // will be called when pin D2 goes low  
  attachInterrupt (0, wake, LOW);
 
  // turn off brown-out enable in software
  MCUCR = _BV (BODS) | _BV (BODSE);
  MCUCR = _BV (BODS); 
  sleep_cpu ();  
  
  // must do this as the pin will probably stay low for a while
  detachInterrupt (0);
  
  } // end of loop

Isn't an FSR a force sensitive resistor? Which is an analog device? Interrupts only work on digital changes (eg. high to low) so I wouldn't think an FSR is suitable, unless you hook it up to a comparator before the interrupt pin.

Please could you take a look at the code and see if i m doing it correct way.

Try it and see ...

Thanks Nick Gammon for your quick reply. Yes FSR is a force sensitve resistor. Please Nick Gammon, do you know or have a direction on how to connect FSR to comarator and then before connecting it to interrupt pin?

PaulS:
You can't use an analog device, like an FSR, to generate an input that wakes the Arduino. A digital device, yes.

Very much to my surprise, this can be done and it works exceedingly well! I have a project with several tactile button switches and an FSR. It sleeps in power down mode; I wanted any button or the FSR to wake it. I treat the FSR identically to the buttons, I have the internal pullups enabled and use pin change interrupts to wake the µC. I use the same library for debouncing and sensing the FSR and the buttons. Actually, for this project I never use the FSR as an analog device, since I just want to know if it's "pressed" or not.

Going in to the project, I of course assumed that I would have to treat the FSR as an analog device. But in a moment of weakness (and temporary insanity), I thought I'd try just treating it the same as the switches, nothing to lose really. I was amazed when it worked perfectly. Maybe I got lucky, maybe the characteristics of the FSR I chose, the way it's being loaded, and the hysteresis provided by the AVR all just lined up perfectly, so YMMV, but it works just great for me.

Thanks, Jack. I'm not totally surprised. If the voltage from the FSR when not pressed is quite high (eg. 4V) and when pressed is quite low (eg. 2V) then that effectively could be treated as a digital signal, because the digital inputs would have a "transition" zone (around 2.5V) where above that is considered high, and below is considered low.

Indeed, I've measured it, and I think the FSR is darn near an open circuit with no load (weight) on it, so I'd bet the pin is very close to Vcc (the project actually runs on 2xAA alkaline cells). Since the FSR actuations in my project are quite slow, I did use a fairly long debounce interval on it (100ms vs. 20 or 25 for the buttons), but I'm not sure that is really of any consequence. Just one of those serendipitous things, it still makes me smile :smiley:

I used this FSR from Sparkfun if that makes a difference to anyone:

Thanks for your help. I have one more question , how do i test to see if the arduino is at sleep or not. ?

zajebiscie:
how do i test to see if the arduino is at sleep or not. ?

Do you mean how can your code test whether the Arduino it runs on is asleep or not? The answer is that it is awake.

zajebiscie:
Thanks for your help. I have one more question , how do i test to see if the arduino is at sleep or not. ?

You're welcome! I just used an ammeter to monitor the current drawn by the circuit.