Controlling multiple LEDs using LDRs to turn them on and off

Afternoon,

I'm hoping somebody could help with with a project to turn LEDs on and off when you move something (e.g. hand) over them using LDRs. I started with one LED and one LDR and used this code which seems to work fine.

int sensorReading;
const byte LEDPin = 6;

void setup()
{
 Serial.begin(9600);
 pinMode(6,OUTPUT); //LED
}

void loop()
{
 sensorReading=analogRead(0); //LDR
 if (sensorReading<850)
 {
   digitalWrite(6,HIGH); //LED,ON
 }
 else digitalWrite(6,LOW); //LED,OFF
 Serial.println(sensorReading); 
 delay(100);
}

I understand the script in the "void loop" is what turns the LED on and off when you move your hand over the LDR. But if I want to have an array of LEDs all connected to individual LDRs that turn on and off independently when you move your hand over them one by one, is there a simpler way of writing the code to achieve this other than copying and pasting the above void loop and changing the corresponding analogRead and digitalWrite (as below)?

int sensorReading;
const byte LEDPin(1) = 6;
const byte LEDPin(2) = 7;

void setup()
{
 Serial.begin(9600);
 pinMode(6,OUTPUT); //LED1
 pinMode(7,OUTPUT); //LED2
}

void loop()
{
 sensorReading=analogRead(0); //LDR1
 if (sensorReading<800)
 {
   digitalWrite(6,HIGH); //LED1,ON
 }
 else digitalWrite(6,LOW); //LED1,OFF
 Serial.println(sensorReading); 
 delay(100);

 sensorReading=analogRead(1); //LDR2
 if (sensorReading<800)
 {
   digitalWrite(7,HIGH); //LED2,ON
 }
 else digitalWrite(7,LOW); //LED2,OFF
 Serial.println(sensorReading); 
 delay(100);
}

Sorry if this is very simple and i'm missing a trick.

Eventually I would like to create a simple 3x4 grid of LEDs that turn on and off when you move your hand across them (to create a shadow of your hand in LEDs). I would have a bigger grid but I'm guessing I will need to use & connect two arduino boards as there is only 6 analog pins on my UNO and I don't want to over complicate it at this stage.

Also any advice on whether I would be better off using photodiodes instead of LDRs would be much appreciated.

Thank you in advance!

Tom

Welcome to the Forum. Please read the two posts

How to use this forum - please read.
and
Read this before posting a programming question ...

at the top of this Forum on guidelines for posting here, especially the use of code tags which make the code look

like this

when posting source code files. It makes it easier to read, and can be copied with a single mouse click. Also, if you don't do it, some of the character sequences in the code can be misinterpred by the forum code as italics or funny emoticons.

Many questions can be answered by simply reading the documentation which is provided with the IDE, available under the help tab, or online here.

If you have already posted without using code tags, open your message and select "modify" from the pull down menu labelled, "More", at the lower left corner of the message. Highlight your code by selecting it (it turns blue), and then click on the "</>" icon at the upper left hand corner. Click on the "Save" button.

There are many other things that programmers do to make their code understandable. Please do them, as a courtesy to the members who volunteer their time to help you here. One is to use a standard indentation to clearly show the code blocks. So before posting the code, use Ctrl-T in the IDE to reformat the code in a standard format, which makes it easier for us to read. Another is to give things descriptive names. You can name numerical constants, pin numbers, variables and many other things in this way. For example, you can refer to a pin and an output level by number, like digitalWrite(3,0). But such a statement doesn't reveal anything about the purpose. digitalWrite(hornRelayPin, LOW) does. You can do that by declaring const byte hornRelayPin = 3; before setup() in your program.

Thank you aarg.

I hope the changes help. Sorry I missed using the code tags.

I'm unsure how to use const byte hornRelayPin = 3; obviously i'm guessing the wording changes slightly (i.e. hornReplayPin to LEDPin?) but I hope that it will at least make sense and somebody may be able to help.

Thanks,

Tom

You can make use of functions. The below code makes the assumption that an analog input is associated with a LED by a constant offset of 2. So analog0 is associated with a LED on pin2, analog1 is associated with a LED on pin3 and so on

void loop()
{
  for(int ledcnt=0;ledcnt<6;ledcnt++)
  {
    // switch LED on or of based on light level
    doLed(ledcnt);
    // wait a while
    delay(100);
  }
}

// read value of given LDR and switch associated LED on or off
void doLed(int iLedNumber)
{
  // read voltage
  int sensorReading = analogRead(iLedNumber)

  // logic to switch on or off
  if (sensorReading<800)
  {
    digitalWrite(iLedNumber + 2, HIGH);
  }
  else
  {
    digitalWrite(iLedNumber + 2, LOW);
  }
}

You can also make use of a lookup table; that way you will get rid of the hard relation (offset 2)

// lookup table to associated analog inputs 0 to 5 with pins connected to LEDs
int lookup[6];
void setup()
{
  // associated analog inputs 0 to 5 with LEDs on specified pin numbers
  lookup[0] = 13;
  lookup[1] = 11;
  lookup[2] = 10;
  lookup[3] = 9;
  lookup[4] = 12;
  lookup[5] = 3;
}

void loop()
{
  for(int ledcnt=0;ledcnt<6;ledcnt++)
  {
    // switch LED on or of based on light level
    doLed(ledcnt);
    // wait a while
    delay(100);
  }
}

// read value of given LDR and switch associated LED on or off
void doLed(int iLedNumber)
{
  // read voltage
  int sensorReading = analogRead(iLedNumber);

  // logic to switch on or off
  if (sensorReading<800)
  {
    digitalWrite(lookup[iLedNumber], HIGH);
  }
  else
  {
    digitalWrite(lookup[iLedNumber], LOW);
  }
}

In the last step, you can replace the pin numbers by sensible names.

#define LDR1 0  // LDR on analog 0
#define LDR2 1  // LDR on analog 1
#define LDR3 2  // LDR on analog 2
#define LDR4 3  // LDR on analog 3
#define LDR5 4  // LDR on analog 4
#define LDR6 4  // LDR on analog 5

#define LED1 13 // LED on digital 13
#define LED2 11 // LED on digital 11
#define LED3 10 // LED on digital 10
#define LED4 9  // LED on digital 9
#define LED5 12 // LED on digital 12
#define LED6 3  // LED on digital 3

int lookup[6];
void setup()
{
  // associated analog inputs 0 to 5 with LEDs on specified pin numbers
  lookup[LDR1] = LED1;
  lookup[LDR2] = LED2;
  lookup[LDR3] = LED3;
  lookup[LDR4] = LED4;
  lookup[LDR5] = LED5;
  lookup[LDR6] = LED6;
}

The loop stays the same.

Note: you need to complete the setup with the usual stuff like setting pinmode and so on.

void setup()
{
  // associated analog inputs 0 to 5 with LEDs on specified pin numbers
  lookup[0] = 13;
  lookup[1] = 11;
  lookup[2] = 10;
  lookup[3] = 9;
  lookup[4] = 12;
  lookup[5] = 3;
}

That is not a good way to do initialization. Do it like this:

  // associated analog inputs 0 to 5 with LEDs on specified pin numbers
const uint8_t  lookup[] = {13, 11, 10, 9, 12, 3};

void setup()
{
}

aarg:
That is not a good way to do initialization. Do it like this:

Thanks for that, I have been looking into the 'const' but wasn't quite there yet.

Hi,

Thank you for the replies.

I' struggling to define how your code works (which is does - so thank you) and hope that somebody could help with a my question below.

const int nLEDs=2;
int ledPins[nLEDs]={2,3};

const int nSensors=2;
int LDRs[nSensors]={(0),(1)};

int sensorReading; //analog pin reading
int ledPinX;

void setup()
{
  Serial.begin(9600);
  //Declares all LEDs as OUTPUT
  for (int i=0; i<nLEDs; i++)
  {
    pinMode(ledPins[i],OUTPUT);
  }
}

void loop()
{ 
  for (int i=0; i<nSensors; i++)
  {
    sensorReading=analogRead(LDRs[i]);
    Serial.println(sensorReading);
  
    //ledPinX=
    
    if (sensorReading<850);
    {
      digitalWrite(ledPinX,HIGH);
    } 
    else digitalWrite(ledPinX,LOW);
    delay(50);
  }
}

(To simplify it down, the arrays each have two LEDs/LDR which later I will increase to 12.)

