Timed LDR sensor readings

Hello folks,

I have an problem wich i would like some feedback on from more experienced arduino users then me. I hope its not inappropriate to do such a large post as a 1st post. ( i want to explain my issue as clear as possible)

I am trying to make a small book (only 4 pages for now) wich has ldr's in it for triggering a LED (and later triggering a audio sample in an other IC).

The objective is to make a book that works good under different light conditions and i want to try a few different methods of reading and comparing LDR's

But since pretty much a noob to arduino and programming in particular im having a little trouble realizing an idea i have in code.

I have written a simple program for a book with 4 pages that works but it's a bit sensitive, when u turn the pages sometimes it will activate a led that is not supposed to light up.

The program does the following:

It reads the LDR's and maps the value to a range of 0-4.
Then it looks if there are any LDR's that have a higher value then 2.
If only LDR1 is > 2 turn on LED1, if LDR1 and 2 are > 2 turn on LED2 and so on.

This seems to work ok, when i turn to page 1 LDR1 get's lid and LED1 turn on. I turn to page 2 and LDR1 and 2 get lid and LED2 turn on. But as i mentioned before it's a bit noisy, sometimes when i turn the pages a LED lights up that isn't supposed to light up. :-[

I have an idea to fix this issue but don't know how to implement it in my programming.
My idea is the following:

I want to have have the LED switched on after the LDR value is higher then 2 for a specified amount of time.
For example: if LDR1 > 2 for longer then 300ms turn on LED1
if LDR1 and 2 > 2 for longer then 300ms turn on LED2

But i have no idea how to implement the time into the code :-[
I looked into alot of examples and tutorials but can't seem to figure it out, so i was hoping someone here could help me out.

Here's the code i have so far (remember im a programming noob who is also not very good at algebra, so it is prolly not very optimized).

/* 
 LDR Book
    
*/

const int LED1 = 8;             // pin that the led is connected to
const int LED2 = 7;
const int LED3 = 6;
const int LED4 = 5;
const int LDR1 = A0;            // pin for LDR1
const int LDR2 = A1;            // pin for LDR2
const int LDR3 = A2;            // pin for LDR3
const int LDR4 = A3;            // pin for LDR4
const int sensorMin = 50;       // sensor minimum, discovered through experimentation
const int sensorMax = 600;      // sensor maximum, discovered through experimentation
int state = 0;                  // State of the LDR's


void setup() {
  pinMode(LED1, OUTPUT);        // Set the LED pins to Output
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  
  Serial.begin(9600);           // initialize serial communication:
}


void loop (){
  //read LDR1 through 4
  int LDR1val = analogRead(LDR1);
  int LDR2val = analogRead(LDR2);
  int LDR3val = analogRead(LDR3);
  int LDR4val = analogRead(LDR4);
  
  // map the LDR sensors ranges to a range of 4 options
  int LDR1range = map(LDR1val, sensorMin, sensorMax, 0, 3);
  int LDR2range = map(LDR2val, sensorMin, sensorMax, 0, 3);
  int LDR3range = map(LDR3val, sensorMin, sensorMax, 0, 3);
  int LDR4range = map(LDR4val, sensorMin, sensorMax, 0, 3);
  
  
  // Set the state of the leds depending on how many LDR's are getting light 
 if(LDR1range >= 2)
    state = 1;
 
 if(LDR1range && LDR2range >= 2)
   state = 2;
 
 if(LDR1range && LDR2range && LDR3range >= 2)
  state = 3;
 
 if(LDR1range && LDR2range && LDR3range && LDR4range >= 2)
  state = 4;
 
 if(LDR1range < 2)
  state = 0;

// Turn on the LED depending on state 
if (state ==0){
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);
  digitalWrite(LED4, LOW);
 }
if (state ==1){
  digitalWrite(LED1, HIGH);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);
  digitalWrite(LED4, LOW);
 }
if (state ==2){
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, HIGH);
  digitalWrite(LED3, LOW);
  digitalWrite(LED4, LOW);
 }
if (state ==3){
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, HIGH);
  digitalWrite(LED4, LOW);
 }
if (state ==4){
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);
  digitalWrite(LED4, HIGH);
 } 
}

I'm currently looking into the blink without delay and smoothing examples to see if i can implement it into my programming and
see if it helps with the noise issue.
But i would very much like to hear some input of more experienced users then me.

Also any other ideas on Triggering the pages with the LDR's are welcomed.

I am afraid that the method described above won't work in every lighting condition (light rooms, dark rooms, natural light , artifical light). But since i'm new to programming i want to start simple and am learning alot along the way.

My next idea was to have an extra 5th LDR in the book (already in the book prototype i use now) wich is used to determin the lowest and highest brightness of the room the book is in.
Then it compares the other LDR's tot the Value of the 5th LDR and if for example LDR1 is higher or has a value that is close to that of the 5th LDR, LED1 s turned on.
I made a small program that tries to do this but it wasn't working at all. I'm still looking into how to code this so that will work with a LDR that determines the room brightness.

I hope my story isn't to long and boring ::).

Any help would be much appreciated.

Best regards,

Sim

 if(LDR1range && LDR2range >= 2)

This is NOT testing that LDR1range and LDR2 range are greater than or equal to 2. It is testing that LDR1range is true, and if it is, whether LDR2range is greater than or equal to true.

There are no shortcuts.

 if(LDR1range [glow]>= 2[/glow] && LDR2range >= 2)
const int LDR1 = A0;

I thought A0 to A5 were reserved for whn you used the analogue inputs as digital?

I thought A0 to A5 were reserved for whn you used the analogue inputs as digital?

I have no idea, but every example i can find on the arduino site uses A0 t/m A5 to define the analog inputs.
And when i print the value to serial it seems to print the analog values and not just high or low.

They're wrong.
They will, of course work (the input mux select is a simple mask operation), but just not on the pins you expect!

On my Arduino Uno the analog pins are marked A0 t/m A5 on the board itself, on my duemilanove the pins are marked 0t/m5 on the board.

I use the uno for this project, and pin A0 definitely corresponds with A0 in the programming so it does work on the pin i expect it to work on.

But anyways this seems get a bit off topic and is kind of irrelevant to my problem since both methods seem to have the same functionallity and the analog values are read ok.

Anyone have any ideas how i can implement the timed reading so that the led only turns on after the LDR has been high for a specified amount of time.

NB The mux select in analogRead is now adjusted to allow A0 onwards to be used to select the correct input, as well as set the digital pinMode if necessary.

Mea culpe.
Apologies all round.

