I want to run my atmega328 on batteries, power consumption has to be lowered

Hi. I'm making a simple digital alarm clock for my moms cooking. The code itself works just fine and can be found here: http://pastebin.ca/2098613 The atmega328 drives a 2-digit 7-segment display telling my mom the minutes left, when the timer goes down to zero it drives a buzzer through a 2n2222 NPN transistor.

I read in the site below that it is possible to get the idle power consumption of the atmega328 down to 6.8uA which is a massiv decrease. http://jeelabs.org/2009/05/16/power-consumption-more-savings/ though my problem is that my understanding when it comes to programming, C and MCU's is very slim so I have no idea what the code on that sites mean. I am wondering if there is some kind of "quick fix" to lower the chips idle power consumption? Something I can easly implement with my code without ruining everything :P

Sure, you can put it in various sleep modes. Power down sleep mode is the best.

If you build up a standalone circuit with bare minimum parts and an RTC chip, you can put it in power down sleep mode, wake up once a second on RTC 1/second pulse, do whatever in a millisecond or two, then go back to sleep. No wasting power on the regulator, USB interface chip, power on LED. Will need: atmega328 16 MHz xtak (and you will likely get suggestions to run from internal 1MHz setting, I figure why make life difficult? build it as if you had an Uno for ease of programming & testing - current in sleep mode is comparable, or the same) two 22 caps three 100nF caps 10K pullup resistor whatever buttons you need for setting time DS1307 32.768 xtal three 4.7K pullup resistors socket for the atmega socket for the DS1307 backup battery & holder for the Ds1307 3 AA batterys & holder for the ATmega power Program the atmega in your uno, move it over.

You can find a prototype kit and the other components quite inexpensively at dipmicro.com.

Your code is constantly driving the 7-segment displays. I don't think you'll be able to do that if you put the arduino to sleep.

I'm going to skip the RTC, letting the atmega328 doing the timing is more than good enough.

I need to know how to put it in power down sleep mode. I want it to enter sleep mode after the alarm has gone off and then exit sleep mode the moment someone touches the potmeter controlling the timing.

Your code is constantly driving the 7-segment displays. I don't think you'll be able to do that if you put the arduino to sleep.

My code turns the 7-segment display off if the timer value is zero so the display isn't lighting up if it isn't counting down.

Plecto:
my moms coocking.

LOL

If you get the “p” varient, ATMega328p, it can operate down to 1.8v. Also, have a look at the following routine ( will need to include avr/sleep.h and avr/power.h):

void sleepNow()
{
  /* Now is the time to set the sleep mode. In the Atmega8 datasheet
   * http://www.atmel.com/dyn/resources/prod_documents/doc2486.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-manual/group__avr__power.html
   */

  set_sleep_mode(SLEEP_MODE_IDLE);   // sleep mode is set here

  sleep_enable();          // enables the sleep bit in the mcucr register
  // so sleep is possible. just a safety pin 

  power_adc_disable();
  power_spi_disable();
  power_timer0_disable();
  power_timer1_disable();
  power_timer2_disable();
  power_twi_disable();


  sleep_mode();            // here the device is actually put to sleep!!

  // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
  sleep_disable();         // first thing after waking from sleep:
  // disable sleep...

  power_all_enable();

}

I can't really tell you if it is the p-variant or not because the chip has it's pin-out printed on top of it.

I need some more guidance here. Do I just set "set_sleep_mode(PWR_DOWN):" and then call "sleep_mode();" to put it to sleep? How do I get it out of it's sleep?

This is also a good demo of low power Arduino too:

http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/

I tried reading the code that was used in the demo you linked supercrab, but I don't even have any idea of how this kind of power saving works so learning it directly from the code is extremely hard, the code also contained alot of commands that I haven't used before. This demo also doesn't operate in the same way as I wan't my code to do. I wan't my alarm clock to go to sleep mode after the alarm has sounded and then keep checking every second or so for signs to get out of the sleep mode. I need someone to explain to me how to operate this sleep function and how to get it out of it

