Arduino sleep code - HELP!...

220 views
Skip to first unread message

Chunky

unread,
Feb 3, 2014, 6:18:07 AM2/3/14
to notti...@googlegroups.com
Hi,
If there is an arduino/AVR code person out there who has experience with using sleep modes on a 'bare bones' arduino then a bit of help would be great.
I am trying to build a data logger which wakes up every so often and takes a few analog readings and then goes back to sleep. I want it to run from batteries for a long time.
I am using a 'bare bones' arduino (ie with no power regulator). I am using a real time clock to give me a 1Hz (once per second) interrupt onto pin D3/Interrupt 1.
I want to save as much power as possible by putting the device to sleep for most fo the time. Thsi interrupt sets a flag high which tells the main loop to take a reading and then go back to sleep again. The sleep functions seem to work OK, except when I try and add an analogRead() to my code.

I am finding that I can put the unit to sleep (just waking up to  flash an LED 1 per second) and the unit consumes around 2mA on average.

When I wake up and then do an analogRead() I find that the device consumes 13mA constanly - as if it is never sleeping or doing something that consumes power.

Has anyone else had similar issues? Do I need to set other pins to switch off the ADC?

 My code is below. The RTC functions work well. The ONLY change I make is to comment out the analogRead() line in the main loop. This gives the difference between 2mA consumption and 13mA consumption....

Any help apreciated,
Cheers,
Matt
<code>
/********************************************************
/****** Testing sleep modes******************************
/****** by Matt Little **********************************
/****** Date: 3/2/2014 **********************************
/****** in...@re-innovation.co.uk ************************
/****** www.re-innovation.co.uk *************************
/********************************************************

  See www.re-innovation.co.uk for information and construction details
 
  This is sample code for the DataDuino.

/*************Details of Code*****************************

This is test code to investigate power used when in sleep modes.
A Real Time Clock is used on pin D3 (Interrupt 1) to wake the unit
every second (on the falling edge).
I want to wake up, read the ADC (temperature reading) then go back to sleep.
This should happen every 'X' seconds.

 
 //************ Real Time Clock code*******************
 A PCF8563 RTC is attached to pins:
 ** A4 - SDA (serial data)
 ** A5 - SDC (serial clock)
 ** D2 - Clock out - This gives a 1 second pulse to record the data
 
 RTC PCF8563 code details:
 By Joe Robertson, jmr
 orbit...@bellsouth.net
 
**********************************************************************************************************/

/************ External Libraries*****************************/

#include <Wire.h>          // Required for RTC
#include <Rtc_Pcf8563.h>   // RTC library
#include <avr/sleep.h>
#include <avr/power.h>

/************User variables and hardware allocation**********************************************/

/*************Real Time Clock*******/
Rtc_Pcf8563 rtc;
#define I2C_RTC 0x51 // 7 bit address (without last bit - look at the datasheet)
#define RTCinterrupt 0  // RTC interrupt - This is pin 2 of ardunio - which is INT0

/********* I/O Pins *************/
#define LEDred 5      // The output led is on pin 5
#define thermistor A3  // This is the pin for the thermistor

/********** Analogue Data Storage ************/
int analog0 = 0;  // Analog input

///********* Thermistor Temperature sensor****************/
float temp;        // Temporary store for float

long sampleTime = 2;  // This is the time between samples for the DAQ
long dataCounter = 0;  // This holds the number of seconds since the last data store

volatile int writedataflag = HIGH;  // A flag to tell the code when to write data

// These next ints are for the filename conversion
int day_int =0;      // To find the day from the Date for the filename
int day_int1 =0;
int day_int2 =0;
int month_int = 0;
int month_int1 = 0;
int month_int2 = 0;
int year_int = 0;  // Year
int hour_int = 0;
int min_int = 0;
int sec_int = 0;

// These are Char Strings - they are stored in program memory to save space in data memory
// These are a mixutre of error messages and serial printed information
const char initialisesd[] PROGMEM = "Initialising SD card...";

#define MAX_STRING 80      // Sets the maximum length of string probably could be lower
char stringBuffer[MAX_STRING];  // A buffer to hold the string when pulled from program memory


