HC-SR501 Motion Detecting light Sensor


#1

Hey,

I’ve written a quick blog post describing how i used the HC-SR501 to control a light connected to a power tail switch, and just wanted to share.

http://dannypeters.me/spark/2015/01/24/spark-core-motion-light.html

Here’s the code, but there are more details on my post

   // functions
void light_on(void);
void light_off(void);
// variables
int ledPin = D6;
volatile int state = LOW;
unsigned long current_time;
volatile unsigned long set_time;

// 15 mins
#define FIFTEEN_MIN_MILLIS (15 * 60 * 1000)

void setup()
{
  pinMode(D0, INPUT_PULLDOWN );
  pinMode(ledPin, OUTPUT);
  attachInterrupt(D0, light_on, RISING);
  set_time = millis(); 
}

void loop()
{
  digitalWrite(ledPin, state);
  current_time = millis();
  if( set_time+FIFTEEN_MIN_MILLIS < current_time ){
    light_off();   
  }
  delay(2000);
}

void light_on(){
 set_time = millis();
 state = HIGH;
}

void light_off(){
 set_time = set_time-FIFTEEN_MIN_MILLIS;
 state = LOW;
}

let me know if you have comments or suggestions for improvements!


#2

A good habit to start now would be to keep your Interrupt Service Routines (ISR’s) as lean and mean as possible. I’m not sure about Spark Core, but on some AVR’s the same timers that handle interrupts also handle millis( ) (arduino is a good example).

Also, generally you want to use unsigned subtraction on your millis() timers, and stay away from addition. This will keep you from having overflow issues when the UL rolls over to zero. More on the math here… It may not matter for your code, but for fifteen minute timers, I’d stick with the math that works all the time.

So, you may want to consider like this (untested) code… but as they say, if it works, don’t break it!!!

// functions
void light_on(void);
void light_off(void);
// variables
int ledPin = D6;
volatile bool flagState = false;
unsigned long set_time;

// 15 mins
#define FIFTEEN_MIN_MILLIS (15 * 60 * 1000)

void setup()
{
  pinMode(D0, INPUT_PULLDOWN );
  pinMode(ledPin, OUTPUT);
  attachInterrupt(D0, light_on, RISING);
  set_time = millis();
}

void loop()
{
  if (flagState == true)
  {
    digitalWrite(ledPin, HIGH);
    set_time = millis();
    flagState = false;
  }
  if( millis() - set_time > FIFTEEN_MIN_MILLIS)
  {
    digitalWrite(ledPin, LOW);
  }
  delay(2000);
}

void light_on()
{
  flagState = true;
}

#3

@BulldogLowell, nice cleanup on the code! The only comment I can make is that given the new “state-full” handling of the digitalWrite() to ledPin means not writing every time loop() runs). However, once the delay condition is met, it will write on every loop(). It may be worth having a ledState as well so the digitalWrite() is only done once on every change. :smile:


#4

good point, but not to bang away at the pin, like this:

digitalWrite(ledPin, state);

you could do it without adding another variable:

if( millis() - set_time > FIFTEEN_MIN_MILLIS && digitalRead(ledPin) == HIGH)

digitalRead() is fast

I forgot to ask @danmanstx too, what he felt the need for the delay was…


#5

first off thanks for the code review guys, I really like the idea of moving the millis() out of the ISR

@BulldogLowell, no real reason for the delay. It kinda got left in when I was trying something a little different, and never removed. Is there any extra power consumption with letting the loop run continuously?


#6

versus using the delay, no…

But you could easily put your Spark to sleep and wake on interrupt.

But maybe first you ought to think about putting in a Spark.function and creating even more awesome…

Have you tried to send yourself a message when the motion is sensed?

What about sending a command to your mac or PC and get it to say “Intruder Alert”

have fun!


#7

@BulldogLowell love the suggestions! I actually have another spark sending me notifications over the new IFTTT notifications.

I’m guessing it would be pretty trivially to have the interrupt switch the spark on. Which that would then start the loop back up? And then have it turn off after the 15mins to save power.

Also I have plans to enhance it to have an override to control it from my phone for when I would want to be able to move around, but also have the lights out (i.e. watching a movie).


#8

check out the Spark.sleep() function and think about waking on rising interrupt and sleeping with your milllis() timer.

that’s the fun stuff… monitor the power to the TV and:

if (isNight == true && tvIsOn == true)
{
  doSomethingDifferent()
}
else
{
  doYourNormalThing();
}