I started by declaring all LEDs as OUTPUT, but struggling to work out how I can associate each LED with a specific LDR. I have a loop which reads each sensor to determine whether the associated LED should be on of off (below):

void loop()
{ 
  for (int i=0; i<nSensors; i++)
  {
    sensorReading=analogRead(LDRs[i]);
    Serial.println(sensorReading);

and in this loop I want to tell the arduino to turn on a specific LED associated with the LDR. I feel at this point I need to declare the LED number (i've used ledPinX to represent this) but i'm not sure how to do this.

Sorry, i'm very new to arduino, but I hope somebody may be able to help.

Thanks.

I must say I found this topic very interesting in that it (the members) showed differing ways to resolve the problem. I am, as it happens, in the middle of a project which itself is partly using ldrs (covered by hands etc) to choose different menu options. I often read back through old topics when looking for solutions to difficulties with getting an Arduino to do exactly as I want and as with this topic, it doesn't always need the defining post showing the full solution to help me along the way.
Thank you forum.

You're welcome. But be aware that responses to a question may address issues that some other person wouldn't need help with. I think it's because there are more ways to be wrong than there are to be right. :slight_smile:

aarg:
You're welcome. But be aware that responses to a question may address issues that some other person wouldn't need help with. I think it's because there are more ways to be wrong than there are to be right. :slight_smile:

Erm yes, he said rather hesitantly, so if a topic does not cover an area a reader needs help with, they won't necessarily find it useful. How very astute of you. Accordingly, if a post does indeed cover an area a reader finds interesting, then it may be of interest to them. I see what you mean. Time for a cuppa and bacon sarnie I feel.

Indeed, if there was more awareness of the search capability at the upper left of the forum page, it would be great. Otherwise it is a hit and miss effort to get an answer just by reading today's posts. It might even make a lot of posts unnecessary. But I think a magnifying glass is just too subtle for many people to grasp. :wink:

aarg:
Indeed, if there was more awareness of the search capability at the upper left of the forum page, it would be great. Otherwise it is a hit and miss effort to get an answer just by reading today's posts. It might even make a lot of posts unnecessary. But I think a magnifying glass is just too subtle for many people to grasp. :wink:

Yes exactly - search first for any resemblance to your query and then, if nothing suitable is found, post your question.

Anyway - back to the topic:
I have been looking at interrupts and need my void loop() to be interrupted if an analog pin has a certain data value (through an ldr).
Could anyone advise as to the best way to do this - the documentation seems to tell me interrupts only work on digital pins - or have I got that wrong?

Why do you think you need an interrupt?

sterretje:
Why do you think you need an interrupt?

Ah good question sterrtje - simple answer, my project needs two ldr's to be able to interrupt the void loop() independently and individually whilst allowing everything else within the loop() to continue up until the moment of interrupt then instantly branch off to do some specific function and then return to the loop().
All the best and all that
D6

How instantly? I'm quite sure that moving a hand over a LDR is in the order of a 0.5 to 1 second; that is ages for the microcontroller.

Interrupt routines should be short. Do something, read a few registers and set a flag and out. Next in loop you test the flag.

If you show your code, we will be able to advise better.

sterretje:
How instantly? I'm quite sure that moving a hand over a LDR is in the order of a 0.5 to 1 second; that is ages for the microcontroller.

Interrupt routines should be short. Do something, read a few registers and set a flag and out. Next in loop you test the flag.

If you show your code, we will be able to advise better.

OK so "instantly" in this instance is subjective and perhaps "straight away" would have been better.
Oh - code - so no one can tell me how to get an analog pin to work as an interrupt through an ldr without seeing my code first? Bit weird, or perhaps you imagine, without even seeing my code, I have made errors and what on earth do I think I need an interrupt for?
Meh, ok, pick the bones out of this then...

#include <SPI.h>
 #include <SD.h>
#include <TM1637Display.h> //4 digit display
#include "DHT.h"
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
//LedControl lc = LedControl(12, 11, 10, 1); //these are the pins on Arduino for the max7219 module
File myFile;
int tempC, rh;
#define DHTPIN 5     // what pin we're connected to
#define DHTTYPE DHT11   // DHT 11 
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x3F, 20, 4);  // Set the LCD I2C address

//HC_SR04
#define trigPin 8
#define echoPin 7
#define MAX_DISTANCE 150 //cm

#define soundPin 6

// 4 digit display
#define CLK 2
#define DIO 3
TM1637Display display(CLK, DIO);

int ldr1 = 0;
int ldr2 = 1;

int covered = 50; //ldr values
int uncovered = 250; //ldr values
String msgln1;
String msgln2;
String NextMeet;
int TempOffset;

// setup ldr options system
boolean option1 = false;
boolean option2 = false;
boolean option3 = false;
boolean option4 = false;
String op1l1, op1l2, op1l3, op1l4;
String op2l1, op2l2, op2l3, op2l4;
String op3l1, op3l2, op3l3, op3l4;
String op4l1, op4l2, op4l3, op4l4;

void setup() {  //run setup once
  Serial.begin(9600);
// /////////////////SD Setup ////////////
pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  pinMode(53, OUTPUT);
  digitalWrite(53, HIGH);
 //SD.begin(4);
 if (!SD.begin(4)) {
 Serial.println("initialization failed!");
 return;
 }
 Serial.println("initialization done.");



 readSDSettings();

 // debugging
 Serial.println("In RAM Memory");
 Serial.print("msgln1=");
 Serial.println(msgln1);
 Serial.print("msgln2=");
 Serial.println(msgln2);
 Serial.print("NextMeet=");
 Serial.println(NextMeet);
 Serial.print("TempOffset=");
 Serial.println(TempOffset);
 
 // ///////////////SD Setup ///////////////
  
  pinMode(ldr1, INPUT);       // declare the LDR as an INPUT
  pinMode(ldr2, INPUT);
  pinMode(ldr3, INPUT);
  pinMode(ldr4, INPUT);
  pinMode(trigPin, OUTPUT);  //Ping sensor setup
  pinMode(echoPin, INPUT);     //Pint sensor setup
  dht.begin(); // start temperature sensor
  lcd.begin();   // initialize the lcd for 16 chars 2 lines
  lcd.backlight(); // finish with backlight on
  lcd.clear();

}
void loop() {  //run continuously

  float h = dht.readHumidity();
  float t = dht.readTemperature();
  tempC = (int)t;
  rh   = (int)h;

  // HC_SR04
  int duration, distance;
  digitalWrite(trigPin, LOW);  // Added this line
  //delayMicroseconds(2); // Allow to set
  digitalWrite(trigPin, HIGH);
  //delayMicroseconds(10); // Allow to set
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) / 29.1;
if (distance<50){
 noTone(soundPin);
  // play on soundPin, note, duration ms:
  tone(soundPin, 1023, 100);
  delay(200);
noTone(soundPin);
  tone(soundPin, 823, 100);
  delay(300);
    noTone(soundPin);
    tone(soundPin, 1023, 100);
  delay(200);
noTone(soundPin);
   tone(soundPin, 823, 100);
  delay(300);
    noTone(soundPin); 
}
  // LCD
  //readSDSettings;
  lcd.setCursor(0, 0);
  lcd.print(msgln1.substring(1, 20)); //22 character in the string inc " at each end
  lcd.setCursor(0, 1);
  lcd.print(msgln2.substring(1, 20)); // only the middle 20 chars needed
  lcd.setCursor(0, 2);
  lcd.print("Temperature: ");
  lcd.setCursor(15, 2);
  lcd.print("c");
  lcd.setCursor(1, 3);
  lcd.print("Next Meet ");
  lcd.print(NextMeet);
  lcd.setCursor(13, 2);
  lcd.print(tempC-TempOffset); // calibrated with off-set to show correct temperature

  // 7segment 4 digit led display
  display.setBrightness(0x0f);
  uint8_t segto;
  display.showNumberDec(distance, true);
  segto = 0x80 | display.encodeDigit((distance / 100) % 10);

  

}
void readSDSettings(){
 char character;
 String settingName;
 String settingValue;
 myFile = SD.open("poster.txt");
 if (myFile) {
 while (myFile.available()) {
 character = myFile.read();
 while((myFile.available()) && (character != '[')){
 character = myFile.read();
 }
 character = myFile.read();
 while((myFile.available()) && (character != '=')){
 settingName = settingName + character;
 character = myFile.read();
 }
 character = myFile.read();
 while((myFile.available()) && (character != ']')){
 settingValue = settingValue + character;
 character = myFile.read();
 }
 if(character == ']'){
 
  //Debuuging Printing
 Serial.print("Name:");
 Serial.println(settingName);
 Serial.print("Value :");
 Serial.println(settingValue);
 
 // Apply the value to the parameter
 applySetting(settingName,settingValue);
 // Reset Strings
 settingName = "";
 settingValue = "";
 }
 }
 // close the file:
 myFile.close();
 } else {
 // if the file didn't open, print an error:
 Serial.println("error opening poster.txt");
 }
 }
 void applySetting(String settingName, String settingValue) {
 if(settingName == "msgln1") {
msgln1 = settingValue;
 }
 if(settingName == "msgln2") {
msgln2 = settingValue;
 }
 if(settingName == "NextMeet") {
 NextMeet = settingValue;
 }
if(settingName == "TempOffset") {
  TempOffset = settingValue.toInt();
}
if(settingName == "op1l1") {
op1l1 = settingValue;
 }
 if(settingName == "op1l2") {
op1l2 = settingValue;
 }
 if(settingName == "op1l3") {
op1l3 = settingValue;
 }
 if(settingName == "op1l4") {
op1l4 = settingValue;
 }
 if(settingName == "op121") {
op2l1 = settingValue;
 }
 if(settingName == "op2l2") {
op2l2 = settingValue;
 }
 if(settingName == "op2l3") {
op2l3 = settingValue;
 }
 if(settingName == "op2l4") {
op2l4 = settingValue;
 }
 if(settingName == "op3l1") {
op3l1 = settingValue;
 }
 if(settingName == "op3l2") {
op3l2 = settingValue;
 }
 if(settingName == "op3l3") {
op3l3 = settingValue;
 }
 if(settingName == "op3l4") {
op3l4 = settingValue;
 }
 if(settingName == "op4l1") {
op4l1 = settingValue;
 }
 if(settingName == "op4l2") {
op4l2 = settingValue;
 }
 if(settingName == "op4l3") {
op4l3 = settingValue;
 }
 if(settingName == "op4l4") {
op4l4 = settingValue;
 }
}
void displayoptions() {
  lcd.setCursor(0,0);
  while(option1){
    lcd.print(op1l1);
    lcd.setCursor(1,0);
    lcd.print(op1l2);
    lcd.setCursor(2,0);
    lcd.print(op1l3);
    lcd.setCursor(3,0);
    lcd.print(op1l4);
  }
while(option2){
 lcd.print(op2l1);
    lcd.setCursor(1,0);
    lcd.print(op2l2);
    lcd.setCursor(2,0);
    lcd.print(op2l3);
    lcd.setCursor(3,0);
    lcd.print(op2l4); 
}
while(option3){
 lcd.print(op3l1);
    lcd.setCursor(1,0);
    lcd.print(op3l2);
    lcd.setCursor(2,0);
    lcd.print(op3l3);
    lcd.setCursor(3,0);
    lcd.print(op3l4); 
}
while(option4){
  lcd.print(op4l1);
    lcd.setCursor(1,0);
    lcd.print(op4l2);
    lcd.setCursor(2,0);
    lcd.print(op4l3);
    lcd.setCursor(3,0);
    lcd.print(op4l4);
}
}

Oh, we can tell or point you in the right direction. There are two (or more) articles on the web about interrupt driven analogReads for arduino; one by Nick Gammon if I'm not mistaken. You can do a search (not posting from a pc at the moment so I don't have my references at hand).

Question is if it's the right approach. And seeing delays in your code, there are more than likely far better approaches.

Fantastic, it's a shame you couldn't help although thank you for the link suggestion, it'll be very helpful sterretje,

I shall search for Nicks article.
As an aside, I found a couple of ldr modules in the workshop (probably from eBay and/or China, which output digital (onboard Schottky and pot for adjusting the trigger level) and so I'll use those in the meantime. The code is for an interactive poster and so most of it is display and formatting with delays to make it more child-friendly. After a month or so, the component parts will be broken down for use in other projects.
Thanks again
D6

Just in case you can't find them

https://www.gammon.com.au/adc; search the page for the keyword 'interrupt'; it's at about a 1/3 of the page

And as I mentioned, if you get rid of the delay around your tone functions, you probably don't need interrupts. You can use a small statemachine and a millis() based timing (see e.g. Using millis() for timing. A beginners guide)

Good luck.