/***************************************************
 *  Name:        RTC
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: I use the CLK_OUT from the RTC to give me exact 1Hz signal
 *               To do this I changed the initialise the RTC with the CLKOUT at 1Hz
 *
 ***************************************************/
void RTC()
{
  detachInterrupt(RTCinterrupt);
  dataCounter++;
 
  if(writedataflag==LOW&&dataCounter>=sampleTime)  // This stops us loosing data if a second is missed
  {
    // Reset the DataCounter
    dataCounter = 0; 
    // Set the writedataflag HIGH
    writedataflag=HIGH;
  }
}

/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Enters the arduino into sleep mode.
 *
 ***************************************************/
void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();

  attachInterrupt(RTCinterrupt, RTC, FALLING);
 
  sleep_cpu();
 
  /* The program will continue from here. */
 
  /* First thing to do is disable sleep. */
  sleep_disable();
}


/***************************************************
 *  Name:        setup
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Setup for the Arduino.          
 *
 ***************************************************/
void setup()
{
  Serial.begin(9600);
   
  //******Real Time Clock Set - up********
  // A4 and A5 are used as I2C interface.
  // D2 is connected to CLK OUT from RTC. This triggers an interrupt to take data
  // We need to enable pull up resistors
  pinMode(A4, INPUT);           // set pin to input
  digitalWrite(A4, HIGH);       // turn on pullup resistors
  pinMode(A5, INPUT);           // set pin to input
  digitalWrite(A5, HIGH);       // turn on pullup resistors
  pinMode(2,INPUT);    // Set D2 to be an input for the RTC CLK-OUT  
  //initialise the real time clock
  Rtc_Pcf8563 rtc;
 
  setupRTC();  // Initialise the real time clock 
 
  pinMode(LEDred,OUTPUT);    // Set D5 to be an output LED  
 
  Serial.println("Initialisation complete.");

  attachInterrupt(RTCinterrupt, RTC, FALLING);
}



/***************************************************
 *  Name:        main loop
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Main application loop.
 *
 ***************************************************/
void loop()
{
 
  if(writedataflag==HIGH)
  { 
    digitalWrite(LEDred, HIGH);   // set the LED ON

    // *********** TEMPERATURE *****************************************
    // Two versions of this - either with thermistor or I2C sensor
   
    // Thermistor version
    // Reading from
    // Get the temperature readings and store to variables    
    //analog0 = analogRead(A0);
    Serial.print("Temperature: ");
    Serial.println(analog0);
    delay(50);     
    digitalWrite(LEDred, LOW);   // set the LED ON
  }
      
  enterSleep();

}

// Set Up RTC routine
void setupRTC()
{
    // This section configures the RTC to have a 1Hz output.
  // Its a bit strange as first we read the data from the RTC
  // Then we load it back again but including the correct second flag 
  rtc.formatDate(RTCC_DATE_WORLD);
  rtc.formatTime();
 
  year_int = rtc.getYear();
  day_int = rtc.getDay();
  month_int = rtc.getMonth(); 
  hour_int = rtc.getHour();
  min_int = rtc.getMinute();
  sec_int = rtc.getSecond();
 
  Wire.begin(); // Initiate the Wire library and join the I2C bus as a master
  Wire.beginTransmission(I2C_RTC); // Select RTC
  Wire.write(0);        // Start address
  Wire.write(0);     // Control and status 1
  Wire.write(0);     // Control and status 2
  Wire.write(DecToBcd(sec_int));     // Second
  Wire.write(DecToBcd(min_int));    // Minute
  Wire.write(DecToBcd(hour_int));    // Hour
  Wire.write(DecToBcd(day_int));    // Day
  Wire.write(DecToBcd(2));    // Weekday
  Wire.write(DecToBcd(month_int));     // Month (with century bit = 0)
  Wire.write(DecToBcd(year_int));    // Year
  Wire.write(0b10000000);    // Minute alarm (and alarm disabled)
  Wire.write(0b10000000);    // Hour alarm (and alarm disabled)
  Wire.write(0b10000000);    // Day alarm (and alarm disabled)
  Wire.write(0b10000000);    // Weekday alarm (and alarm disabled)
  Wire.write(0b10000011);     // Output clock frequency enabled (1 Hz) ***THIS IS THE IMPORTANT LINE**
  Wire.write(0);     // Timer (countdown) disabled
  Wire.write(0);     // Timer value
  Wire.endTransmission();
}

