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 projects.
It’s based on the use of watch dog timers and interrupts which is a very easy way to code sensors (temperature, humidity, shock, etc) and very efficient for not wasting to much power for the circuit. A Attiny85 should draw only a few micro amps(µA) while sleeping.
//
// +-\/-+
// 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
#include
#include
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// 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="" }="" void="" system_sleep()="" {="" cbi(adcsra,aden);="" switch="" analog="" to="" digitalconverter="" off="" set_sleep_mode(sleep_mode_pwr_down);="" sleep="" mode="" is="" here="" sleep_enable();="" sleep_mode();="" system="" sleeps="" here,="" waiting="" for="" interrupt="" sleep_disable();="" continues="" execution="" when="" out="" sbi(adcsra,aden);="" on="" service="" executed="" isr(wdt_vect)="" f_wdt="1;" global="" flag="" setup()="" setup_watchdog(9);="" pinmode(wakeuppin,="" input);="" the="" pin="" input="" digitalwrite(wakeuppin,="" high);="" activate="" internal="" pullup="" resistor="" pcmsk="" (pcint0);="" change="" mask="" register="" gifr="" (pcif);="" clear="" any="" outstanding="" interrupts="" general="" gimsk="" (pcie);="" enable="" sei();="" isr="" (pcint0_vect){}="" loop()="" system_sleep();="" if="" (=""> 0) { // watchdog signal
blink(5);
f_wdt=0; //reset flag
} else {
blinkRed(5); // PCINT0 occured
}
}
</wdce);>
Low battery detection code
Nick Gammon http://www.gammon.com.au/power
uint16_t readVcc(void) {
uint16_t result;
// Read 1.1V reference against Vcc
ADMUX = (0<<REFS0) | (12<<MUX0);
delay(2); // Wait for Vref to settle
ADCSRA |= (1<<ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCW;
return 1018500L / result; // Back-calculate AVcc in mV
}