sleep mode

Hey guys, I’m hoping someone can help me out. I’m interested in mailing an arduino project as a gift. The project is the adafruit waveshield connected to an ambi light sensor. When the sensor detects a certain level of light (when the box is opened) I want it to play a song. Its going to be in transit for about 7 days so I’m assuming I’ll have to use an arduino sleep mode? I’ve been reading up about it but since this is a gift I don’t want to mess it up. Could someone help me modify the code to add a sleep function for 7 days? Also, I’ll be powering the project with 8 AA batteries wired in series.

#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"

SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the filesystem on the card

uint8_t dirLevel; // indent level for file/dir names    (for prettyprinting)
dir_t dirBuf;     // buffer for directory reads

WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

int LDR = 0; // LDR Pin
int val = 0;       // variable to store the value coming from the sensor



// Function definitions (we define them here, but the code is below)
void lsR(FatReader &d);
void play(FatReader &dir);

void setup() {
  Serial.println(analogRead(0));   // print out value of light sensor on analog pin 0
  val = analogRead(LDR);       // read the value from the sensor
  if ( val > 500 ) play(root);
  
  Serial.begin(9600);           // set up Serial library at 9600 bps for debugging
  pinMode(LDR, INPUT);       // declare the LDR as an INPUT
  putstring_nl("\nWave test!");  // say we woke up!
  
  putstring("Free RAM: ");       // This can help with debugging, running out of RAM is bad
  Serial.println(freeRam());  
 
  // Set the output pins for the DAC control. This pins are defined in the library
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  
  //  if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
  if (!card.init()) {         //play with 8 MHz spi (default faster!)  
    putstring_nl("Card init. failed!");  // Something went wrong, lets print out why
    sdErrorCheck();
    while(1);                            // then 'halt' - do nothing!
  }
  
  // enable optimize read - some cards may timeout. Disable if you're having problems
  card.partialBlockRead(true);
  
  // Now we will look for a FAT partition!
  uint8_t part;
  for (part = 0; part < 5; part++) {     // we have up to 5 slots to look in
    if (vol.init(card, part)) 
      break;                             // we found one, lets bail
  }
  if (part == 5) {                       // if we ended up not finding one  :(
    putstring_nl("No valid FAT partition!");
    sdErrorCheck();      // Something went wrong, lets print out why
    while(1);                            // then 'halt' - do nothing!
  }
  

  
  // Try to open the root directory
  if (!root.openRoot(vol)) {
    putstring_nl("Can't open root dir!"); // Something went wrong,
    while(1);                             // then 'halt' - do nothing!
  }
  
  // Whew! We got past the tough parts.
  putstring_nl("Files found:");
  dirLevel = 0;
  // Print out all of the files in all the directories.
  lsR(root);
}

//////////////////////////////////// LOOP
void loop() { 
     root.rewind();
//  play(root);
  val = analogRead(LDR);       // read the value from the sensor
if ( val > 500 ) play(root);
}

/////////////////////////////////// HELPERS

// this handy function will return the number of bytes currently free in RAM, great for debugging!   
int freeRam(void)
{
  extern int  __bss_end; 
  extern int  *__brkval; 
  int free_memory; 
  if((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end); 
  }
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval); 
  }
  return free_memory; 
} 

/*
 * print error message and halt if SD I/O error, great for debugging!
 */
void sdErrorCheck(void)
{
  if (!card.errorCode()) return;
  putstring("\n\rSD I/O error: ");
  Serial.print(card.errorCode(), HEX);
  putstring(", ");
  Serial.println(card.errorData(), HEX);
  while(1);
}
/*
 * print dir_t name field. The output is 8.3 format, so like SOUND.WAV or FILENAME.DAT
 */
void printName(dir_t &dir)
{
  for (uint8_t i = 0; i < 11; i++) {     // 8.3 format has 8+3 = 11 letters in it
    if (dir.name[i] == ' ')
        continue;         // dont print any spaces in the name
    if (i == 8) 
        Serial.print('.');           // after the 8th letter, place a dot
    Serial.print(dir.name[i]);      // print the n'th digit
  }
  if (DIR_IS_SUBDIR(dir)) 
    Serial.print('/');       // directories get a / at the end
}
/*
 * list recursively - possible stack overflow if subdirectories too nested
 */
