I have seen several other posts and tutorials regarding putting an ATMEga328P to sleep and I have tried to follow those but my consumption is still quite high. My sketch is heavily based on a sparkfun tutorial I found but I can not replicate the results. My project requires the use of a small lipo battery with a solar cell to recharge it so I need to get the micro into the deepest sleep possible to conserve battery. I have moved the micro off the Arduino board and bread boarded it so I can accurately measure consumption. I loaded a boot loader from the Arduino tutorial which runs an 8MHz internal clock and I use a 32.768 external crystal for timer2. I only need it to wake up if timer2 overflows or if it gets an external interupt so I have tried to shut down everything else. My goal is to get this into the single digit uA range and at the moment I am only getting down to 1.2 mah. I thought that maybe my DMM was the issue so I bought a second one which reads the same. I have made sure to remove everything from the board including the programming leads. To check current I connect the battery GND directly to the bread board and I put my DMM inline with VCC. I posted my sketch below and hope that someone has some suggestions.
#include <avr/sleep.h> //Needed for sleep_mode
#include <avr/power.h> //Needed for powering down perihperals such as the ADC/TWI and Timers
#define TRUE 1
#define FALSE 0
int show_the_time = FALSE;
volatile long seconds = 0;
//The very important 32.686kHz interrupt handler
SIGNAL(TIMER2_OVF_vect){
seconds++;
}
//The interrupt occurs when you push the button
ISR(INT1_vect){
if(show_the_time == FALSE)show_the_time = TRUE;
}
//The interrupt occurs when you push the button
ISR(INT0_vect){
if(show_the_time == FALSE)show_the_time = TRUE;
}
void setup() {
//To reduce power, setup all pins as inputs with no pullups
for(int x = 1 ; x < 18 ; x++){
pinMode(x, INPUT);
digitalWrite(x, LOW);
}
//Power down various bits of hardware to lower power usage
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
sleep_enable();
//Shut off ADC, TWI, SPI, Timer0, Timer1
ADCSRA &= ~(1<<ADEN); //Disable ADC
ACSR = (1<<ACD); //Disable the analog comparator
DIDR0 = 0x3F; //Disable digital input buffers on all ADC0-ADC5 pins
DIDR1 = (1<<AIN1D)|(1<<AIN0D); //Disable digital input buffer on AIN1/0
power_twi_disable();
power_spi_disable();
power_usart0_disable();
power_timer0_disable();
power_timer1_disable();
//power_timer2_disable(); //Needed for asynchronous 32kHz operation
//Setup TIMER2
TCCR2A = 0x00;
TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); //Set CLK/1024 or overflow interrupt every 8s
ASSR = (1<<AS2); //Enable asynchronous operation, 32kHz xtal needed
TIMSK2 = (1<<TOIE2); //Enable the timer 2 interrupt
//Setup external INT1 (pin3) interrupt
EICRA = (1<<ISC11)|(1<<ISC01)|(1<<ISC10)|(1<<ISC00); //Interrupt on rising edge
EIMSK = (1<<INT0)|(1<<INT1); //Enable INT interrupts
//need pull downs if active high, active low can enable internal pulllups
//digitalWrite(3, HIGH);
//digitalWrite(2, HIGH);
sei(); //Enable global interrupts
}
void loop() {
sleep_mode(); //Stop everything and go to sleep. Wake up if the Timer2 buffer overflows or if you hit the button
// 10000 ~= 5 hours
if(seconds > 3){
reset_5s();
}
if(show_the_time == TRUE) {
reset_5s();
}
}
void reset_5s(){
pinMode(A0, OUTPUT);
digitalWrite(A0, LOW); // needs to be LOW
fake_msdelay(1000);
digitalWrite(A0, HIGH); // needs to be HIGH
pinMode(A0, INPUT);
seconds = 0;
show_the_time = FALSE;
}
//This is a not-so-accurate delay routine
//Calling fake_msdelay(100) will delay for about 100ms
//Assumes 8MHz clock
void fake_msdelay(int x){
for( ; x > 0 ; x--)
fake_usdelay(1000);
}
//This is a not-so-accurate delay routine
//Calling fake_usdelay(100) will delay for about 100us
//Assumes 8MHz clock
void fake_usdelay(int x){
for( ; x > 0 ; x--) {
asm("nop\n\t");
asm("nop\n\t");
asm("nop\n\t");
asm("nop\n\t");
asm("nop\n\t");
asm("nop\n\t");
asm("nop\n\t");
}
}