
I use that code as a basis for all my sensor sketch developments with a Attiny85 chip.
It might be useful for some geeks out there.
Actually, this page is a kind of reminder and a startup for all my new project. It’s based on the use of watchdog timers and interrupts which is a very simple way to code sensors (temperature, humidity, shock, etc) and very efficient for not wasting power for the circuit. A Attiny85 should draw only a few µA when sleeping.
//
// http://blog.onlinux.fr
//
// +-\/-+
// Ain0 (D 5) PB5 1| |8 Vcc
// Ain3 (D 3) PB3 2| |7 PB2 (D 2) Ain1
// Ain2 (D 4) PB4 3| |6 PB1 (D 1) pwm1
// GND 4| |5 PB0 (D 0) pwm0
// +----+
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
//
// W H Y V O L A T I L E ?
//
// Why volatile?
// ---->
// https://www.arduino.cc/en/Reference/Volatile
// volatile keyword:
// Specifically, it directs the compiler to load the variable from RAM and not from a storage register,
// which is a temporary memory location where program variables are stored and manipulated.
// Under certain conditions, the value for a variable stored in registers can be inaccurate.
volatile boolean f_wdt = 1;
// Use pin PB0 as wake up pin
const int wakeUpPin = 0;
const byte pinLed = 4;
const byte pinLedRed = 3;
void blink(int ii) {
pinMode(pinLed, OUTPUT);
for (byte i = ii ; i > 0 ; i--){
digitalWrite(pinLed, HIGH);
delay(50);
digitalWrite(pinLed, LOW);
delay(50);
}
pinMode(pinLed, INPUT); // reduce power
}
void blinkRed(int ii) {
pinMode(pinLedRed, OUTPUT);
for (byte i = ii ; i > 0 ; i--){
digitalWrite(pinLedRed, HIGH);
delay(50);
digitalWrite(pinLedRed, LOW);
delay(50);
}
pinMode(pinLedRed, INPUT); // reduce power
}
/******************************************************************/
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {
byte bb;
int ww;
if (ii > 9 ) ii=9;
bb=ii & 7;
if (ii > 7) bb|= (1<<5);
bb|= (1<<WDCE);
ww=bb;
MCUSR &= ~(1<<WDRF);
// start timed sequence
WDTCR |= (1<<WDCE) | (1<<WDE);
// set new watchdog timeout value
WDTCR = bb;
WDTCR |= _BV(WDIE);
}
void system_sleep() {
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
sleep_mode(); // System sleeps here, waiting for interrupt
sleep_disable(); // System continues execution here when watchdog timed out
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
}
// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect) {
f_wdt=1; // set global flag
}
void setup()
{
setup_watchdog(9);
pinMode(wakeUpPin, INPUT); // Set the pin to input
digitalWrite(wakeUpPin, HIGH); // Activate internal pullup resistor
PCMSK |= bit (PCINT0); // Pin Change Mask Register
GIFR |= bit (PCIF); // clear any outstanding interrupts General Interrupt Flag Register
GIMSK |= bit (PCIE); // enable pin change interrupts General Interrupt Mask Register
sei(); // enable interrupts
}
ISR (PCINT0_vect){}
void loop()
{
system_sleep();
if ( f_wdt > 0) { // watchdog signal
blink(5);
f_wdt=0; //reset flag
} else {
blinkRed(5); // PCINT0 occured
}
}