void lsR(FatReader &d)
{
  int8_t r;                     // indicates the level of recursion
  
  while ((r = d.readDir(dirBuf)) > 0) {     // read the next file in the directory 
    // skip subdirs . and ..
    if (dirBuf.name[0] == '.') 
      continue;
    
    for (uint8_t i = 0; i < dirLevel; i++) 
      Serial.print(' ');        // this is for prettyprinting, put spaces in front
    printName(dirBuf);          // print the name of the file we just found
    Serial.println();           // and a new line
    
    if (DIR_IS_SUBDIR(dirBuf)) {   // we will recurse on any direcory
      FatReader s;                 // make a new directory object to hold information
      dirLevel += 2;               // indent 2 spaces for future prints
      if (s.open(vol, dirBuf)) 
        lsR(s);                    // list all the files in this directory now!
      dirLevel -=2;                // remove the extra indentation
    }
  }
  sdErrorCheck();                  // are we doign OK?
}
/*
 * play recursively - possible stack overflow if subdirectories too nested
 */
void play(FatReader &dir)
{
  FatReader file;
  while (dir.readDir(dirBuf) > 0) {    // Read every file in the directory one at a time
    // skip . and .. directories
    if (dirBuf.name[0] == '.') 
      continue;
    
    Serial.println();            // clear out a new line
    
    for (uint8_t i = 0; i < dirLevel; i++) 
       Serial.print(' ');       // this is for prettyprinting, put spaces in front

    if (!file.open(vol, dirBuf)) {       // open the file in the directory
      Serial.println("file.open failed");  // something went wrong :(
      while(1);                            // halt
    }
    
    if (file.isDir()) {                    // check if we opened a new directory
      putstring("Subdir: ");
      printName(dirBuf);
      dirLevel += 2;                       // add more spaces
      // play files in subdirectory
      play(file);                         // recursive!
      dirLevel -= 2;    
    }
    else {
      // Aha! we found a file that isnt a directory
      putstring("Playing "); printName(dirBuf);       // print it out
      if (!wave.create(file)) {            // Figure out, is it a WAV proper?
        putstring(" Not a valid WAV");     // ok skip it
      } else {
        Serial.println();                  // Hooray it IS a WAV proper!
        wave.play();                       // make some noise!
       
        while (wave.isplaying) {           // playing occurs in interrupts, so we print dots in realtime
          putstring(".");
          delay(100);
        }
        sdErrorCheck();                    // everything OK?
//        if (wave.errors)Serial.println(wave.errors);     // wave decoding errors
      }
    }
  }
}

I’m not an expert in these things
but can’t you simply get the 'duino to wake up when it sees the light?
tie an interrupt to the light sensor

plan B is to have a piece of plastic or somesuch that isolates the batteries
mark it “pull me” in bright red
(some clocks use this method)

finally
8 in series! 12 volts???

jeffd: opened) I want it to play a song. Its going to be in transit for about 7 days so I’m assuming I’ll have to use an arduino sleep mode?

First: Are you sure 7 days is too long? Measure the power consumption while idle, and see whether the batteries won't actually last anyway.

Second: You really only need 5 1.5V batteries to get to 7.5 volts, which is sufficient to drive the 5V regulator. Try putting in 5 "C" size batteries, and I'm pretty sure the idle card will last for more than 7 days.

Third: You don't need to sleep for 7 days -- what if the delivery is fast? Instead, you probably want to sleep for 1 second, then wake up only long enough to detect light or not, then go to sleep again. Once you detect light, drive some pin high to turn on power for the wave player -- it should be idle when not used! -- and start playing the wave. Waking up for 1 ms each second is going to reduce power consumption by a very large amount, and probably will get you where you need to go with 5 AA batteries. (Unless the Wave shield needs 12V?)

Outline:

setup:
  turn off power to ambi
  turn off power to wave shield

loop:
  sleep 1 second
  turn on power to ambi
  read ambi light
  turn off power to ambi
  if light:
    turn on power to wave player
    wait for wave player to stabilize/boot (if needed)
    play wave
    turn off power to wave player

This will also allow you to actually pack up the device. It will play the song immediately when reset, but then when you pack it into darkness, it will go quiet until it sees light again.

Thanks for the great suggestions! I'm not really sure how to program that though, Im kind of a noob when it comes to C.

Keep in mind that sleep mode only puts the ATmega328 to sleep, not the Arduino. The Waveshield, Power LED, 8U2 (or FT232 on older boards), 5V reg, and 3V3 reg are all going to still be running. You might be saving a few millliamps while the rest of the circuit is still drawing 10s of milliamps.

jeffd: When the sensor detects a certain level of light (when the box is opened) I want it to play a song.

A microswitch on the box lid (one of those ones with a long lever) connected to the battery is all that is required, isn't it? Then the sketch fires up and plays the tune. Simple and effective. And you can test it at home, and there is no reason why it wouldn't work at the other end (eg. no worries about the light level, or whether it stayed asleep, or whether the batteries ran down).

Also: Do you need to power the Ardy through the regulator? I imagine that it might be 6V tolerant (4 AA or C batteries) or 4.5V capable (3 AA or C batteries).
Anyway, a lid open detector is probably simpler :slight_smile: