Sensor - Pro MIni - Sleep mode

Hi All,

I am a real newbie on here so please excuse any mistakes!

I am working on a pulse sensor device - it is very small so I am using a pro mini and powering it with 6v.

I want it to go to sleep when not in use and be triggered awake with a sensor input - I think I have managed to put together all the code correctly only I cannot really tell how much power is being used. My batteries seemed to deplete overnight which doesn’t seem right if it is working?

Is there anyone out there who can have a look at my code to see if I am missing anything / it all compiles and seems to sleep so I cant figure out whats happening?

:o

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


// Pins
const int ledPin = 3;
const int sensePin = 0;
int brightness = 0;    // how bright the LED is
int sleep_mode_LED = 13;          // LED used to detect the sleep mode 

// LED blink variables
int ledState = LOW;

// Hearbeat detect variables
int newHeartReading = 0;
int lastHeartReading = 0;
int Delta = 0;
int recentReadings[2] = {0,0};
int historySize = 2;
int recentTotal = 0;
int readingsIndex = 0;
boolean highChange = false;
int totalThreshold = 2;


// Heartbeat Timing
long lastHeartbeatTime = 0;
long debounceDelay = 150;
int currentHeartrate = 0;


void pciSetup(byte pin)    // function to change interrupt pin to A0 
{
    *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
    PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
    PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

ISR (PCINT1_vect) // handle pin change for interrupt1 at A0 pin
 {
    digitalRead(A0);
 }  
 
 void pinA0_Interrupt(void)
{
  detachInterrupt(0);  // disable interrupt
  sleep_disable();   // wake up cpu
}
void sleepNow() {  
  // here we put the arduino to sleep
 

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);         // set sleep mode
  sei();                                    //Enables interrupts by setting the global interrupt mask.
  pciSetup(A0);                            // enable interrupt at A0
  attachInterrupt(1, pinA0_Interrupt, HIGH);  //interrupt1 at pin A0,when A0 high call interrupt funtion
  sleep_enable();                             // enables the sleep bit in the mcucr register 
  digitalWrite(sleep_mode_LED,LOW);           // off LED before the device is going to sleep
  sleep_cpu();                                // here the device is actually put to sleep!!
 
  
  // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP   
}





void setup() {
// initialize the serial communication:
Serial.begin(9600);
// initialize the digital pin as an output:
pinMode(ledPin, OUTPUT);

pinMode(sleep_mode_LED,OUTPUT);   // pin that will check the sleep mode

    pciSetup(A0);


}
void loop() {
// Turn off LED
ledState = LOW;



// Read analogue pin.
newHeartReading = analogRead(sensePin);
//Serial.println(newHeartReading);
//Calculate Delta
Delta = newHeartReading - lastHeartReading;
lastHeartReading = newHeartReading;

// Find new recent total
recentTotal = recentTotal - recentReadings[readingsIndex] + Delta;
// replace indexed recent value
recentReadings[readingsIndex] = Delta;
// increment index
readingsIndex = (readingsIndex + 1) % historySize;

//Debug
//Serial.println(recentTotal)  6666666666666 ;

// Decide whether to start an LED Blink.
if (recentTotal >= totalThreshold) {
// Possible heartbeart, check time
if (millis() - lastHeartbeatTime >= debounceDelay) {
// Heartbeat
{


 for (brightness = 0; brightness < 200; brightness ++)
 {
   analogWrite(ledPin, brightness);
   delay(1);
 }

 for (brightness = 200; brightness > 0; brightness --)
 {
   analogWrite(ledPin, brightness);
   delay(1);
 }

  
  
}
currentHeartrate = 60000 / (millis() - lastHeartbeatTime);
lastHeartbeatTime = millis();
// Print Results
//Serial.println("Beat");
if (currentHeartrate <= 200) { Serial.println(currentHeartrate); } } } delay(10); 

if (ledState = LOW > 8000){ {                  // if 8 seconds go by without a beat
  
  digitalWrite(sleep_mode_LED,HIGH);             //  make LED ON when sleep mode function goin to call    

  
  sleepNow();                                   // called sleep mode function

}
  sei();                                   // enable interrupts when youre done!
}// end isr

}
ISR (PCINT1_vect) // handle pin change for interrupt1 at A0 pin
 {
    digitalRead(A0);
 }

That hardly seems to be a useful thing to do. A bit like reading a book with a blindfold on.

if (ledState = LOW > 8000){ {                  // if 8 seconds go by without a beat

Assigning the value of LOW to ledState seems pointless. The result of making that assignment, though, is the assigned value. 0 is never greater than 8000.

You meant to compare ledState to LOW, you should have used ==. Even so, neither true or false is greater than 8000, so this statement will never evaluate to true.

Even if it did, it does NOT need two open braces.

}// end isr

No, it isn't.

Quite apart from the coding issues, the overnight depletion of the battery must have some other contributory factors.
Which pin on the pro mini are you using to power it ?
Have you disconnected the power led on the pro mini board ?
What else have you connected to it ?

You could also have a look here for other ideas: mini low power and here yet another

Hi,

Thank you for your quick input! I am working on this all day today so its great - I have been looking in to a void with this!

I have removed this bit o code -

ISR (PCINT1_vect) // handle pin change for interrupt1 at A0 pin
 {
    digitalRead(A0);
 }

and the reason I was using the Led - Low time as a trigger for sleep was that it seems to be the only trigger I can use - I have been fiddling with the code for hours trying to find another - if for this but cant see a possible one.

I am powering the micro on RAW - via x2 3v coin cells and yes thank you for the power consumption links . I have ruined a few boards with my attempts at getting rid of the on board LEDs but I am going to have another go!

and the reason I was using the Led - Low time as a trigger for sleep was that it seems to be the only trigger I can use

But you can't mix states and times in any meaningful way.

Why don't you start with telling us WHEN the Arduino should go to sleep, either as an absolute time or relative to some event. Then, we can help you make sure that the Arduino DOES go to sleep then.

I suspect that the reason your battery doesn't last is because you don't actually go to sleep.

There are many things that use power. Sleeping does not automatically disable all of them. You must make sure that you turn off everything that can be turned off before going to sleep, and to turn it all back on again when you wake up.

Hi Paul,

Thankyou - I am looking for the mini to go to sleep when there is not longer a pulse on the sensor ( about 8 seconds after no pulse ) Only I cannot see a defined instance of ( heartbeat ) that I would be able to use to do this?

I am looking at now what it is I can disable on the device - The only thing I need to keep running I guess is the sensor on A0 as this is what I use to trigger an awake?

when there is not longer a pulse on the sensor

On which sensor? Connected to which pin?

If you are referring to a heartbeat sensor, doesn't the name lastHeartbeatTime suggest anything? If it does, what does it suggest?

Something along the lines, maybe, of:

   if(millis() - lastHearbeatTime >= 8000)
   {
       itsNapTime();
   }

The only thing I need to keep running I guess is the sensor on A0 as this is what I use to trigger an awake?

You'll need to keep the analog to digital converter running, too.

Are you CERTAIN that the sensor connected to the analog pin can wake the Arduino? I am not.

obsidianeyes:
. . .
I am powering the micro on RAW - via x2 3v coin cells and yes thank you for the power consumption links . I have ruined a few boards with my attempts at getting rid of the on board LEDs but I am going to have another go!

I'm sure you'll get better results if you wire the 2 coin cells in parallel ( = 3 volts) then use the Vcc terminal instead of the RAW terminal. That way, the voltage regulator does not drain your batteries. (works best with the 3volt / 8 Mhz pro mini)

Hi Paul,

Its connected to A0 - and yes its a heart beat sensor.

Thank you for pointing out - lastHeartbeatTime as a trigger - yes this is totally the way to go !

No I'm not too sure if the sensor can trigger a wake but it seems like the only external interrupt I got going ?

6v6gt Thank you - I have a 2 x coin cell parallel holder so am going to try that out!

No I'm not too sure if the sensor can trigger a wake but it seems like the only external interrupt I got going ?

It may be the only external signal that you have. That does NOT make it an external interrupt, though.

You could attach the signal to both A0 and D2, using a pair of diodes, so that an external interrupt does happen when a pulse happens.

Do you think if I move the led pin ( which blinks on pulse from the sensor ) to an interrupt pin / 2? I can then use this as a trigger?

obsidianeyes:
. . .
6v6gt Thank you - I have a 2 x coin cell parallel holder so am going to try that out!

Wired in parallel (3 volts) . Not lying together , parallel to each other in the same holder (could be 6 Volts from your OP).

batteryWireDiagram.jpg

The ATMEGA328P tolerates up to 5.5 volts. If you must use 6 volts on the Vcc pin, put a silicon diode (eg 1N4007) in series with the battery to drop the voltage by 0.7 volts.

PaulS:

if (ledState = LOW > 8000){ {                  // if 8 seconds go by without a beat

Assigning the value of LOW to ledState seems pointless. The result of making that assignment, though, is the assigned value. 0 is never greater than 8000.

You meant to compare ledState to LOW, you should have used ==. Even so, neither true or false is greater than 8000, so this statement will never evaluate to true.

While the comparison of LOW with 8000 is senseless, its value gets assigned to ledState.

The operator precedence of the assignment is lower than the precendence of the comparison.

http://en.cppreference.com/w/cpp/language/operator_precedence

I have changed -

if (ledState = LOW > 8000){ {                  // if 8 seconds go by without a beat

To -

 if(millis() - lastHeartbeatTime >= 8000) {                  // if 8 seconds go by without a beat

I have done my first circuit on Fritzing! Attached but could fins all my parts so put them on separately. 6v6gt Thankyou mate - I have put a diode from power to Vcc.

PaulS - Thanks for your help - would you be able to tell me how I would attach the two diodes in to the circuit for the interrupt and do I then need to include this new pin into the interrupt code or leave as is?

Thank you so much!

circuit !

PaulS - Thanks for your help - would you be able to tell me how I would attach the two diodes in to the circuit for the interrupt and do I then need to include this new pin into the interrupt code or leave as is?

If the heartbeat sensor is triggering an interrupt with the way the code is written, and the interrupt wakes the Arduino, there is no reason to make a change.

But, you need to prove to yourself that the Arduino IS going to sleep and that it wakes up when the sensor sends a pulse.

Have you told us exactly what sensor you're using yet? What it's typical outputs will be in the conditions you're using it in? That's kind of just a tiny little bit important.

Which variant of the Pro Mini are you using? There's a 3.3V and 5V version.

I am using a pulse sensor pro and a 5v version of pro mini . the pulse senor will be used in a small box and powered by 2x 3v batteries - it will blink in time to the heartbeat.

I have updated my code to add the setup - is this disabling the pins correctly?

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


// Pins
const int ledPin = 3;
const int sensePin = 0;
int brightness = 0;    // how bright the LED is
int sleep_mode_LED = 13;          // LED used to detect the sleep mode 

// LED blink variables
int ledState = LOW;

// Hearbeat detect variables
int newHeartReading = 0;
int lastHeartReading = 0;
int Delta = 0;
int recentReadings[2] = {0,0};
int historySize = 2;
int recentTotal = 0;
int readingsIndex = 0;
boolean highChange = false;
int totalThreshold = 2;


// Heartbeat Timing
long lastHeartbeatTime = 0;
long debounceDelay = 150;
int currentHeartrate = 0;


void pciSetup(byte pin)    // function to change interrupt pin to A0 
{
    *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
    PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
    PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}


  void pinA0_Interrupt(void)

{
  detachInterrupt(0);  // disable interrupt
  sleep_disable();   // wake up cpu
}
void sleepNow() {  
  // here we put the arduino to sleep
 

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);         // set sleep mode
  sei();                                    //Enables interrupts by setting the global interrupt mask.
  pciSetup(A0);                            // enable interrupt at A0
  attachInterrupt(1, pinA0_Interrupt, HIGH);  //interrupt1 at pin A0,when A0 high call interrupt funtion
  sleep_enable();                             // enables the sleep bit in the mcucr register 
  digitalWrite(sleep_mode_LED,LOW);           // off LED before the device is going to sleep
  sleep_cpu();                                // here the device is actually put to sleep!!
 
  
  // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP   
}





void setup() {
// initialize the serial communication:
Serial.begin(9600);
// initialize the digital pin as an output:
pinMode(ledPin, OUTPUT);

pinMode(sleep_mode_LED,OUTPUT);   // pin that will check the sleep mode

    pciSetup(A0);

    DDRD &= B01000011;       // 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() {
// Turn off LED
ledState = LOW;



// Read analogue pin.
newHeartReading = analogRead(sensePin);
//Serial.println(newHeartReading);
//Calculate Delta
Delta = newHeartReading - lastHeartReading;
lastHeartReading = newHeartReading;

// Find new recent total
recentTotal = recentTotal - recentReadings[readingsIndex] + Delta;
// replace indexed recent value
recentReadings[readingsIndex] = Delta;
// increment index
readingsIndex = (readingsIndex + 1) % historySize;

//Debug
//Serial.println(recentTotal);

// Decide whether to start an LED Blink.
if (recentTotal >= totalThreshold) {
// Possible heartbeart, check time
if (millis() - lastHeartbeatTime >= debounceDelay) {
// Heartbeat
{


 for (brightness = 0; brightness < 255; brightness ++)
 {
   analogWrite(ledPin, brightness);
   delay(1);
 }

 for (brightness = 255; brightness > 0; brightness --)
 {
   analogWrite(ledPin, brightness);
   delay(1);
 }

  
  
}
currentHeartrate = 60000 / (millis() - lastHeartbeatTime);
lastHeartbeatTime = millis();
// Print Results
//Serial.println("Beat");
if (currentHeartrate <= 200) { Serial.println(currentHeartrate); } } } delay(10); 

if(millis() - lastHeartbeatTime >= 8000)


{                   // if 8 seconds go by without a beat
  
  digitalWrite(ledPin,LOW);             //  make LED ON when sleep mode function goin to call    

  digitalWrite(sleep_mode_LED,HIGH);             //  make LED ON when sleep mode function goin to call    

  
  sleepNow();                                   // called sleep mode function

}
  sei();                                   // enable interrupts when youre done!
}// end isr

I couldn't find a "Pulse Sensor Pro", did you mean this thing?

Yes thats the one!

I dropped the code they provide as it was not suitable for my needs - I only need - pulse - flash .