The general theory of sleep mode:

You put it to sleep by setting several registers (or by calling functions that do the dirty work for you), and then it sleeps until it gets an interrupt signal.

This interrupt can be from Serial, Timer2, or a pin change interrupt. Since you just want to wake up when the pin change interrupt happens (when a button is pressed), you can make an OR gate (out of diodes) to take all the buttons and put it on an interrupt pin. Then, select a sleep mode from the atmega328p datasheet and figure out how to call it.

The best interrupt is the LOW interrupt on pins D2 or D3. The processor can sleep "deeply" and still notice that interrupt. To notice pin change interrupts it has to sleep more lightly, as it has to be checking if the pins are changing.

For something like an alarm clock, a "wake up" button could achieve that.

Once in sleep you need an interrupt to wake up. That's why I had suggested the Ds1307. http://www.dipmicro.com/store/DS1307N http://www.dipmicro.com/store/XC4-32768

Has a 1/second square wave output that you can use as interrupt.

Ah, I get it now. I have both crystals and 1307's laying here, but do these just output a 1/second square wave the moment you apply power? Don't I need to communicate with it serially?

I will try to learn what kind of code I need to learn in order to activate and deactivate the sleep mode and I'll get back to you if I need more help.

I believe the square wave output is off by default, you send it command using Wire.h library to make it start. I can look it up when I get home if it is not posted already when I get there. Someone will likely say to use some library, I just used mine with discrete I2C commands. The square wave output needs to be pulled up with a 10K resistor.

Here’s my code for testing one out that I wrote up a while ago under IDE -0022. Should work under -0023 also.
IDE 1.0 made changes, you will have to tweak the Wire.x commands for it to work.

http://www.maxim-ic.com/datasheet/index.mvp/id/2688/t/al

/*
Test of RTC DS1307 via I2C.
 Counts 
 Seconds, 
 Minutes, 
 Hours, 
 Date of the Month, 
 Month, 
 Day of the week, and 
 Year with Leap-Year
 
 56 bytes battery backed RAM
 Square Wave Output, can connect to INT2/D6 or PD7
 
// use F0xx, F1xx,F2xx, F3xx, F4xx, F5xx, F6xx, F7xx from IDE's serial port window
// use F0xx to send one register write commands to set the seconds.  Upper bit must be 0 to enable counting.
// F1xx for minutes, 
// F2xx for hours, 
// F3xx for day_week, 
// F4 for date_month,
// F5 for month,
// F6 for year,
// F7 for  square wave

*/
#include <Wire.h>

//variables
byte seconds_address = 0x00;
byte seconds; // bit 7 = Clock Halt, Enabled = 0, Halt = 1
// bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9

byte minutes_address = 0x01;
byte minutes;  // bits 6-5-4 = tens of minutes, bits 3-2-1-0 = units of minutes

byte hours_address = 0x02; 
byte hours;  // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
// bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
// bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)

byte day_week_address = 0x03; 
byte day_week = 0; // range 01-07

byte date_month_address = 0x04;
byte date_month = 0; // range 01-31

byte month_address = 0x05;
byte month = 0; // range 01-12

byte year_address = 0x06;
int year = 0; // upper byte 0-9, lower byte 0-9

byte square_address = 0x07;
byte sqwe = 0;  // square wave enable
// Out-0-0-Sqwe-0-0-RS1-RS0
// Out, Sqwe = 0/0 - Square wave output = 0
// Out, Sqwe = 1/0 - Square wave output = 1
// Out, Sqwe = 0/1 or 1/1 - Square wave output per RS1/RS0
// RS1/RS0 = 00 = 1 Hz
// RS1/RSo = 01 = 4 KHz
// RS1/RS0 = 10 = 8 KHz
// RS1/RS0 = 11 = 32 KHz

byte RTC_ram_address = 0x08; //range = 08-63, 0x08-0x3F

int RTC_address = 0x68; // 1101 000 

byte incomingCommand = 0;
byte RTC_write_command = 0;
byte RTC_read_command = 0;
byte RTC_ram_command = 0;