Oops.
:-[

What he said.

Anyone have any ideas how i can implement the timed reading so that the led only turns on after the LDR has been high for a specified amount of time.

Once you can get stable readings from the LDRs, then it is simply a matter of keeping track of when a particular LDR reached a particular value. Storing the times in an array makes it easy. Each time the LDR reading goes above a threshold, record the time in the array. Each time through loop, if the LDR is above the threshold, see how long it has been above the threshold. If it has been above long enough, turn the LED on.

Although why you want to turn on more light is beyond me.

Although why you want to turn on more light is beyond me.

??

What do u mean by turning on more light?

The point is not to light a led, the leds are only there so i know that it send out a signal on the correct digital pin. The end goal is to have the arduino send a digital signal to a voice-IC wich in turn wil play an audio sample over a speaker.

So if i understand u correctly this is what i have to do. (im a noob so i will dissect ur suggestion in a way my simple brain will understand)

I know the millis function and if im correct this is the time that has passed since the arduino has been reset.

When the LDR is ># store the millis somewhere
Then when the loop runs again and LDR is still ># store millis again and then substract the 1st stored millis from the 2nd and store the remaining value (Let's call it timePassed) and then replace the the 1st stored millis with the 2nd.

Then the loops runs again and it has to substract millis1 from millis2 again and add the remaining value to timePassed again.

This loop will keep running and when timePassed goes beyond a specified value it will turn on the LED and has to reset the timepassed after.

Plz correct me if i have understand this wrong.

Now if my understanding of this function is correct i still need to do the hard part and that is convert this into code.

Ive been looking into some examples but i can't seem to find any examples that do something like this except for the debounce example in tutorials.

Does anyone know of more examples that have sort of similar functionallity or make heavy use of recording time in it that i can look into and learn from?

What do u mean by turning on more light?

You said:

Anyone have any ideas how i can implement the timed reading so that the led only turns on after the LDR has been high for a specified amount of time.

So, when the LDR is sensing plenty of light, turn on an LED. Turning on an LED isn't going to suck up all the light in the room. So, when you turn the LED on, you get MORE light.

The point is not to light a led

Then why did you say it was?

You need to keep track of when the LDR reading exceeds a threshold and when it drops below that threshold. Record the time when either event occurs.

Some psuedo code for what you need to do.
On each pass through loop:
Read the LDR value.
If the reading is above the threshold:
If the current reading and the previous reading are above the threshold:
If the current time - previous time is greater than interval:
Turn the LED on
Otherwise, record the time when the LDR went above the threshold.
Save the previous reading.

Take a shot at converting this to code. If you need help, post what you have.

he end goal is to have the arduino send a digital signal to a voice-IC wich in turn wil play an audio sample over a speaker.

So what chip are you going to use?

You could use a wave shield and record your own samples.

@PaulS

The LEDS are only there so i can check a signal is coming out of the digital out.
I think i have figured out a way to time the sensorreading, wich i think is similar to ur pseudo code.
Will post the code when i finish it. (Almost time to go home, prolly gonna be friday since i have a day off tommorow)

Thanks for ur lightning fast help, it is much appreciated and im learning alot from u.

@Grumpy_Mike

I'm probably gonna use Alpha AM4EA127A_DB flash or OTP cards as the voice IC. These are very cheap Voice IC's the company i work for uses in their products. They are widely used in greetingcards with sound and electronics.

The reason i'm using arduino now for prototyping is that these chips have no analog inputs to read LDR values.
I'm trying to make a proof of concept that with analog sensors i can make an audiobook that will work under many different or difficult lighting conditions.

I have added timed reading to my code and also added smoothing to have an average reading from the LDR.

So far it seems to work the LED turns on after LDR1 has been lit for 500ms.

But this only works for 1 LDR and 1 led so far.
Now i have to make it so it reads from 5 LDR's.
I can do this by adding new time and average reading variables for every seperate LDR but this seems like a cumbersome way of doing this.

/*  

Smoothing LDR test

*/

const int LED1 = 8;
const int LDR1 = A0;
const int sensorMin = 0;
const int sensorMax = 600;
const int numReadings = 10;
int state = 0;
int timeNew = 0;
int timePass = 0;
const int timeON = 500;

int readings [numReadings];  // the readings from the analog input
int index = 0;
int total = 0;
int LDR1avg = 0;

void setup ()
{
  
  pinMode (LED1, OUTPUT);        // set the LED pins to output
  Serial.begin(9600);            // initialize serial communication
  // initialize all the readings to 0:
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings[thisReading] = 0;
    
}


void loop() 
{
  // substract the last reading
  total = total - readings[index];
  // read from the sensor
  readings[index] = analogRead(LDR1);
  // add the reading to the total:
  total = total + readings[index];
  // advance to next position in the array:
  index = index + 1;
  
  // if we're at the end of the array...
  if (index >= numReadings)
    // ...wrap around to the beginning:
    index = 0;
           
 // Calculate the average;
 LDR1avg = total / numReadings;
 // print to serial 
 Serial.println(LDR1avg, DEC);
 
 // get the current time and store it as oldtime
 int timeOld = millis();     
 // map the LDR sensor average reading to a range of 10 options
 int LDR1range = map(LDR1avg, sensorMin, sensorMax, 0, 10);

 
  Serial.println(LDR1range);
  
  // check if LDR1range is higher then 5 if so start recording the time 
  if (LDR1range >= 5)
      timeNew = (millis() - timeOld);
      timePass = (timePass + timeNew);
      
      // If an LDR >= 5 for a by timeON speciefied amount of time set the state
      if (timePass >= timeON && LDR1range >=5 ){
      state = 1;
      timePass = 0;
      }
      
      
      // If LDR1 <5 set state to 0
      if (LDR1range <5){
        state = 0;
        timePass = 0;
      } 
    
    // Turn on LED depending on state)
    if (state ==0){
      digitalWrite(LED1, LOW);
    }
    
    if (state ==1){
      digitalWrite(LED1, HIGH);
    }

}

I'm now searching for a way to have multiple LDR's read and have the readings averaged in an effecient way. (not having to need 10lines of code for a each LDR)
Also i'm looking for a way i can reuse the time part to have it reset and start keeping track of time again when LDR1 and 2 are high, reset and start over when LDR1,2 and 3 are high and so on.

Anyway any suggestions to optimize this code are welcomed.