Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define BAUD 9600
- #include <avr/sleep.h> // the important one for sleep ability
- #include <avr/wdt.h> // Watch Dog Timer extension
- #include <avr/power.h> // used to easier turn off unused modules in the AVR chip
- #include "wiring.c" // to enable our millis() hack after being asleep
- // /*****\ Variables to be used in this sketch (program) /*****\
- //***** Basic Blink example, but without the use of delay()
- const int blink_pin = 13; //the pin number that the LED is connected to
- const int on_delay = 500; //change this value to adjust the number of MilliSeconds the LED is ON
- const int off_delay = 500; //change this value to adjust the number of MilliSeconds the LED is OFF
- //***** Misc. variables
- int loop_count = 0;
- //***** WDT (Watch Dog Timer) variables
- volatile bool sleep_entered = false; // flag used to see if watchDog timeout is only a wakeup call,
- // or a true Reset is needed
- //************************************************//
- //**** ****//
- //**** Setup ****//
- //**** ****//
- //************************************************//
- void setup() {
- // initialize serial communications at 9600 bps:
- Serial.begin(BAUD);
- Serial.println( F("Hello World!") );
- // initialize digital pin 13 as an output.
- pinMode(blink_pin, OUTPUT);
- }
- //************************************************//
- //**** ****//
- //**** Main Loop ****//
- //**** ****//
- //************************************************//
- void loop() {
- Blink_example();
- debug_info(); //some development and debug info, once every second only
- loop_count++; //gives an option to see how many times loop() is run per second
- sleepNow();
- wdt_reset();
- }
- //************************************************//
- //**** ****//
- //**** SLEEP functions ****//
- //**** ****//
- //************************************************//
- void sleepNow() // here we put the arduino to sleep
- {
- wdt_disable(); // waiting for the serial buffer to empty might take long, so no WDT during this time
- Serial.flush(); // waiting for the serial send buffer to empty (as of Arduino ver.1.00)
- wdt_reset(); // reset the WDT counter, so we sleep a full WDT counter cycle
- wdt_interrupt_enable(); // enable the WDT again
- /* Now is the time to set the sleep mode. In the Atmega328 datasheet
- * http://www.atmel.com/Images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet.pdf
- * page 38 (section 10) there is a list of sleep modes which explains
- * which clocks and wake up sources are available in which sleep mode.
- *
- * In the avr/sleep.h file, the call names of these sleep modes are to be found:
- *
- * The 5 different modes are:
- * SLEEP_MODE_IDLE - the least power savings
- * SLEEP_MODE_ADC
- * SLEEP_MODE_PWR_SAVE - main clock is still running, so wake time can be quicker (but is not on an Arduino)
- * * wake time is 16K clock cycles on an Arduino (16K clock cycles @ 16MHz crystal is 1 milli second)
- * * software BOD Disable is possible
- * SLEEP_MODE_STANDBY - same as PWR_SAVE, but needs extermal clock source (crystal or resonator is ok)
- * * waketime is only 6 clock cycles
- * * software BOD Disable is possible, but will cause a minimum waketime of 60μs (960 clock cycles @ 16MHz external clock)
- * SLEEP_MODE_PWR_DOWN - the most power savings
- * * waketime is 16K clock cycles on an Arduino (16K clock cycles @ 16MHz crystal is 1 milli second)
- * * software BOD Disable is possible
- */
- //set_sleep_mode(SLEEP_MODE_STANDBY); // sleep mode is set here
- set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
- sleep_enable(); // enables the sleep bit in the mcucr register
- // so sleep is possible. just a safety pin
- sleep_entered = true; // used by WDT Interrupt to see if we are just waking up from sleep,
- // or WDT Interrupt was actually caused by a program loop error
- 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...
- wdt_interrupt_enable(); // setup the wdt interrupt option as it might have been reset by the wakeup call.
- timer0_millis = timer0_millis + 125 + 1; // a hack - to update milis() after sleeping
- // WDT is set to 64ms,
- // wake time from pwr_down is 1ms
- // wake time from standby is 0ms
- // Do NOT use anything but constants in the equation above, or it will take way too long
- // and it will mess up the entire sleep system and the millis() timing.
- }
- //*****************************************************//
- //**** ****//
- //**** WDT (Watch Dog Timer) functions ****//
- //**** ****//
- //*****************************************************//
- void wdt_interrupt_enable()
- {
- // A 'timed' sequence is required for configuring the WDT, so we need to
- // disable interrupts here.
- cli(); //Disables all interrupts by clearing the global interrupt mask.
- wdt_reset(); // reset the counter, just to be on the safe side.
- MCUSR &= ~_BV(WDRF);
- /* Start the WDT Config change sequence. */
- WDTCSR |= _BV(WDCE) | _BV(WDE);
- /* Configure the prescaler and the WDT for interrupt mode only - cause interrupt after X (milli) seconds of no call to "wdt_reset();" */
- // WDTCSR = _BV(WDIE); // 16 milli seconds
- // WDTCSR = _BV(WDP0) | _BV(WDIE); // 32 milli seconds
- // WDTCSR = _BV(WDP1) | _BV(WDIE); // 64 milli seconds
- WDTCSR = _BV(WDP0) | _BV(WDP1) | _BV(WDIE); // 1/8 second (125 ms)
- // WDTCSR = _BV(WDP2) | _BV(WDIE); // 1/4 second (250 ms
- // WDTCSR = _BV(WDP0) | _BV(WDP2) | _BV(WDIE); // 1/2 second (500 ms)
- // WDTCSR = _BV(WDP1) | _BV(WDP2) | _BV(WDIE); // 1 second
- // WDTCSR = _BV(WDP0) | _BV(WDP1) | _BV(WDP2) | _BV(WDIE); // 2 seconds
- // WDTCSR = _BV(WDP0) | _BV(WDP3) | _BV(WDIE); // 8 seconds
- sei(); //Enables interrupts again by setting the global interrupt mask.
- }
- /*
- * The routine called by The watchdog interrupt.
- * The watchdog has two functions:
- * 1) to detect if the application code has locked up.
- * 2) to wake up the module from sleep.
- */
- ISR(WDT_vect)
- {
- /* Check if we are in sleep mode or it is a genuine WDR. */
- if(sleep_entered == false) {
- /* The app has locked up, force a WDR. */
- wdt_enable(WDTO_15MS);
- while(1);
- } else {
- wdt_reset();
- /* Service the timer if necessary. */
- sleep_entered = false;
- sleep_disable();
- }
- }
- //*****************************************************//
- //**** ****//
- //**** debug info ****//
- //**** ****//
- //*****************************************************//
- void debug_info() {
- static unsigned long last_millis = 0;
- if(millis() - last_millis > 1000) { //update once every second
- last_millis = millis(); //ready for next update
- Serial.print(F("loop: "));
- Serial.print( loop_count );
- Serial.println();
- loop_count = 0; // reset loop_count
- }
- }
- //*****************************************************//
- //**** ****//
- //**** Blink ****//
- //**** ****//
- //*****************************************************//
- void Blink_example()
- {
- static unsigned long blink_millis = 0;
- static unsigned long blink_interval = 0;
- static boolean do_on = true;
- if ( millis() - blink_millis > blink_interval ) { // if its time to change the blink
- if (do_on) { //use a flag to determine wether to turn on or off the Blink LED
- digitalWrite(blink_pin, HIGH); // set the LED on, if okay to use power for it
- blink_millis = millis();
- blink_interval = on_delay; // wait for a second
- do_on = false;
- }else{
- digitalWrite(blink_pin, LOW); // set the LED off
- // set the time to do next blink
- blink_millis = millis();
- blink_interval = off_delay; // wait for a second
- do_on = true;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment