Laser beam break detector with auto set up and four Modes.

This  post has been completely updated

This simple project just grew, as they often do. This laser beam break detector now has four modes, the normal mode – where the beam is broken and the alarm sounds (pin 13 goes HIGH as well), then after three seconds the system resets ready for the beam to be broken again. The second mode is a single shot mode, once the beam is broken the alarm sounds and pin 13 goes HIGH. The alarm sound stops and the laser is turned off, but pin 13 remains HIGH and the beam cannot be broken again until the Arduino Reset button is pressed. The third mode is a counting mode, every time the beam is broken the total is incremented. The counting is designed for fairly slow counting, for example people breaking the beam, or a ball dropping through the beam. It is not intended for small objects travelling at speed. The last mode turns the laser on to allow the beam to be aligned with the LDR. There is also a button to shut the laser down, this is connected to Interrupt 0 and as a side effect if this is pressed when the normal, or count modes are operational the total counts and time period are shown. Pressing this button shuts the sketch down and a Reset is needed to get it going again.

Showing the returned beam after a nine metre path.
Showing the returned beam after a nine metre path.
The laser is a Keyes KY-008 module available cheaply on e-bay. I have used PWM to reduce the light output from the laser to a minimum.

laser beam break2
Showing the laser and LDR about 1 cm apart.

The beam is designed to be reflected from a mirror on the other side of a door or path. When the sketch is first run the laser is shut down while the light level is calculated. This provides a ‘trip’ level. Next the laser is switched on at low power and the power gradually increased until the output from the LDR is above the trip level. With a total path of nine metres across a room the power was set to only 30% and this still gave reliable results. If the laser cannot output enough power the circuit shuts down. Full details of each step is shown on the Serial Monitor (9600).

Rather than having to alter the code to change the modes one of four pins is connected to ground. Pin 3 selects the Normal Mode, pin 4 selects the One Shot Mode and pin 5 selects the Count Mode and pin 6 selects the Laser Align Mode.

The layout is shown in the diagram below. The laser is attached to pin 9 and GND. An LDR is attached to 5 volts and a 270R resistor, the other side is attached to GND. The Junction is attached to A0. A small pizzo speaker is connected between pin 10 and GND. Finally a small push button is connected between GND and pin 2 (Interrupt 0), a 10k resistor goes from pin 2 to 5 volts to keep this input HIGH.

Wiring diagram.
Wiring diagram.
Mount the laser and LDR side by side about 1 cm apart ( I used a six pin female/female connector to fit them both in), although as long as the reflected beam strikes the LDR this is not important. For the initial test mount the LDR in front of the laser and separated by about 6 inches (make sure the laser points away from you!). Plug the black GND wire into pin 6 on the Arduino, load the sketch and switch on the Serial Monitor. This is the align mode, make sure the beam is on the LDR. Move the black wire to pin 3 on the Arduino, shut the Serial Monitor, then re open it. This resets the Arduino and the normal mode will be run. The Serial Monitor displays all steps as it determines the correct settings. It will then show the beam is ready, break the beam with your hand and the alarm will sound. Three seconds later the sketch will run the set up routine again and be ready to detect another break. Each mode has a different number of ‘bleeps’ to show its ready.

A relay to control other equipment could be connected to the alarm pin 13. Finally the push button is provided as a quick means of turning off the laser.

/*********************************************************************************************
Laser Beam Break Chris Rouse Jan 2015
WARNING Lasers can be dangerous, this sketch attempts to use the lowest
power it can, but do not stare directly at the laser beam, or reflection.

DESCRIPTION:

This is a multi purpose Laser Beam Break detector
* The trigger level and laser output level are set automatically to suit conditions
* Laser can be switched off easilly, for safety
* Functions selected by connecting Arduino pins to GND, can easilly be reprogrammed
without changing code, or requiring Serial Monitor
* Modes identified by distinct tones
* Full information about system status is displayed on the Serial Monitor (9600).
* All electronics are located in the same place, the beam is reflected back by a mirror.

There are four modes:
* Mode 1 This is the default, no Arduino pins are connected to GND
In this mode when the beam is broken a tone is sounded and Arduino Pin 13 goes HIGH
after a user adjustable time Arduino Pin 13 goes LOW and the syatem is reset
and waits for another beam break. This mode is identified by 2 beeps as the
system is 'armed'.

* Mode 2 This is a single Shot Mode. Connect Arduino pin 5 to GND.
In this mode when the beam is broken the alarm sounds, Arduino Pin 13
goes HIGH. The Laser is switched OFF and pin 13 remains HIGH until the
Arduino is reset. This mode is identifies by 3 beeps as the system
is 'armed'.

* Mode 3 This is a Counter Mode. Arduino Pin 6 is connected to GND.
In this mode the alarm is disabled and a total number of beam-breaks is shown
In order to ensure that false triggering does not occur the next count will
not take place until the object (person) has completly passed through the beam.
This mode is NOT intended to count at high speed.

* Mode 4 This is the beam alignment mode. Arduino pin 4 is connected to GND.
The beam power is set in a user adjustable variable, for short range initial testing
this value should be aroud 2 to 5. For long range this can be increased to a maximum
of 255 (0 turns the beam OFF). A warning is issued and after a 2 second delay the
beam is turned on. The mirror is adjusted so that the reflected light strikes the LDR.
Use the Interrupt Button to turn the laser off.

*********************************************************************************************/

// variables that the user can change

int restore = 3000; // delay before system is reset 1000 = 1 second
int lowPower = 2; // lowest power to start laser putput at
volatile int powerTest = 2; // power the laser is set to for alignment, max 255
boolean silence = false; // if true then no audio output

// do not alter these variables
//
int interruptPin = 2;
int normalPin = 3; // take this pin LOW to run in normal mode
int loopPin = 4; // take this pin LOW to make alarm one shot only
int countPin = 5; // take this pin LOW to convert to count breaks mode
int testPin = 6; // take this pin LOW to run the test routine
int laser = 9; // laser pin
int alarm = 13; // alarm pin
int trigger = 14; // analog input A0, LDR connects to this
int tripOffset = 50; // added to the measured ambient light level
int ldr=0; // value read from the LDR input
int delay1 = 200; // delay used in determining ambient light
int trip = 0; // used to calculate alarm trip level
int pinSpeaker = 10; // Set up a speaker on a PWM pin (digital 9, 10, or 11)
int total = 0; // number of times the beam has been broken
volatile int power = lowPower; // light output from laser, max = 255

volatile boolean alarmDisable = false; // if true the alarm will not trigger
volatile boolean emergency = false; // set to true when interupt button is pressed
boolean normal = false; // normal mode resets after 3 seconds
boolean oneShot = false; // if set to true for one shot mode
boolean countMode = false; // set to true for counter mode
boolean align = false; // used by laser alignment routine

unsigned long time; // measure how long the sketch has been running

//
void setup() {
Serial.begin(9600);
printHeader(); // display sketch information
attachInterrupt(0,laserOff, FALLING); // allows a push button to turn the laser off

// initialize the digital pins as inputs with pull up resistors attached.
pinMode(interruptPin, INPUT_PULLUP);
pinMode(normalPin, INPUT_PULLUP); // connect to GND to enter normal mode
pinMode(loopPin, INPUT_PULLUP); // connect to GND to switch to one shot mode
pinMode(countPin, INPUT_PULLUP); // connect to GND to enter count breaks mode
pinMode(testPin, INPUT_PULLUP); // connect to GND to enter align laser mode
//
// initiallise digital pins as Outputs
pinMode(laser, OUTPUT);
pinMode(alarm, OUTPUT);
pinMode(pinSpeaker, OUTPUT);
//
// check to see which pin has been selected (one only at a time)
if (digitalRead(normalPin) == LOW){ // set normal mode
normal = true;
oneShot = false;
countMode = false;
align = false;
alarmDisable = false;
}
if (digitalRead(testPin) == LOW && normal == false){ // allow the align laser/LDR routine
normal = false;
oneShot = false;
countMode = false;
align = true;
alarmDisable = true;
}
if (digitalRead(loopPin) == LOW && normal == false && align == false){
// switch on alarm one shot mode
normal = false;
countMode = false;
align = false;
oneShot = true;
alarmDisable=false;
}
if (digitalRead(countPin) == LOW && normal == false && align == false && oneShot== false){
// switch to count breaks mode
normal = false;
oneShot = false;
align = false;
countMode = true;
alarmDisable = true;
}

//
if (align == false){ // dont calibrate if in align laser mode
initiallise(); // calibrate the system
}
}

void loop() {
//
if (emergency == true){ // shut down laser if interupt button pressed
analogWrite(laser,0);
align=false;
Serial.println("\n***LASER switched OFF***"");
if(normal == true || countMode == true){
Serial.print("\nTotal Number of times the beam was broken = ");
Serial.print(total);
time = millis();
Serial.print(" in ");
Serial.print(time/1000);
Serial.println(" seconds");
}
countMode=false;
emergency = false;
soundSet();
}
//

analogWrite(laser, power); // turn on Laser with power adjusted through PWM
delay(10);
ldr=analogRead(trigger); // look for a return beam using a LDR
//
if (alarmDisable == false){ // look for the beam being broken
if (ldr <trip){
setAlarm(); // set alarm off
if (normal == true){
total ++; // keep a count of the number of beam breaks
}
// see if this a one shot alarm
if (oneShot == false){
// pause for a time then reset the system, this recalibrates the system
delay(restore);
Serial.println("\nSystem recalibration and reset....\n");
initiallise();
alarmDisable = false; // alarm reset
}
}
}

//
if(align == true){ // align laser
// this allows the alignment of the laser and LDR
// press RESET button to exit this
soundSet();
Serial.println("\n***WARNING Laser will be switched on to High Power \nto "
"allow alignment with LDR, press RESET to exit\n");
delay(2000);
// turn on Laser with power adjusted through PWM
analogWrite(laser, powerTest);
align=false;
}
//
if(countMode == true && alarmDisable == true){ // count beam breaks
if (analogRead(trigger) < trip){
soundSet();
countLoop();
while(analogRead(trigger) < trip); // wait for object to pass through
}
}
}
//
//
void ambient() {
// check the ambient light level and use this to set the value of ldr
Serial.print("Laser turned off, checking background light level ");
// first turn off the laser
analogWrite(laser, 0);
trip = 0; // reset
trip = analogRead(trigger);
// now take 10 readings from the LDR at 200ms intervals and calculate the average
for(int i=0; i<10; i++){
Serial.print(".");
delay(delay1); // wait 200ms
trip += analogRead(trigger);
}
trip = int(trip / 10) + tripOffset; // average it and add a bit
Serial.println("");
// turn laser back on in the calling routine
}

void checkLaser(){
// check to make sure the laser is detected by the ldr
// see if we can see the laser
power = lowPower; // start at the lowest level
analogWrite(laser, power); // turn the Laser at low power
delay(10);
while ((analogRead(trigger) - 10 < trip) && power<=255) { // try increasing the laser power
if(power==2){power=10;}
else{power += 10;}
analogWrite(laser, power); // try a higher power level
Serial.print(".");
delay(200);
}
if (power <=255){
Serial.print("\n\nLASER power level set at: ");
Serial.print(power);
Serial.println(" (max = 255)");
Serial.print("Trip level is: ");
Serial.println(trip);
ldr = analogRead(trigger); // print out current Ldr reading
Serial.print("LDR reading is: ");
Serial.println(ldr);
Serial.println("");
// check the mode we are in
if (normal == true){
Serial.print("Normal Mode - Alarm resets after ");
Serial.print(restore /1000);
Serial.println(" seconds");
soundSet(); // two beeps
}
if (oneShot== true){
Serial.println("OneShot Mode in operation, alarm will remain triggered\n");
soundSet2(); // three beeps
}
if (countMode == true){
Serial.println("\n***Count Beam-Brake Mode*** \n\n"
"Total incremented each time beam broken\n");
soundSet3(); // four beeps
}

attachInterrupt(0,laserOff,FALLING);
Serial.println("\nInterupt Enabled\n");
Serial.println("\n***Alarm now active*** \n"); // now just wait for the beam to be broken
}
}

void setAlarm(){
Serial.println("\n\n***ALARM ACTIVATED - LASER SHUT DOWN***\n");
if (oneShot == true){
Serial.println("\nOneShot Mode, press Arduino RESET to restart");
}
if (normal == true){
Serial.println("\nre-calibrating system .....");
}
digitalWrite(alarm, HIGH); // alarm has been tripped
alarmDisable=true; // stop alarm retriggering
power=0;
analogWrite(laser, power); // turn laser off
for(int i=0; i<5; i++){ // sound alarm
playTone(500, 200);
playTone(500, 400);
// duration, pitch
}
}

void laserOff(){
// called from an interupt, switches laser Off
emergency = true; // flag to show stop button on interupt line pressed
alarmDisable=true; // stop alarm from being triggered
power = 0;
powerTest = 0;
detachInterrupt(0);
}

void playTone(long duration, int freq) {
// duration in mSecs, frequency in hertz
if (silence == true){ // silent mode
return;
}
duration *= 1000;
int period = (1.0 / freq) * 1000000;
long elapsed_time = 0;
while (elapsed_time < duration) {
digitalWrite(pinSpeaker,HIGH);
delayMicroseconds(period / 2);
digitalWrite(pinSpeaker, LOW);
delayMicroseconds(period / 2);
elapsed_time += (period);
}
}

void initiallise(){
// reset the system
digitalWrite(alarm, LOW); // turn off alarm
ambient(); // get a trigger level based on the ambient light
Serial.print("\nChecking LASER do not stare directly at the beam ");
checkLaser(); // make sure the ldr can see the laser,
if (power > 255){
// we are here if the laser cannot be seen, so quit.
power=0;
analogWrite(laser, power); // shut down laser
Serial.println("\n\nCannot continue as the LDR cannot see the laser");
Serial.println("Either the background light level is too great "
"or the distance is too great");
Serial.println("\n>>>>>> Quitting program\n\n");
analogWrite(laser,0);
delay(1000);
exit(0);
}
}

void soundSet() {
// makes sound to show system is set
playTone(100, 600);
delay(200);
playTone(100, 600);
}

void soundSet2() {
// makes sound to show system is set
playTone(100, 600);
delay(200);
playTone(100, 600);
delay(200);
playTone(100, 600);
}

void soundSet3() {
// makes sound to show system is set
playTone(100, 600);
delay(200);
playTone(100, 600);
delay(200);
playTone(100, 600);
delay(200);
playTone(100, 600);
}

void countLoop(){
// counts number of beam breaks
if(emergency == false){
total++;
Serial.print("total = ");
Serial.println(total);
}
}

void printHeader(){
Serial.print("***Automated Laser Beam-Break by Chris Rouse Jan 2015***\n\n");
}

Advertisements

Keyes 8 RGB Led board.

.

It seems that I was wrong when I suggested this board was common Cathode, in fact it is common Anode, with the RGB pins driving the LED’s through transistors. The board can be obtained quite cheaply through eBay.

Connect the board to an Arduino as follows:

Vcc to Arduino 5 volts.
D0 to D6 connect to Arduino pins 2 to 8
D7 to Arduino pin 12
R to Arduino pin 9
G to Arduino pin 10
B to Arduino pin 11

To light a led take one of the D pins LOW, then take any of the RGB pins LOW as well,   with Vcc on the board connected to 5 volts. If you use PWM then almost any colour can be mixed. PWM is used in the following sketch which is why pin 12 is used for D7 as pins 9, 10 and 11 are PWM pins.

The following sketch fades each led from red to green to blue, then moves on to the next led and can be used to test the unit.

/********************************************************

Keyes 8 RGB LED board

This sketch fades each LED in sequence from Red, Green to Blue

LEDs are selected by taking the digit line LOW
then taking the R, G, B pins LOW to turn ON

Connect:
VCC pin to Arduino 5 v
D0 to pin 2
D1 to pin 3
D2 to pin 4
D3 to pin 5
D4 to pin 6
D5 to pin 7
D6 to pin 8
D7 to pin 12
R to pin 9
G to pin 10
B to pin 11
*********************************************************/

int ledRed = 9; // the pin that the Red LED is attached to
int ledGreen = 10; // the pin that the Green LED is attached to
int ledBlue = 11; // the pin that the Blue LED is attached to
int currentLed =0; // used in sub routine
int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by

// the setup routine runs once when you press reset:
void setup() {
Serial.begin(9600);
// declare pins to be an output:
pinMode(2, OUTPUT); // D0
pinMode(3, OUTPUT); // D1
pinMode(4, OUTPUT); // D2
pinMode(5, OUTPUT); // D3
pinMode(6, OUTPUT); // D4
pinMode(7, OUTPUT); // D5
pinMode(8, OUTPUT); // D6
pinMode(12, OUTPUT);// D7
//
pinMode(ledRed, OUTPUT);
pinMode(ledGreen, OUTPUT);
pinMode(ledBlue, OUTPUT);
}
//
void loop() {
for(int i=2; i= 0;){
// set the brightness of selected led:
analogWrite(currentLed, brightness);
// change the brightness for next time through the loop:
brightness -= fadeAmount;
// wait for 30 milliseconds to see the dimming effect
delay(20);
}
brightness += fadeAmount;
while(brightness <= 255){
// fade DOWN
// set the brightness of selected led:
analogWrite(currentLed, brightness);
// change the brightness for next time through the loop:
brightness += fadeAmount;
// wait for 30 milliseconds to see the dimming effect
delay(20);
}
}
void allOff(){
// turn all LEDs off
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(8, HIGH);
digitalWrite(12, HIGH);

}

Using a HC-SR501 PIR to detect movement.

This PIR sketch detects movement in a room and prints a message to the Serial Monitor as well as sounding a buzzer. The Arduino pin used to drive the buzzer could just as easily drive a LED or a relay.

The layout is shown below, a small speaker is connected between Gnd and pin 10. The PIR unit has three connections, connect Vcc to the Arduino 5volts , Gnd to Arduino Gnd and the signal output to Arduino pin 2.

/home/wpcom/public_html/wp-content/blogs.dir/10d/72092500/files/2014/12/img_1557-0.jpg

The sketch is shown here.


/*******************************************************

Uses a PIR sensor to detect movement, sounds a buzzer

*******************************************************/

int ledPin = 13; // choose the pin for the LED
int inputPin = 2; // choose the input pin (for PIR sensor)
int pirState = LOW; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int pinSpeaker = 10; //Set up a speaker on a PWM pin (digital 9, 10, or 11)

void setup() {
pinMode(ledPin, OUTPUT); // declare LED as output
pinMode(inputPin, INPUT); // declare sensor as input
pinMode(pinSpeaker, OUTPUT);

Serial.begin(9600);
Serial.println ("Calibrating sensor");
delay (2000); // it takes the sensor 2 seconds to scan the area
Serial.println ("Done!");
}

void loop(){
val = digitalRead(inputPin); // read input value
if (val == HIGH) { // check if the input is HIGH
blinky(); // blink LED when motion haas been detected
//digitalWrite(ledPin, HIGH); // turn LED ON
playTone(300, 160);
delay(150);
if (pirState == LOW) {
// we have just turned on
Serial.println("Motion detected!");
// We only want to print on the output change, not state
pirState = HIGH;
}
}
else {
digitalWrite(ledPin, LOW); // turn LED OFF
playTone(0, 0);
delay(300);
if (pirState == HIGH){
// we have just turned off
Serial.println("Motion ended!");
// We only want to print on the output change, not state
pirState = LOW;
}
}
}

void playTone(long duration, int freq) {
// duration in mSecs, frequency in hertz
duration *= 1000;
int period = (1.0 / freq) * 1000000;
long elapsed_time = 0;
while (elapsed_time < duration) {
digitalWrite(pinSpeaker,HIGH);
delayMicroseconds(period / 2);
digitalWrite(pinSpeaker, LOW);
delayMicroseconds(period / 2);
elapsed_time += (period);
}
}

void blinky() {
for(int i=0; i<3; i++) {
digitalWrite(13, HIGH);
delay(200);
digitalWrite(13, LOW);
delay(200);
}
}

Using a Hall effect sensor with Arduino

A Hall effect sensor is a solid state magnetic switch and can be used to switch a circuit in the presence of a magnetic field. A low cost Keyes KY-003, unit is used here as there seems to be a number of these Keyes sensor boards at low cost on eBay. This board has a single digital output that goes LOW when a magnetic field is detected. Note, each side of the sensor reacts to a different magnetic pole, so if nothing seems to happen use the other pole of the magnet.

/home/wpcom/public_html/wp-content/blogs.dir/10d/72092500/files/2014/12/img_1556.jpg

The following sketch turns on the onboard LED when a magnet is brought near to the sensor.


/***************************************************

Hall Effect magnetic switch, a magnet is used to turn on the onboard Led

Hall Effect board is from Keyes. KY-003

Connection:
Pin 1 connect to Arduino Gnd
Pin 2 connect to Arduino 5 volts
Pin 3 marked S connect to Arduino pin 2

***************************************************/

# define hallPin 2
# define ledPin 13

void setup() {
Serial.begin(9600);
pinMode(hallPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
}

void loop() {
if (! digitalRead(hallPin)) {
Serial.println("Magnetic field detected");
digitalWrite(ledPin, LOW); // turn on LED
}
else{
digitalWrite(ledPin, HIGH);
}
}

Using a rotary encoder with Arduino

A rotary or “shaft” encoder is an angular measuring device. It is used to precisely measure rotation of motors or to create wheel controllers (knobs) that can turn infinitely (with no end stop like a potentiometer has). Some of them are also equipped with a pushbutton when you press on the axis (like the ones used for navigation on many music controllers). They come in all kinds of resolutions, from maybe 16 to at least 1024 steps per revolution, and cost from 2 to maybe 200 EUR. (From playground.arduino.cc/Main/RotaryEncoders).

/home/wpcom/public_html/wp-content/blogs.dir/10d/72092500/files/2014/12/img_1555.jpg

This example is a low cost board from Keyes, I tried the example code from their website, but it needed some correction and even after that I was not happy with the result. I found this code on the Internet but cannot remember where. Full credit to the original writer of this sketch.

/* interrupt routine for Rotary Encoders

The average rotary encoder has three pins, seen from front: A C B
Clockwise rotation A(on)->B(on)->A(off)->B(off)
CounterCW rotation B(on)->A(on)->B(off)->A(off)

and may be a push switch with another two pins, pulled low at pin 8 in this case

*/

// usually the rotary encoders three pins have the ground pin in the middle
enum PinAssignments {
encoderPinA = 2, // right (labeled DT on our decoder, yellow wire)
encoderPinB = 3, // left (labeled CLK on our decoder, green wire)
clearButton = 8 // switch (labeled SW on our decoder, orange wire)
// connect the +5v and gnd appropriately
};

volatile unsigned int encoderPos = 0; // a counter for the dial
unsigned int lastReportedPos = 1; // change management
static boolean rotating=false; // debounce management

// interrupt service routine vars
boolean A_set = false;
boolean B_set = false;

void setup() {

pinMode(encoderPinA, INPUT_PULLUP); // new method of enabling pullups
pinMode(encoderPinB, INPUT_PULLUP);
pinMode(clearButton, INPUT_PULLUP);
// turn on pullup resistors (old method)
//digitalWrite(encoderPinA, HIGH);
// digitalWrite(encoderPinB, HIGH);
// digitalWrite(clearButton, HIGH);

// encoder pin on interrupt 0 (pin 2)
attachInterrupt(0, doEncoderA, CHANGE);
// encoder pin on interrupt 1 (pin 3)
attachInterrupt(1, doEncoderB, CHANGE);

Serial.begin(9600); // output
}

// main loop, work is done by interrupt service routines, this one only prints stuff
void loop() {
rotating = true; // reset the debouncer

if (lastReportedPos != encoderPos) {
Serial.print("Index:");
Serial.println(encoderPos, DEC);
lastReportedPos = encoderPos;
}
if (digitalRead(clearButton) == LOW ) {
encoderPos = 0;
}
}

// Interrupt on A changing state
void doEncoderA(){
// debounce
if ( rotating ) delay (1); // wait a little until the bouncing is done

// Test transition, did things really change?
if( digitalRead(encoderPinA) != A_set ) { // debounce once more
A_set = !A_set;

// adjust counter + if A leads B
if ( A_set && !B_set )
encoderPos += 1;

rotating = false; // no more debouncing until loop() hits again
}
}

// Interrupt on B changing state, same as A above
void doEncoderB(){
if ( rotating ) delay (1);
if( digitalRead(encoderPinB) != B_set ) {
B_set = !B_set;
// adjust counter - 1 if B leads A
if( B_set && !A_set )
encoderPos -= 1;

rotating = false;
}
}

Clockwise rotation gives an increasing value, anticlockwise rotation gives a decreasing value, from 0 the value becomes 65535 and the continues to decrease. Pressing the shaft in resets the value to 0.

Using the BH1750 light sensor

This sensor can give a fairly accurate indication of light level and is available on the usual breakout board.

/home/wpcom/public_html/wp-content/blogs.dir/10d/72092500/files/2014/12/img_1554.jpg

Connection is as follows

Gnd to Arduino Gnd
ADD to Gnd for 0x23 or 5volts for 0x5C address
SDA to Arduino A4
SCL to Arduino A5
Vcc to Arduino 5volts

The sketch I used reports light levels in lux units, the Serial Monitor needs to be set to 9600.

// Measuring Light Intensity with the BH1750 board
// Connect Gnd --> Gnd
// Connect ADD --> Gnd for address 0x23 or leave unconnected
// Connect ADD --> Vcc 5v for address 0x5C
// Connect SDA --> A4
// Connect SCL --> A5
// Connect Vcc --> 5 volts

int ledPin =13; // onboard LED

#include //BH1750 IIC Mode
int BH1750address = 0x23; //setting i2c address with ADD LOW
//int BH1750address = 0x5C; //setting i2c address with ADD HIGH

byte buff[2];
void setup()
{
Wire.begin();
Serial.begin(9600);//init Serial band rate
pinMode(ledPin, OUTPUT);
}

void loop()
{
int i;
uint16_t val=0;
BH1750_Init(BH1750address);
delay(200);

if(2==BH1750_Read(BH1750address))
{
val=((buff[0]< 1000) { // set the level here
digitalWrite(ledPin,HIGH); // turn on the onboard LED if light level above a certain amount
}
else {
digitalWrite(ledPin, LOW);
}
}
delay(150);
}

int BH1750_Read(int address) //
{
int i=0;
Wire.beginTransmission(address);
Wire.requestFrom(address, 2);
while(Wire.available()) //
{
buff[i] = Wire.read(); // receive one byte
i++;
}
Wire.endTransmission();
return i;
}

void BH1750_Init(int address)
{
Wire.beginTransmission(address);
Wire.write(0x10);//1lx reolution 120ms
Wire.endTransmission();
}

Checking I2C addresses on Arduino

/home/wpcom/public_html/wp-content/blogs.dir/10d/72092500/files/2014/12/img_1553.jpg

One of the biggest problems I found when working with I2C devices on the Arduino was being sure that the device was working and/or connected correctly.

A very useful sketch is available on github

github.com/todbot/arduino-i2c-scanner

That scans the I2C bus and shows the address of any connected device. The screen shot above shows a device at HEX address 23 has been found. The sketch as downloaded shows addresses in decimal, but it is an easy task to change three occurrences of DEC to HEX.

Two things to be aware of, the baud rate is set at 19200 so you need to set this on the Serial Monitor and if two or more devices on the bus share the same address they will show as one device.

Many thanks to the original author for publishing this sketch.