MrAlvin

Arduino Sleep functions

Oct 24th, 2016
173
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.69 KB | None | 0 0
  1. #define BAUD 9600
  2.  
  3. #include <avr/sleep.h>           // the important one for sleep ability
  4. #include <avr/wdt.h>             // Watch Dog Timer extension
  5. #include <avr/power.h>           // used to easier turn off unused modules in the AVR chip
  6. #include "wiring.c"              // to enable our millis() hack after being asleep
  7.  
  8.  
  9. // /*****\ Variables to be used in this sketch (program)  /*****\
  10.  
  11. //***** Basic Blink example, but without the use of delay()
  12. const int blink_pin = 13;    //the pin number that the LED is connected to
  13. const int on_delay = 500;    //change this value to adjust the number of MilliSeconds the LED is ON
  14. const int off_delay = 500;   //change this value to adjust the number of MilliSeconds the LED is OFF
  15.  
  16. //***** Misc. variables
  17. int loop_count = 0;
  18.  
  19.  
  20. //***** WDT (Watch Dog Timer) variables
  21. volatile bool sleep_entered = false;     // flag used to see if watchDog timeout is only a wakeup call,
  22.                                          // or a true Reset is needed
  23.  
  24.                                          
  25. //************************************************//
  26. //****                                        ****//
  27. //****           Setup                        ****//
  28. //****                                        ****//
  29. //************************************************//
  30. void setup() {
  31.  
  32.   // initialize serial communications at 9600 bps:
  33.   Serial.begin(BAUD);
  34.   Serial.println( F("Hello World!") );
  35.  
  36.  
  37.   // initialize digital pin 13 as an output.
  38.   pinMode(blink_pin, OUTPUT);
  39.  
  40. }
  41.  
  42. //************************************************//
  43. //****                                        ****//
  44. //****           Main Loop                    ****//
  45. //****                                        ****//
  46. //************************************************//
  47. void loop() {
  48.   Blink_example();
  49.  
  50.  
  51.   debug_info();   //some development and debug info,  once every second only
  52.   loop_count++;   //gives an option to see how many times loop() is run per second
  53.  
  54.   sleepNow();
  55.  
  56.   wdt_reset();
  57. }
  58.  
  59.  
  60.  
  61.  
  62. //************************************************//
  63. //****                                        ****//
  64. //****           SLEEP functions              ****//
  65. //****                                        ****//
  66. //************************************************//
  67.  
  68. void sleepNow()         // here we put the arduino to sleep
  69. {
  70.   wdt_disable();            // waiting for the serial buffer to empty might take long, so no WDT during this time
  71.   Serial.flush();           // waiting for the serial send buffer to empty (as of Arduino ver.1.00)
  72.   wdt_reset();              // reset the WDT counter, so we sleep a full WDT counter cycle
  73.   wdt_interrupt_enable();   // enable the WDT again
  74.    
  75.     /* Now is the time to set the sleep mode. In the Atmega328 datasheet
  76.      * http://www.atmel.com/Images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet.pdf
  77.      * page 38 (section 10) there is a list of sleep modes which explains
  78.      * which clocks and wake up sources are available in which sleep mode.
  79.      *
  80.      * In the avr/sleep.h file, the call names of these sleep modes are to be found:
  81.      *
  82.      * The 5 different modes are:
  83.      *     SLEEP_MODE_IDLE          - the least power savings
  84.      *     SLEEP_MODE_ADC
  85.      *     SLEEP_MODE_PWR_SAVE      - main clock is still running, so wake time can be quicker (but is not on an Arduino)
  86.      *                                * wake time is 16K clock cycles on an Arduino (16K clock cycles @ 16MHz crystal is 1 milli second)
  87.      *                                * software BOD Disable is possible
  88.      *     SLEEP_MODE_STANDBY       - same as PWR_SAVE, but needs extermal clock source (crystal or resonator is ok)
  89.      *                                * waketime is only 6 clock cycles
  90.      *                                * software BOD Disable is possible, but will cause a minimum waketime of 60μs (960 clock cycles @ 16MHz external clock)
  91.      *     SLEEP_MODE_PWR_DOWN      - the most power savings
  92.      *                                * waketime is 16K clock cycles on an Arduino (16K clock cycles @ 16MHz crystal is 1 milli second)
  93.      *                                * software BOD Disable is possible
  94.      */
  95.      
  96.     //set_sleep_mode(SLEEP_MODE_STANDBY);   // sleep mode is set here
  97.     set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  98.  
  99.     sleep_enable();          // enables the sleep bit in the mcucr register
  100.                              // so sleep is possible. just a safety pin
  101.                              
  102.     sleep_entered = true;    // used by WDT Interrupt to see if we are just waking up from sleep,
  103.                              // or WDT Interrupt was actually caused by a program loop error
  104.                              
  105.     sleep_mode();            // here the device is actually put to sleep!!
  106.    
  107.        // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
  108.  
  109.     sleep_disable();         // first thing after waking from sleep:
  110.                              // disable sleep...
  111.                              
  112.     wdt_interrupt_enable();  // setup the wdt interrupt option as it might have been reset by the wakeup call.                            
  113.  
  114.     timer0_millis = timer0_millis + 125 + 1;  // a hack - to update milis() after sleeping
  115.                                               // WDT is set to 64ms,
  116.                                               // wake time from pwr_down is 1ms
  117.                                               // wake time from standby is 0ms
  118.                                               // Do NOT use anything but constants in the equation above, or it will take way too long
  119.                                               // and it will mess up the entire sleep system and the millis() timing.
  120. }  
  121.  
  122.  
  123.  
  124. //*****************************************************//
  125. //****                                             ****//
  126. //****       WDT (Watch Dog Timer) functions       ****//
  127. //****                                             ****//
  128. //*****************************************************//
  129.  
  130. void wdt_interrupt_enable()
  131. {
  132.      // A 'timed' sequence is required for configuring the WDT, so we need to
  133.     // disable interrupts here.
  134.      cli();   //Disables all interrupts by clearing the global interrupt mask.
  135.    
  136.     wdt_reset();  // reset the counter, just to be on the safe side.
  137.    
  138.     MCUSR &= ~_BV(WDRF);
  139.    
  140.     /* Start the WDT Config change sequence. */
  141.     WDTCSR |= _BV(WDCE) | _BV(WDE);
  142.    
  143.     /* Configure the prescaler and the WDT for interrupt mode only - cause interrupt after X (milli) seconds of no call to "wdt_reset();" */
  144.    
  145.     // WDTCSR = _BV(WDIE);                                     // 16 milli seconds
  146.     // WDTCSR = _BV(WDP0) | _BV(WDIE);                         // 32 milli seconds
  147.     // WDTCSR = _BV(WDP1) | _BV(WDIE);                         // 64 milli seconds
  148.     WDTCSR = _BV(WDP0) | _BV(WDP1) | _BV(WDIE);             // 1/8 second (125 ms)
  149.     // WDTCSR = _BV(WDP2) | _BV(WDIE);                         // 1/4 second (250 ms
  150.     // WDTCSR = _BV(WDP0) | _BV(WDP2) | _BV(WDIE);             // 1/2 second (500 ms)
  151.     // WDTCSR = _BV(WDP1) | _BV(WDP2) | _BV(WDIE);             // 1 second
  152.     // WDTCSR =  _BV(WDP0) | _BV(WDP1) | _BV(WDP2) | _BV(WDIE);   // 2 seconds
  153.     // WDTCSR =  _BV(WDP0) | _BV(WDP3) | _BV(WDIE);            // 8 seconds
  154.    
  155.     sei();     //Enables interrupts again by setting the global interrupt mask.
  156. }
  157.  
  158.  
  159. /*
  160.  * The routine called by The watchdog interrupt.
  161.  *    The watchdog has two functions:
  162.  *      1) to detect if the application code has locked up.
  163.  *      2) to wake up the module from sleep.
  164.  */
  165. ISR(WDT_vect)
  166. {
  167.     /* Check if we are in sleep mode or it is a genuine WDR. */
  168.     if(sleep_entered == false) {
  169.         /* The app has locked up, force a WDR. */
  170.         wdt_enable(WDTO_15MS);
  171.         while(1);
  172.     } else {
  173.         wdt_reset();
  174.         /* Service the timer if necessary. */
  175.         sleep_entered = false;
  176.         sleep_disable();
  177.     }
  178. }
  179.  
  180. //*****************************************************//
  181. //****                                             ****//
  182. //****       debug info                            ****//
  183. //****                                             ****//
  184. //*****************************************************//
  185. void debug_info() {
  186.  static unsigned long last_millis = 0;
  187.  
  188.  if(millis() - last_millis >  1000)  {  //update once every second
  189.      last_millis = millis();            //ready for next update
  190.      
  191.      Serial.print(F("loop: "));
  192.      Serial.print( loop_count );
  193.      Serial.println();
  194.  
  195.     loop_count = 0;       // reset loop_count
  196.  }
  197. }
  198.  
  199.  
  200. //*****************************************************//
  201. //****                                             ****//
  202. //****       Blink                                 ****//
  203. //****                                             ****//
  204. //*****************************************************//
  205.  
  206. void Blink_example()
  207. {
  208.   static unsigned long blink_millis = 0;
  209.   static unsigned long blink_interval = 0;
  210.   static boolean do_on = true;
  211.  
  212.   if ( millis() - blink_millis >  blink_interval )  { // if its time to change the blink
  213.     if (do_on) { //use a flag to determine wether to turn on or off the Blink LED
  214.       digitalWrite(blink_pin, HIGH);   // set the LED on, if okay to use power for it
  215.       blink_millis = millis();
  216.       blink_interval = on_delay; // wait for a second
  217.       do_on = false;
  218.     }else{
  219.       digitalWrite(blink_pin, LOW);    // set the LED off
  220.       // set the time to do next blink
  221.       blink_millis = millis();
  222.       blink_interval = off_delay;  // wait for a second
  223.       do_on = true;
  224.     }
  225.   }
  226. }
Advertisement
Add Comment
Please, Sign In to add comment