// Converts a decimal to BCD (binary coded decimal)
byte DecToBcd(byte value){
  return (value / 10 * 16 + value % 10);
}
</code>

Michael Erskine

unread,
Feb 3, 2014, 6:34:24 AM2/3/14
to nottinghack
Hi Matt,
Have a look at this: http://arduino720.wikispaces.com/Power+Saving+Techniques
When you do AnalogRead the ADC must be powered up and the Arduino core
must do this.
Regards,
Michael.

Michael Erskine

unread,
Feb 3, 2014, 6:44:25 AM2/3/14
to nottinghack
Matt,
further to the above, if you haven't continued on to this other reference...
http://www.gammon.com.au/forum/?id=11497

...then do! See the usage of the power reduction register (PRR) which
must be used in conjunction with ADCSRA.

Hope this helps.

Pat McDonald

unread,
Feb 3, 2014, 11:37:54 AM2/3/14
to notti...@googlegroups.com
A suggestion that might help with the above is; if you have a little extra circuit to disconnect and reconnect the analogue signal you are reading from with a couple transistors.

The REASON why this might help is that ADC works by feeding the analgue signal across a matrix of increasing resistor values (which go in a double last value series) to produce a string of ones and zeroes.

If the analogue signal is disconnected, there isn't anything to amplify and feed into the resistor matrix. Be aware though, you will need to leave it connected for at least a second for it to stabilize enough to get a reasonable "average value".

Read up a bit on ADC theory and you might see where I'm coming from on this.

Roger Light

unread,
Feb 3, 2014, 11:53:35 AM2/3/14
to notti...@googlegroups.com
Hi Pat,

I think you're wrong here. Most ATmegas have a sample/hold circuit
used with a successive approximation ADC (ref:
http://www.atmel.com/Images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet.pdf
page 242). Once the sampling capacitor is charged, there should be
negligible input current.

Cheers,

Roger
> --
> You received this message because you are subscribed to the Google Groups
> "Nottingham Hackspace - Nottinghack" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to nottinghack...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

jfowkes

unread,
Feb 3, 2014, 11:56:03 AM2/3/14
to notti...@googlegroups.com
The AVRs don't have a flash ADC, they have a successive approximation one.

jfowkes

unread,
Feb 3, 2014, 12:00:01 PM2/3/14
to notti...@googlegroups.com
Ah, Roger posted as I was typing. What he said.

Pat McDonald

unread,
Feb 3, 2014, 6:33:59 PM2/3/14
to notti...@googlegroups.com
Even if I am right, I am doubtful the extra current required by external circuitry would be less than the ADC hardware that wasn't hibernating and waking up properly.. Possible. Worth checking. But unlikely.

Chunky

unread,
Feb 4, 2014, 9:41:20 AM2/4/14
to notti...@googlegroups.com
Thanks for all the comments and help.
I think I have now solved it and it turns out to be an issue not relating to the sleep modes....

I am using a 3V3 regulated signal into Vref.
But I had not told the ATMega328 to use an external reference, so it was using 5V input voltage (that is the default). But if we use an internal reference then the Vref pin MUST be left unconnected.

My high consumed current reading was basically the 3V3 fighting the 5V where they meet on the Vref pin. This was not bad enough to cause the unit to short circuit, but counsmed current (and probably did not do much good to the 3v3 regulator or uP).

This only became an issue when the analogRead() was used, hence why I only saw the issue when that code was used.

To solve this I needed to specify the analogReference in the Setup using:
    analogReference(EXTERNAL);

This seems to work and I now have analogRead() working but it still going into low power, sleep, mode.
So its now taking readings and consuming <2mA on average.
Cool....

Matt

Pat McDonald

unread,
Feb 4, 2014, 10:05:08 AM2/4/14
to notti...@googlegroups.com
It's amazing how many Arduino people are unaware of the VRef feature and it's implications. ;)

Reply all
Reply to author
Forward
0 new messages