I'm making an alarm for a toddler stair gate that flashes led and buzzer if gate is left open.
That bit works ok off an external interrupt. I would love it to have a ten second delay before it starts flashing and buzzing, so it doesn't go off every time you walk through.
How do I do this?
This is the code I am using:
#include <avr/power.h>
#include <avr/sleep.h>
#include <Ports.h>
int wakePin = 2; // pin used for waking up
int led=13;
int pinSpeaker = 10;
int delaytime = 0;
ISR(WDT_vect) { Sleepy::watchdogEvent(); }
void wakeUpNow() {
// execute code here after wake-up before returning to the loop() function
// timers and code using timers (serial.print and more...) will not work here.
// we don't really need to execute any special functions here, since we
// just want the thing to wake up
}
void setup() {
pinMode(wakePin, INPUT_PULLUP);
pinMode(led, OUTPUT);
pinMode(pinSpeaker, OUTPUT);
attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function wakeUpNow when pin 2 gets LOW
}
void sleepNow() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable(); // enables the sleep bit in the mcucr register
attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
sleep_mode(); // here the device is actually put to sleep!!
// THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
sleep_disable(); // first thing after waking from sleep: disable sleep...
detachInterrupt(0); // disables interrupt 0 on pin 2 so the wakeUpNow code will not be executed during normal running time.
}
void loop() {
digitalWrite(led, HIGH);
digitalWrite(pinSpeaker, HIGH);
Sleepy::loseSomeTime (150);
digitalWrite(led, LOW);
digitalWrite(pinSpeaker, LOW);
Sleepy::loseSomeTime (150);
digitalWrite(led, HIGH);
sleepNow(); // sleep function called here
}
In your case, it looks like you could just add a delay at the start of your loop.
Personally I would do something along these lines:
void loop()
{
// Check whether the gate is open
newGateState = readGateStateFromHardware();
if (newGateState != gateState)
{
gateState = newGateState;
gateStateChangeTime = the current time;
}
// Check whether we should have an alarm (gate open for more than 10 seconds)
newAlarmState = (gateState == GATE_OPEN && gateStateChangeTime is more than 10 seconds ago);
if (newAlarmState != alarmState)
{
alarmState = newAlarmState;
if (alarmState == ALARM_ON)
{
turnOn(lights);
sound(horns);
}
else
{
turnOff(lights);
silence(horns);
}
}
}
If you need to check if something is in a particular state throughout a period of time, this code should do it. It is assumed to be in loop() and called repeatedly.
btnVal = digitalRead(btnPin);
if (btnVal == HIGH) { // assumes btn is LOW when pressed
lastBtnPressMillis = millis(); // btn not pressed so reset clock
}
if (millis() - lastBtnPressMillis > = interval) {
// button has been pressed for longer than interval
}
@LarryD - that makes sense. I wrote that code for a different situation - but it illustrates the timing control.
In any case I don't think the OP really means "once" even though the title suggests that. I think he just wants an interval before the alarm is triggered to allow the gate to opened and closed. It should only alarm if it is left open for an unacceptably long period.
ok this is what I came up with. It probably doesn't look pretty, but it works the way I need. Except for one issue. If wakePin is already HIGH when I power up the board, it wont work until the gate is closes first. Any ideas?
#include "LowPower.h"
int wakePin = 2; // pin used for waking up
int led=13;
int pinSpeaker = 10;
int val=0;
int j=1;
void wakeUpNow() {
// execute code here after wake-up before returning to the loop() function
// timers and code using timers (serial.print and more...) will not work here.
// we don't really need to execute any special functions here, since we
// just want the thing to wake up
}
void setup() {
pinMode(wakePin, INPUT_PULLUP);
pinMode(led, OUTPUT);
pinMode(pinSpeaker, OUTPUT);
digitalWrite(led, HIGH);
digitalWrite(pinSpeaker, HIGH);
LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_ON);
digitalWrite(pinSpeaker, LOW);
attachInterrupt(0, wakeUpNow, HIGH); // use interrupt 0 (pin 2) and run function wakeUpNow when pin 2 gets LOW
}
void sleepNow() {
attachInterrupt(0,wakeUpNow, HIGH); // use interrupt 0 (pin 2) and run function
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
detachInterrupt(0); // disables interrupt 0 on pin 2 so the wakeUpNow code will not be executed during normal running time.
}
void loop() {
sleepNow(); // sleep function called here
while(j<=33){
val = digitalRead(wakePin);
if(val == LOW){
software_Reset();
}
digitalWrite(led, HIGH);
LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_ON);
digitalWrite(led, LOW);
LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_ON);
j++;
}
while(1){
val = digitalRead(wakePin);
if(val == LOW){
software_Reset();
}
digitalWrite(led, HIGH);
digitalWrite(pinSpeaker, HIGH);
LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_ON);
digitalWrite(led, LOW);
digitalWrite(pinSpeaker, LOW);
LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_ON);
digitalWrite(led, HIGH);
}
}
void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers
{
asm volatile (" jmp 0");
}