Quiero construir un pequeño indicador LED para la puerta de mi baño. La idea básica es que cuando una persona se sienta o se para al lado del inodoro, un pequeño transmisor lo señala de forma inalámbrica al diodo LED que está montado en el lado frontal de la puerta. El LED se enciende para que la siguiente persona que quiera entrar sepa que el lugar ocupado está ocupado. Cuando el huésped sale del baño, el transmisor vuelve a señalar que el LED debe apagarse. Se me ocurrió un plan para conectar el LED a una pequeña batería. El circuito tiene que funcionar como un interruptor de encendido/apagado. Junto al averiado habrá un circuito con una fotorresistencia (?) que puede ayudar a detectar a alguien junto al inodoro. El cambio en su corriente/voltaje activa el pequeño transmisor que envía un pulso simple (u otra señal simple), que el circuito LED podrá recibir, y luego cambia su estado.
Pero tengo algunas preguntas. ¿Usar la fotorresistencia es un buen plan? ¿Quizás hay una mejor solución de la que no tengo idea? ¿Qué tipo de señal debe producir el transmisor? ¿Qué sería mejor usar como circuito de interruptor en el lado del LED?
Me encantaría leer algunas sugerencias que puedan ayudarme con este proyecto.
Construí algo a lo largo de estas líneas. Es un sensor de puerta inalámbrico con un sensor magnético en un lado y un LED en el receptor. Convenientemente, tanto el sensor de la puerta como el receptor son idénticos en esquema, placa y firmware, excepto por un solo puente que indica qué papel desempeñará el receptor/sensor.
Este diseño utiliza un sensor de láminas, que es un sensor magnético que detecta la presencia de un imán en un par de pulgadas. Adjunto un imán a la parte inferior de la puerta y adjunto la placa del sensor a la parte inferior del marco de la puerta. Esto funciona en los retretes o en la propia puerta del baño.
Para ahorrar energía, el receptor se enciende durante 1/10 de segundo cada segundo. Eso significa que el receptor tendrá un retraso de 1 segundo, pero consume 1/10 de la energía. Puede ajustar fácilmente estos números en función de la poca potencia que desea que use el receptor y la cantidad de retraso que está dispuesto a tolerar.
El control remoto usa interrupciones de cambio de pin de hardware, por lo que solo usa energía cuando transmite. Eso significa que puede funcionar con una sola batería de celda de moneda durante meses.
Aquí está el esquema:
Este esquema permite una batería de celda de moneda CR2032 o un conector de batería JST de 2 pines (usado para paquetes de baterías AA y LiPo). Utiliza el IC inalámbrico nRF24L01, que está fácilmente disponible.
El código fuente y los archivos EAGLE están disponibles en https://github.com/samuelclay/doormonitor Aquí está el código fuente del firmware. Las bibliotecas y las dependencias están vinculadas arriba, pero esta es la rutina principal.
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <pinchange.h>
void sleepNow(void);
void wakeup();
void setupWatchdog(uint8_t prescalar);
#if defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny85__)
RF24 radio(3,7);
const int role_pin = 10;
const int sensor_pin = 2;
const int led_pin = 1;
// const int sensor_pin = 8;
// const int led_pin = 9;
#else
RF24 radio(9, 10);
const int role_pin = 6;
const int sensor_pin = 2;
const int led_pin = 4;
#endif
const uint64_t pipe = 0xA8E8F0F0F1LL;
typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms,
wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e;
typedef enum {
role_remote = 1,
role_led = 2
} role_e;
role_e role;
const char* role_friendly_name[] = { "invalid", "Remote", "LED Board"};
uint8_t led_state = 0;
uint8_t sensor_state = 0;
volatile int awakems = 0;
int send_tries = 0;
bool send_ok = false;
void setup(void) {
// set up the role pin
pinMode(role_pin, INPUT);
digitalWrite(role_pin, HIGH);
delay(20); // Just to get a solid reading on the role pin
// read the address pin, establish our role
role = digitalRead(role_pin) ? role_remote : role_led;
digitalWrite(role_pin, LOW);
Serial.begin(9600);
radio.begin();
radio.setChannel(38);
radio.setDataRate(RF24_250KBPS);
radio.setAutoAck(pipe, true);
radio.setRetries(15, 15);
if (role == role_remote) {
radio.openWritingPipe(pipe);
radio.stopListening();
} else {
radio.openReadingPipe(1,pipe);
radio.startListening();
}
// radio.printDetails();
if (role == role_remote) {
pinMode(sensor_pin,INPUT);
digitalWrite(sensor_pin,HIGH);
}
if (role == role_led) {
setupWatchdog(wdt_2s);
}
pinMode(led_pin,OUTPUT);
led_state = LOW;
digitalWrite(led_pin, led_state);
int i = role == role_led ? 4 : 2;
int pause = role == role_led ? 100 : 300;
while (i--) {
delay(pause);
digitalWrite(led_pin, HIGH);
delay(pause);
digitalWrite(led_pin, LOW);
}
}
void loop(void) {
bool different = false;
if (role == role_remote) {
// Get the current state of buttons, and
// Test if the current state is different from the last state we sent
uint8_t state = !digitalRead(sensor_pin);
Serial.write("Sensor state: ");
Serial.write(state ? "ON" : "off");
Serial.write('\n');
if (state != sensor_state) {
different = true;
send_tries = 1000;
sensor_state = state;
led_state = sensor_state;
}
// Send the state of the buttons to the LED board
if (send_tries && (different || !send_ok)) {
Serial.write("Now sending...");
digitalWrite(led_pin, led_state);
radio.powerUp();
delay(10);
send_ok = radio.write( &sensor_state, sizeof(uint8_t) );
if (send_ok) {
Serial.write("ok\n\r");
} else {
char tries_left_char[1];
send_tries--;
itoa(send_tries, tries_left_char, 10);
Serial.write("failed (");
Serial.write((char *)tries_left_char);
Serial.write(" tries left)\n\r");
digitalWrite(led_pin, LOW);
delay(25);
digitalWrite(led_pin, led_state);
}
radio.powerDown();
awakems = 0;
}
awakems += 1;
if (awakems > 10) {
sleepNow();
awakems = 0;
}
}
if (role == role_led) {
// digitalWrite(led_pin, HIGH);
if (radio.available()) {
// Dump the payloads until we've gotten everything
bool done = false;
awakems = 0;
while (!done) {
done = radio.read( &sensor_state, sizeof(uint8_t) );
}
Serial.write("Got buttons: ");
Serial.write(sensor_state ? "ON\n\r" : "off\n\r");
led_state = sensor_state;
digitalWrite(led_pin, led_state);
awakems = -10000;
}
uint8_t incomingByte;
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got with both the ASCII and decimal representations
Serial.print("I received: ");
Serial.write(incomingByte);
Serial.print(" : ");
Serial.println(incomingByte, DEC);
awakems = 0;
}
awakems += 1;
if (awakems > 4000) {
// digitalWrite(led_pin, LOW);
sleepNow();
awakems = 0;
}
}
}
#define BODS 7 //BOD Sleep bit in MCUCR
#define BODSE 2 //BOD Sleep enable bit in MCUCR
uint8_t mcucr1, mcucr2;
void setupWatchdog(uint8_t prescalar) {
prescalar = min(9,prescalar);
uint8_t wdtcsr = prescalar & 7;
if ( prescalar & 8 )
wdtcsr |= _BV(WDP3);
MCUSR &= ~_BV(WDRF);
WDTCSR = _BV(WDCE) | _BV(WDE);
WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE);
}
void sleepNow(void) {
Serial.write("Sleeping...\n\r");
if (role == role_led) {
radio.stopListening();
}
radio.powerDown();
if (role == role_remote) {
attachPcInterrupt(sensor_pin, wakeup, CHANGE);
}
ACSR |= _BV(ACD); //disable the analog comparator
ADCSRA &= ~_BV(ADEN); //disable ADC
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
//turn off the brown-out detector.
//must have an ATtiny45 or ATtiny85 rev C or later for software to be able to disable the BOD.
//current while sleeping will be <0.5uA if BOD is disabled, <25uA if not.
cli();
mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE); //turn off the brown-out detector
mcucr2 = mcucr1 & ~_BV(BODSE);
MCUCR = mcucr1;
MCUCR = mcucr2;
sei(); //ensure interrupts enabled so we can wake up again
sleep_cpu(); //go to sleep
cli(); //wake up here, disable interrupts
if (role == role_remote) {
detachPcInterrupt(sensor_pin);
}
sleep_disable();
sei(); //enable interrupts again (but INT0 is disabled from above)
Serial.print("Wakeup...\n\r");
if (role == role_led) {
radio.startListening();
}
delay(5);
}
void wakeup() {
awakems = 0;
}
ISR(WDT_vect) {
awakems = 0;
}
Andy alias
bart
Andy alias
Indrek
walyku