Avec la mise en veille (SLEEP_MODE_PWR_DOWN) et l’utilisation des interruptions , le circuit au repos ne consomme que 4µA avec un Attiny85 (1€89 sur ebay) . J’alimente le circuit avec une pile bouton CR2032 3V achétée chez Ikea par lot de 8 pour quelques €uros. Le circuit devrait tourner beaucoup plus d’une année.

Détecteur de choc
A chaque détection de choc, le transmetteur 433Mhz émet un signal RF qui est reconnu par une Zibase en périphérique E10. Ce signaf RF est défini dans le code de l’attiny85 à la ligne n°46 (mySwitch.switchOn(‘e’, 3,2); // Test Zibase signal id E10) Dans mon circuit, je n’alimente pas le détecteur en 5V, mais je l’utilise comme simple contacteur qui déclenche une interruption lorsqu’il y a détection de choc ( voir code: digitalWrite(WAKEUP_PIN, HIGH); // Activate internal pullup resistor ).
Le détecteur, grâce à la zibase, est intégré au système d’alarme . Présentement, il m’est inutile de monter une antenne de 17,3cm. En effet le signal est suffisament puissant pour être reçu 5/5 à environ 7m du récepteur RF ( la zibase, ou mon stick RTL-SDR connecté à un RaspberryPi).
Détection niveau batterie faible
Un niveau de batterie faible est indiqué par la led qui flashe toutes les 8 s. Pour la détection de niveau de batterie faible, je me suis inspiré du post de 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 } |
Consommation du circuit avec un Arduino et Attiny85
- Attiny85: 4µA
- Avec un arduino Nano : 43mA !!!
- Arduino M.J duino uno: 6,5mA
- Arduino XDRduino: 25mA
- Arduino Mini Pro: 3,5 mA . En ôtant la LED (on) et le régulateur de tension 5V, on pourrait tomber à moins d’1mA
Le script pour Attiny85
Pour programmer l’Attiny85 à l’aide d’un arduino, je me suis inspiré du post d’Erwan http://labalec.fr/erwan/?p=1508. Éventuellement, ne pas oublier de graver la séquence d’initialisation (bootloader) de l’Attiny85.
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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | // http://blog.onlinux.fr/ // // // +-\/-+ // Ain0 (D 5) PB5 1| |8 Vcc // Ain3 (D 3) PB3 2| |7 PB2 (D 2) Ain1 - // LED +pin Ain2 (D 4) PB4 3| |6 PB1 (D 1) pwm1 - Shock sensor pin // GND 4| |5 PB0 (D 0) pwm0 - RF433 tx pin // // **** INCLUDES ***** #include <avr/sleep.h> #include <avr/wdt.h> #include <RCSwitch.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 #define LOW_BATTERY_LEVEL 2500 //mV. Led will flash if battery level is lower than this value #define WDT_COUNT 225 // wdt is set to 8s, 8x225=1800 seconds = 30 minutes volatile boolean f_wdt = 0; volatile byte count = WDT_COUNT; volatile boolean f_int = 0; volatile boolean lowBattery = 0; volatile boolean switchState = HIGH; const byte TX_PIN = PB0; // Pin number for the 433mhz OOK transmitter const byte LED_PIN = PB4; const byte WAKEUP_PIN = PB1; // Use pin 1 as wake up pin RCSwitch mySwitch = RCSwitch(); /******************************************************************/ void setup() { setup_watchdog(9); pinMode(TX_PIN, OUTPUT); pinMode(WAKEUP_PIN, INPUT); // Set the pin to input digitalWrite(WAKEUP_PIN, HIGH); // Activate internal pullup resistor mySwitch.enableTransmit(TX_PIN); mySwitch.switchOn('e', 3,2); // Test Zibase signal id E10 lowBattery = !(readVcc() >= LOW_BATTERY_LEVEL); // Initialize battery level value PCMSK |= bit (PCINT1); // set pin change interrupt PB1 GIFR |= bit (PCIF); // clear any outstanding interrupts GIMSK |= bit (PCIE); // enable pin change interrupts sei(); } // set system into the sleep state // system wakes up when watchdog is timed out 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 sleep_disable(); // System continues execution here when watchdog timed out sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON } // 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); } // Watchdog Interrupt Service / is executed when watchdog timed out ISR(WDT_vect) { if (count >= WDT_COUNT) { f_wdt=true; // set WDTl flag count=0; } count++; } ISR (PCINT0_vect){ f_int=true; // set INT flag } void loop() { system_sleep(); if (lowBattery) // lowBattery is at setup(). lowBatteryWarning(); // Flash for 1ms every 8s http://www.gammon.com.au/power if (f_int) { blink(2); cli(); mySwitch.switchOn('e', 3,2); // Zibase signal id E10 f_int=false; // Reset INT Flag sei(); } else if ( f_wdt ) { blink(5); cli(); // disable interrupts lowBattery = !(readVcc() >= LOW_BATTERY_LEVEL); f_wdt=false; // reset WDT Flag sei(); // enable interrupts } } void blink(int ii) { pinMode(LED_PIN, OUTPUT); for (byte i = ii ; i > 0 ; i--){ digitalWrite(LED_PIN, HIGH); delay(50); digitalWrite(LED_PIN, LOW); delay(50); } pinMode(LED_PIN, INPUT); // reduce power } void lowBatteryWarning () { pinMode(LED_PIN, OUTPUT); digitalWrite (LED_PIN, HIGH); delay (1); // mS digitalWrite (LED_PIN, LOW); //delay (999); pinMode(LED_PIN, INPUT); // reduce 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 } |
Et la suite…
Le circuit pourrait ếtre encore plus miniaturé en se passant du breadboard.
Maintenant il ne reste qu’à trouver un joli boîtier pour cacher toute l’électronique.
Malheureusement je n’ai pas d’imprimante 3D!
Si vous avez des idées pour une solution esthétique, n’hésitez pas!