byte incomingRegister = 0;
byte RTC_register = 0;
byte incomingData1 = 0;
byte incomingData2 = 0;
byte new_data = 0;
byte outgoingData = 0;
int delay_time = 100;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long duration = 5000;

void setup() {
  Wire.begin(); // no address, we are master
  Serial.begin (57600);  
  Serial.flush();
  currentMillis = millis();  
}

void loop() {

  if (Serial.available() >3){
    incomingCommand = Serial.read();
    incomingRegister = Serial.read();
    incomingData1 = Serial.read();
    incomingData1 = incomingData1 - 0x30; // convert ASCII to HEX
    incomingData2 = Serial.read();
    incomingData2 = incomingData2 - 0x30;  // convert ASCII to HEX
    new_data = (incomingData1 << 4) + incomingData2;  // put the Upper/Lower nibbles together
    Serial.print ("command ");
    Serial.println (incomingCommand);
    Serial.print ("register ");
    Serial.println(incomingRegister);
    Serial.print ("data1 ");
    Serial.println (incomingData1, HEX);
    Serial.print ("data2 ");
    Serial.println (incomingData2, HEX);
    Serial.print ("combined data ");    
    Serial.println (new_data, HEX);
    
  }
  // *******************************************
//  RTC_write_command = incomingCommand & 0xF0;  // mask off high byte
//  if (RTC_write_command == 0xF0){  // check for Write command
if ((incomingCommand == 'F') | (incomingCommand == 'f')){
  incomingCommand = 0;  // reset for next pass
//    RTC_register = incomingCommand & 0x0F;  // mask off low btye
//    incomingCommand = 0;
//    new_data = incomingData;
    Serial.println (" Sending a command ");
//    switch (RTC_register){
switch (incomingRegister){
  case '0': // write seconds
        Serial.println ("Seconds ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.send(seconds_address);          // queue the register
      Wire.send(new_data);                  // queue data
      Wire.endTransmission();            // send it
      delay (delay_time);
      break;
    case '1': // write minutes
    Serial.println ("Minutes ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.send(minutes_address);          // queue the register
      Wire.send(new_data);                  // queue data
      Wire.endTransmission();            // send it
      delay (delay_time);
      break;
    case '2': // write hours
        Serial.println ("Hours ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.send(hours_address);          // queue the register
      Wire.send(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '3': // write day
        Serial.println ("Day ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.send(day_week_address);          // queue the register
      Wire.send(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '4': // write date of month
        Serial.println ("Day of Month ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.send(date_month_address);          // queue the register
      Wire.send(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '5': // write month
        Serial.println ("Month ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.send(month_address);          // queue the register
      Wire.send(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '6': // write year
        Serial.println ("Year ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.send(year_address);          // queue the register
      Wire.send(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '7': // write square wave
        Serial.println ("Square Wave ");
    Serial.println (RTC_register, HEX);
      Wire.beginTransmission(RTC_address); // select device
      Wire.send(square_address);          // queue the register
      Wire.send(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '8': // write RAM
        Serial.print ("RAM ");
    Serial.println (RTC_register, HEX);
      Wire.beginTransmission(RTC_address); // select device
      Wire.send(RTC_ram_address);          // queue the register
      Wire.send(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
      // all others,do nothing
      Serial.println ("Invalid command ");
    }  // end Switch
  } // end if command == 'F'
  // ************************************

  currentMillis = millis();
  if ( (currentMillis - previousMillis) >= duration){
    previousMillis = currentMillis;  
    // Reset the register pointer  
    Wire.beginTransmission(RTC_address);  
    Wire.send(0x00);  
    Wire.endTransmission();   

    Wire.requestFrom(RTC_address,8 );  
    seconds = Wire.receive();  
    minutes = Wire.receive();  
    hours = Wire.receive();  
    day_week = Wire.receive();  
    date_month = Wire.receive();  
    month = Wire.receive();  
    year = Wire.receive();  
    sqwe = Wire.receive();

    // Seconds 
    // bit 7 = Clock Halt, Enabled = 0, Halt = 1
    // bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9 

    // Hours
    // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
    // bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
    // bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)

    Serial.print ("Hrs " );
    Serial.print (hours, HEX);
    Serial.print (" Mins ");
    Serial.print (minutes, HEX);
    Serial.print (" Secs ");
    Serial.print (seconds, HEX);
    Serial.print (" Day ");
    Serial.print (day_week, HEX);
    Serial.print (" Date ");
    Serial.print (date_month, HEX);
    Serial.print (" Month ");
    Serial.print (month, HEX);
    Serial.print (" Year 20");
    Serial.print (year, HEX);
    Serial.print (" Square Wave ");
    Serial.println (sqwe, HEX);

  }
}

Plecto: Hi. I'm making a simple digital alarm clock for my moms cooking. The code itself works just fine and can be found here: http://pastebin.ca/2098613 The atmega328 drives a 2-digit 7-segment display telling my mom the minutes left, when the timer goes down to zero it drives a buzzer through a 2n2222 NPN transistor.

I read in the site below that it is possible to get the idle power consumption of the atmega328 down to 6.8uA which is a massiv decrease. http://jeelabs.org/2009/05/16/power-consumption-more-savings/ though my problem is that my understanding when it comes to programming, C and MCU's is very slim so I have no idea what the code on that sites mean. I am wondering if there is some kind of "quick fix" to lower the chips idle power consumption? Something I can easly implement with my code without ruining everything :P

I just use the Sleep class from Jeelabs library, it encapsulates the sleep functionality.

Also you can sleep for a few seconds, wake up just long enough to check a pin state and go back to the sleep loop - not as power efficient as interrupt but still a massive saving.

The RTC also has the advantage of keeping much more accurate time than a Resonator drivern UNO if that's what you're using.

I believe the square wave output is off by default, you send it command using Wire.h library to make it start.
I can look it up when I get home if it is not posted already when I get there.
Someone will likely say to use some library, I just used mine with discrete I2C commands.
The square wave output needs to be pulled up with a 10K resistor.

I got the 1307 wired up now and I’ve been scouting google for examples and guides to how to use it, but I am completely clueless. Understanding the way of serial communications seems extremely hard so I thought I could just copy some code to atleast make it give a square wave ouput, but no. Every code I have found gives me an error message when uploading. I found one example using some 1307 library (DS1307 RTC tutorial) and I managed to upload that code, but the serial monitor only gives me a series of wierd signs (ç¤Úåòæ®Ð0#BWï?<Kä etc.). I also tried uploading the code you pasted, but then I get “Wire.send() has been renamed Wire.write()” which is fine, but changing it to Wire.write() gives me this error message “call of overloaded ‘write(int)’ is ambiguous”.

So change back to -0023, and try it there. I used that code for testing, and several others in the forum have, so I know it works.

but then I get "Wire.send() has been renamed Wire.write()" which is fine, but changing it to Wire.write() gives me this error message "call of overloaded 'write(int)' is ambiguous".

Probably because the code contains something like:

Wire.write(0);

Change that to

Wire.write((byte)0);

I got it to upload now :D There is a couple of more things I can't figure out though. I can't see what pins I should connect to 1307 from my arduino. I see that there are no pinModes set in the void setup() so I assume that analog outputs are used instead?

I also found this:

byte square_address = 0x07; byte sqwe = 0; // square wave enable // Out-0-0-Sqwe-0-0-RS1-RS0 // Out, Sqwe = 0/0 - Square wave output = 0 // Out, Sqwe = 1/0 - Square wave output = 1 // Out, Sqwe = 0/1 or 1/1 - Square wave output per RS1/RS0 // RS1/RS0 = 00 = 1 Hz // RS1/RSo = 01 = 4 KHz // RS1/RS0 = 10 = 8 KHz // RS1/RS0 = 11 = 32 KHz

I see that sqwe have to be set to "1" to enable the square wave, though I can't see where I choose the frequency of it :(