Interrupts and wdt code – Attiny85

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.

attiny85Actually, this page is a kind of reminder and a startup for all my new dev.
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//
// 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
  }
 
}