Intro:
Did you ever wish you had light that comes on as you walk up the stairs? With small kids running up and down stairs in the dark can be dangerous. I created lights that will come on as you go up or down the stairs. It use PIR sensors to see you. So lets see what you will need.This is not a tutorial in how Arduino works or electronics. You must know at least how Arduino works to do this project. Most code is from Arduino IDE examples. I just put it all together to make it work.
Buy list:
- 1 x Arduino Uno
- 2 x DSN-FIR800 PIR sensors or compatible ones
- 14 x WS2801 30mm LEDS
- 1 x 12 Volt 2 Amp Switch Mode power supply
- 6 x 22k Ohm Resistors
- 1 x 15k Ohm Pot
- Dip 5 Switch or Dip 2 & 3 Switch
Arduino Uno:
The Arduino Uno comes with 15 digital pins and 6 analog pins. The analog pins will be used as digital pin 15, 16, 17, 18 and 19. Analog A0 will stay as it is but its digital pin is 14.
DSN-FIR800 PIR:
This PIR sensor comes with 3 pins. 2 Setting pots for Time(Tx) on and Sensitivity(Sx). The signal out can be changed to LOW but we need it HIGH so we leave it as is. First sensor pin 2 will be connected to Arduino pin 5 and the other sensor pin 2 to the Aruino pin 3. PIR pin 1 goes to 5 volt on Arduino and Ground to Ground on Arduino.
- Pin 1 is 5 Volt
- Pin 2 is Signal out is HIGH
- Pin 3 is Ground
WS2801 30mm LEDS:
This is where the magic starts. This LED's have 3 RGB LED's inside. They are fitted with a WS2801 chip that control the color and address which one should be on. There are 4 wires Connected to them.
- First wire is 12 volt only!
- Then the clock wire that goes to Arduino Pin12.
- Then the data wire that goes to Arduino Pin13.
- Then Ground. Important Ground must be connected to Arduino Ground also.
- Very important! Look at the arrow on the LED to see direction of the DATA flow.
Fritzing:
Fritzing is a circuit building program that helps a lot with explaining and layout of components.This image is to show you where to put the LED wire and the 2 PIR sensor wires.
- D2 is a push button to change to next demo.
- A1 will switch on Demo mode.
- A2 is to set the speed of the next lights to turn on.
- A3 to set Blue value.
- A4 to set Green value.
- A5 to set Red value.
MY CODE:
#include "WS2801.h" //for use with WS2801 Chip#include "SPI.h"
#include <EEPROM.h> //to write and read from EEPROM
// BE SURE TO CHECK YOUR PIXELS TO SEE WHICH WIRES TO USE!
uint8_t dataPin = 13;
uint8_t clockPin = 12;
// Connect the ground wire Pixels to Arduino ground
// Set the first variable to the NUMBER of pixels. 5 = 5 pixels in a row
WS2801 strip = WS2801(15, dataPin, clockPin);
// EEPROM addresses to save to
const int addr = 0;
const int addrR = 1;
const int addrG = 2;
const int addrB = 3;
const int addrSpeed = 4;
// Where we going to store to byte
byte value;
// Temp holds your color value
int color;
// Motion sensor inputs
const int bottomPIR = 3;
const int topPIR = 5;
// Analog pin used as digital pins 14 to 19
const int redSwitch = 15; //Red Switch
const int greenSwitch = 16; //Green Switch
const int blueSwitch = 17; //Blue Switch
const int speedSwitch = 18; //Speed switch
const int demoSwitch = 19; //Demo Switch
// Which demo to run :) EEPROM save this value
unsigned int switchSelect;
// The time lights stays on before all goes dark
unsigned int lighton = 5000;
// Time lights comes on one by one
unsigned int lightspeed = 100;
// LED Colors
unsigned int RGB1 = 90;
unsigned int RGB2 = 125;
unsigned int RGB3 = 125;
//************************************************************
void setup() {
Serial.begin(19200);
while (!Serial) {
delay(10);
; // wait for serial port to connect. Needed for Leonardo only
}
pinMode(topPIR, INPUT);
pinMode(bottomPIR, INPUT);
pinMode(redSwitch, INPUT);
pinMode(greenSwitch, INPUT);
pinMode(blueSwitch, INPUT);
pinMode(speedSwitch, INPUT);
pinMode(demoSwitch, INPUT);
delay(400);//Wait for serial LCD to start up
Serial.print("Reading EEPROM ");
Serial.print('\n');
delay(300);
strip.begin();// Start WS2801
strip.show();// Start al off
// Read addresses in the EEPROM then save it
value = EEPROM.read(addr);
switchSelect = int(value);
RGB1 = EEPROM.read(addrR);
RGB2 = EEPROM.read(addrG);
RGB3 = EEPROM.read(addrB);
// Read this addresses in the EEPROM then save it
//Miltiply by 10 to allow more time for lights
lightspeed = EEPROM.read(addrSpeed);
lightspeed = lightspeed * 10;
// Set interrupt button. Help select the demo
attachInterrupt(0, debounceInterrupt, HIGH);
Serial.print("Starting.... ");
Serial.print('\n');
delay(1000);
}
//************************************************************
// We use long variables because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;// Last time the output pin was pressed
long debounceDelay = 350;// Time to wait before button will be active
boolean change = true;// Needed to save to EEPROM
void debounceInterrupt() {
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
switchSelect++;
lastDebounceTime = millis();
change = true;
}
}
//************************************************************
int Direction = 0;// What direction we moving
void loop() {
//*** Settings ***
if (!digitalRead(redSwitch)) {//A1 to A5 used as digital pins for switches to set values
while (!digitalRead(redSwitch)) {// Stay active till value is set
change = true;//Update the colors
pickColor();// Function to select a color
Serial.print("Red: ");// Show me the color value on LCD
Serial.print(color);
Serial.print(" ");
Serial.print('\n');
WipeDown(Color(color, RGB2, RGB3), 1);// Show me the color
}
EEPROM.write(addrR, color);// Save value to EEPRM
} else if (!digitalRead(greenSwitch)) {
while (!digitalRead(greenSwitch)) {
change = true;
pickColor();
Serial.print("Green: ");
Serial.print(color);
Serial.print(" ");
Serial.print('\n');
WipeDown(Color(RGB1, color, RGB3), 1);
}
EEPROM.write(addrG, color);
} else if (!digitalRead(blueSwitch)) {
while (!digitalRead(blueSwitch)) {
change = true;
pickColor();
Serial.print("Blue: ");
Serial.print(color);
Serial.print(" ");
Serial.print('\n');
WipeDown(Color(RGB1, RGB2, color), 1);
}
EEPROM.write(addrB, color);
} else if (!digitalRead(speedSwitch)) {
// You can only save to EEPROM 100 000 times. Save it this way
change = true;// When you done picking speed save to EEPROM
while (!digitalRead(speedSwitch)) {
double T;// Needed to test only
lightspeed = analogRead(A0);// Read analog pin
lightspeed = map(lightspeed, 0, 1023, 0, 255);// Map it to workable value
// DONT use Constrains it comes with errors
if (lightspeed > 255) {// Constrains it between 0 and 255
lightspeed = 255;
} else if (lightspeed <= 1) {
lightspeed = 0;
}
T = lightspeed * 10;// Convert to usable value
Serial.print("Speed: ");
Serial.print(T);
Serial.print(" ");
Serial.print('\n');
for (int i = strip.numPixels() ; i >= 0; i--) {
strip.setPixelColor(i, Color(175, 70, 0));
}
strip.show();
delay(T);
AllOff();
delay(T);
}
EEPROM.write(addrSpeed, lightspeed);// Save to EEPROM
}
if (change) {// IF true
change = false;// Set False
EEPROM.write(addr, switchSelect);// Save to EEPROM
value = EEPROM.read(addr);
switchSelect = int(value);
RGB1 = EEPROM.read(addrR);
RGB2 = EEPROM.read(addrG);
RGB3 = EEPROM.read(addrB);
}
//if DEMO is selected run it
if (digitalRead(demoSwitch)) {//NO DEMO
//check if PIR detect motion
if (digitalRead(topPIR) == HIGH) {
Serial.println("PIR 1 Active ");
Serial.println('\n');
WipeUp(Color(RGB1, RGB2, RGB3), lightspeed);// Lights on
if (Direction == 0) Direction = 1;// To switch off in same direction
}
else if (digitalRead(bottomPIR) == HIGH) {
Serial.println("PIR 2 Active ");
Serial.println('\n');
WipeDown(Color(RGB1, RGB2, RGB3), lightspeed);
if (Direction == 0) Direction = 2;
}
else {
if (Direction == 1) {//switch lights off
delay(lighton);
WipeUp(Color(0, 0, 0), lightspeed);
}
if (Direction == 2) {
delay(lighton);
WipeDown(Color(0, 0, 0), lightspeed);
}
Direction = 0;//Reset it else it will on switch on again
}
}
else if (!digitalRead(demoSwitch)) {
demo(); // Call DEMO
}
}
//************************************************************
// When function is called. it will display the lights
//Add funtions so its not needed to repeat this calls over and over
//it save time
void WipeUp(uint32_t c, double wait) {
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();// Activate Lights
delay(wait);//Waiting time that is saved in EEPROM
}
}
//************************************************************
void WipeDown(uint32_t c, double wait) {
for (int i = strip.numPixels() ; i >= 0; i--) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
//************************************************************
void AllOff() {
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, 0);
}
strip.show();
}
//************************************************************
//***** DEMO MODES *****
// Ths is just repeat of top functions. its needed for demo mode only
void demo() {
// Serial.println("DEMO IS RUNNING....");
int PicR = random(255);
int PicG = random(255);
int PicB = random(255);
switch (switchSelect) {
case 1:
Serial.print("Demo 1 Running ");
Serial.println('\n');
WipeDown(Color(color, RGB2, RGB3), lightspeed);
delay(lightspeed);
AllOff();
delay(lightspeed);
break;
case 2:
Serial.print("Demo 2 Running ");
Serial.println('\n');
strip.setPixelColor(random(strip.numPixels()), Color(random(255), random(255), random(255)));
strip.show();
delay(300);
break;
case 3:
Serial.print("Demo 3 Running ");
Serial.println('\n');
int i, j;
for (j = 0; j < 256; j++) { // 3 cycles of all 256 colors in the wheel
for (i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel( (i + j) % 255));
strip.show();
}
// write all the pixels out
delay(30);
}
break;
case 4:
Serial.print("Demo 4 Running ");
Serial.println('\n');
strip.setPixelColor(random(strip.numPixels()), Color(random(255), random(255), random(255)));
strip.show();
delay(150);
AllOff();
delay(80);
break;
case 5:
Serial.print("Demo 5 Running ");
Serial.println('\n');
for (i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Color(random(255), random(255), random(255)));
strip.show();
delay(150);
}
AllOff();
delay(150);
break;
case 6:
Serial.print("Demo 6 Running ");
Serial.println('\n');
for (int i = strip.numPixels() ; i >= 0; i--) {
strip.setPixelColor(i, Color(random(255), random(255), random(255)));
strip.show();
delay(100);
}
delay(500);
break;
case 7:
Serial.print("Demo 7 Running ");
Serial.println('\n');
for (int i = 0 ; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Color(PicR, PicG, PicB));
strip.show();
delay(180);
}
break;
case 8:
Serial.print("Demo 8 Running ");
Serial.println('\n');
for (int i = strip.numPixels() ; i >= 0; i--) {
strip.setPixelColor(i, Color(PicR, 0, PicB));
}
strip.show();
delay(100);
AllOff();
delay(50);
break;
default:
Serial.print("NOTHING SELECTED ");
Serial.println('\n');
AllOff();
while(!change){
if (analogRead(A5) > 100){change = 1;}
delay(10); }
break;
}
if (switchSelect > 8) switchSelect = 0;//End of demo - start over
}
//************************************************************
//***** Needed Functions *****
// Create a 24 bit color value from R,G,B
uint32_t Color(byte r, byte g, byte b)
{
uint32_t c;
c = r;
c <<= 8;
c |= g;
c <<= 8;
c |= b;
return c;
}
void pickColor() {
color = analogRead(A0);//Read analog pin
color = map(color, 0, 1023, 0, 255);//map it
if (color > 255) {// Constrains it between 0 and 255
color = 255;
}
else if (color <= 1) {
color = 0;
}
}
//************************************************************
//Input a value 0 to 255 to get a color value.
//The colours are a transition r - g -b - back to r
uint32_t Wheel(byte WheelPos)
{
if (WheelPos < 85) {
return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
} else if (WheelPos < 170) {
WheelPos -= 85;
return Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}