3

This is my first post. Please excuse me if this is a repost, but I couldn't find a similar question via search.

I have some experience with Arduino and I'm looking to utilize AVR's sleep mode in a project. I followed along with this tutorial here. However, when I modify the code as follows, the uC seems to wait 4.09 seconds before waking up the first time. After that, it wakes up repeatedly (about every 6 milliseconds).

In my mind, the Arduino should enter sleep mode and not wake until the timer interrupt wakes it every 4.09 seconds (and then repeats and sleeps again). When I add a delayMicroseconds() after each wake up, it seems to function correctly. I want to accomplish sleep until interrupt wakes, perform interrupted action, then go back to sleep. What's going on? Am I missing something obvious? Is the Serial.println() causing an interrupt that wakes the uC right as it enters sleep?

Thanks for the help!

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

ISR(TIMER1_OVF_vect)
{
 //do nothing  
}


void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_IDLE);

  sleep_enable();


  /* Disable all of the unused peripherals. This will reduce power
   * consumption further and, more importantly, some of these
   * peripherals may generate interrupts that will wake our Arduino from
   * sleep!
   */
  power_adc_disable();
  power_spi_disable();
  power_timer0_disable();
  power_timer2_disable();
  power_twi_disable();  

  /* Now enter sleep mode. */
  sleep_mode();

  /* The program will continue from here after the timer timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */

  /* Re-enable the peripherals. */
  power_all_enable();
}

void setup()
{
  Serial.begin(9600);

  /*** Configure the timer.***/

  /* Normal timer operation.*/
  TCCR1A = 0x00; 

  /* Clear the timer counter register.
   * You can pre-load this register with a value in order to 
   * reduce the timeout period, say if you wanted to wake up
   * ever 4.0 seconds exactly.
   */
  TCNT1=0x0000; 

  /* Configure the prescaler for 1:1024, giving us a 
   * timeout of 4.09 seconds.
   */
  TCCR1B = 0x05;

  /* Enable the timer overlow interrupt. */
  TIMSK1=0x01;
  while(!Serial);
}

void loop()
{
    enterSleep();
    Serial.println("Waking");
    //delayMicroseconds(10000);
}

1 Answer 1

3

Yes. Arduino's buffered serial output is interrupt-based, in that it uses interrupts to refill the UART transmit register when it runs empty, until the software-managed transmit buffer has been drained.

You cannot put the ATmega back to "lasting" sleep until the last byte of the serial transmission has been written to the UART hardware.

If the goal of your serial output is only debug, it might be simplest to shorten it to a single character and either send that directly or wait long enough that it should have sent. If you want to keep the full message, it may take exploration of the Arduino source code to figure out how to determine when the transmission is done. A simpler, if cruder option might be to just keep going back to sleep until a readback of the counter indicates that your intended sleep is over.

2
  • 4
    You can use Serial.flush() to block until all the data has been sent from the buffer (and the last byte has been sent from the UART internal buffer register).
    – Majenko
    Commented Nov 30, 2015 at 0:08
  • Great! Thank you! Both very helpful answers.
    – CamK
    Commented Nov 30, 2015 at 3:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.