Balido de Oveja
Balido de oveja con Attiny85
Esta semana llega el día: mi cuñado tomará de su propia medicina.
Mi cuñado es de los que cuando se levantan todo el mundo tiene que estar levantado. Yo suelo madrugar, pero hay fines de semana que te apetece levantarte a las 9h
Bueno, uno de esos días en que quería levantarme tarde sufrí a mi cuñado… y le dije que un día lo pagaría. Ese día está cerca, muy cerca: este domingo
Para ello nada mejor que una pequeña broma electrónica: utilizando un attiny85 disparar uno de esos circuitos con soniditos a horas intempestivas (llámese sobre las 2h).
En principio el proyecto incluía poner mi voz en el chip, pero ciertamente llevo unos años sin tiempo ninguno y he tenido que recurrir a un circuito con los sonidos… Bueno, esta parte se queda en el TODO
Lo interensante del proyecto es que pongo el chip en modo sleep, y si a eso añadimos que deshabilitamos alguna que otra cosa innecesaria pasamos a consumir uA. Lo que nos da un tiempo más que suficiente para que dure la broma con una pila de botón.
Aquí utilizo el watchdog para ir despertando al Attiny85 a intervalos regulares (cosa que no había hecho hasta ahora en modo sleep).
Tengo dos prototipos que voy a utilizar:
- uno con pilas AA (la broma puede durar años…)
- otro con una pila de botón CR2032
¿Por qué utilizar el modo sleep? Principalmente por la pila de botón. Una CR2032 tiene una capacidad típica de unos 200mAh y si nuestro Attiny85 consume unos 2mA (a una frecuencia de 1Mhz, que la que estamos utlizando nosotros) solo por él mismo se comería la bateria en unas 100h (que vienen a ser unos 4 días)… nada, una miseria (no he considerado el carrillón porque solo consume durante unos 5sg, y estimo el consumo en 15mA -no lo medí, mea culpa). Por tanto está claro que tenemos que dormir mientras no hacemos nada.
El Attiny85 puede llegar a valores muy bajos de consumo en este modo (cerca de 1uA) pero yo no lo he desconectado absolutamente todo cuando duerme, por tanto podría estar hablando de unos 20uA. Esto ya es otra cosa: ¡¡estamos hablando de unas 10.000h de funcionamiento con una pila de botón. Más de un año funcionando!! En realidad el cálculo no es así puesto que nos despertamos cada 8sg para hacer unas pequeñás operaciones. Otra vez… no sé los datos exactos pero en el peor de los casos (y exagerando muchísimo) estaríamos hablando de consumir 10mA durante 1ms. Por tanto de media estamos consumiendo unos 30uA (voy a suponer 50uA…) por tanto tenemos una vida útil de la broma de unas 4.000h que son más de 5meses ¿No está mal verdad?
Pues eso no es nada. Para las AA, que son alkalinas tenemos nada más y nada menos que 2x2000mAh ¡¡¡es decir 20 veces más!!!
Aquí la imágenen de los dos prototipos:
Aunque hay cosas a mejorar te puede valer como punto de partida para experimentar con el modo sleep y el watchdog.
La verdad creo que no merece la pena poner el esquema porque la conexión depende del circuito carillón que utilices… pero bueno, ahí lo pongo:
Vista:
Para aumentar el volumen, cierro el buzzer con un trozo de celo:
P.D. Aunque está escrito con el Atmel Studio lo puedes traducir a Arduino de forma casi inmediata.
/*
* oveja.c
*
* Created: 29/08/2016 7:41:44
* Author: bull
*
* Disparar de madrugada con un intervalo aleatorio el balido de una oveja para despertar a mi cuñado
*/
#define F_CPU 1000000UL
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <stdlib.h> // random
#include <util/delay.h>
#include <avr/sleep.h>
#define TRIGGER_PIN PB4
#define TRIGGER_DDR DDRB
#define TRIGGER_PORT PORTB
// 1 semana son 604.800sg, que si nos despertamos cada 8sg son 75.600 -> necesitamos un uint32_t
// Desde las 00.00h hasta las 02:00h hay 7.200sg, que si nos despertamos cada 8sg son 900 veces. Y si queremos que
// el tiempo aleatorio esté en 3h = 10800sg = 1350 despertar jjj
const uint32_t semana = 75600;
const uint32_t las2 = 900;
const uint32_t x3h = 1350;
// TODO En realidad creo que no hace falta incrementar 'reloj' en la ISR, con lo que ya no necesitaría ser volatile.
// Comprobar que funciona en el main.
volatile uint32_t reloj = 0;
ISR(WDT_vect)
{
wdt_reset();
//MCUSR = 0x00; NOTE Ahora ya no parece hacer falta...
// No queremos el reset... pág 44 Bit 6 - WDIE
WDTCR |= _BV(WDIE);
reloj = (reloj + 1) % semana;
}
void bleating()
{
TRIGGER_PORT |= _BV(TRIGGER_PIN);
_delay_ms(50);
TRIGGER_PORT &= ~_BV(TRIGGER_PIN);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int main(void)
{
// Puerto de salida
TRIGGER_DDR |= _BV(TRIGGER_PIN);
uint16_t alarma = 0xFFFF;
srandom(1234);
bleating();
// Desactivar cualquier cosa no necesaria
//
cli();
// Desactivar el ADC
ADCSRA = 0x00;
// Desactivar el AC (Analog Comparator)
//ACSR &= ~_BV(ACIE);
ACSR |= _BV(ACD);
// Watchdog. Safety level 1. Levantar cada ~8sg
wdt_reset();
MCUSR = 0x00;
WDTCR |= (1 << WDCE) | (1 << WDE);
WDTCR = _BV(WDIE) | _BV(WDE) | _BV(WDP3) | _BV(WDP0);
sei();
// Preparar para dormir
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
while(1)
{
sleep_mode();
if(reloj == las2)
alarma = las2 + (random() % x3h);
if(reloj == alarma)
{
bleating();
alarma = 0xFFFF;
}
}
}