slide projector control

Hi guys,
the idea is to have this IR controlled box that will interface with a slide projector, and allow me to remote control it with a common TV IR remote.

The output of this box will interface with the projector with a relay, that is closed for a short time, generating a pulse that moves the tray and activates the slide loading sequence.

I was thinking of the modes, using 2 buttons on the remote (let’s call them SINGLE and AUTO):

one click on SINGLE will advance of one slide only

one click on AUTO will activate the timed sequence:
it will load the slide, wait for the time defined by the value read on a pot (to have an adjustable time delay), then load the next slide,and repeat the sequence until I cklick on the same button AUTO again.

I’m away from home and I don’t have any board with me, so I can only play with the code for the moment.

How does it look?
Did I got anything wrong?

Thanks

#include <IRremote.h>
const int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);
decode_results results;


#define OUT_FWD 2   // 
#define OUT_REV 4   // 

#define POT_TD A0  // 


int PULSE = 350;


int TIMER ;

int AUTO_FWD = 0;         //
int AUTO_FWD_START = 0;         //
int AUTO_REV = 0;         //

void setup() {

  Serial.begin(9600);   //
  irrecv.enableIRIn();  //
  irrecv.blink13(true); //


  pinMode(OUT_FWD, OUTPUT); //
  pinMode(OUT_REV, OUTPUT); //

  digitalWrite(OUT_FWD, HIGH); //
  digitalWrite(OUT_REV, HIGH); //

}

void loop() {

  Serial.print("HEX: ");
  Serial.print(results.value, HEX);




  int TIMER = map(POT_TD, 0, 1023, 1500, 3000);




  if (irrecv.decode(&results))

  {
    switch (results.value) {
      case 0x410:  //
        digitalWrite(OUT_FWD, LOW); //
        delay(PULSE); //
        digitalWrite(OUT_FWD, HIGH); //
        break;

     // case 0x10:  //
     //   digitalWrite(OUT_REV, LOW); //
     //   delay(PULSE); //
     //   digitalWrite(OUT_REV, HIGH); //
     //   break;

      case 0x15:  //
        if (AUTO_FWD == 0) {                  //
          digitalWrite(AUTO_FWD_START, HIGH); //
          AUTO_FWD = 1;                       //
        }
        else {
          digitalWrite(AUTO_FWD_START, LOW);  //
          AUTO_FWD = 0;                       //
        }
        while ( digitalRead(AUTO_FWD_START) == 1 ) //
          digitalWrite(OUT_FWD, LOW); //
        delay(PULSE); //
        digitalWrite(OUT_FWD, HIGH); //
        delay(TIMER); //
        //
        //
        break;


    }

    irrecv.resume();
  }

}
  while ( digitalRead(AUTO_FWD_START) == 1 )
               digitalWrite(OUT_FWD, LOW); //
            delay(PULSE); //
            digitalWrite(OUT_FWD, HIGH); //
            delay(TIMER); //

Did you forget some curly brackets there? How do you ever exit that while loop besides resetting the Arduino?

Your code would be easier to read if you remove the useless white space and format with the IDE auto format tool (CTRL-T or Tools, Auto Format). And with auto format there is an indication that the brackets are missing as only the first line under the while is indented.

The white spaces were left there after I removed my own comments, before posting the sketch, my bad :slight_smile: .

There are no errors when I compile the sketch, therefore I guess that your comment on the missing brackets is to “isolate” the while loop.

The sketch was already formatted with ctrl+T before posting it, could you please explain the

And with auto format there is an indication that the brackets are missing as only the first line under the while is indented.

I’ve added the brackets where I think they should be

#include <IRremote.h>
const int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);
decode_results results;

#define OUT_FWD 2   // 
#define OUT_REV 4   // 
#define POT_TD A0  // 


int PULSE = 350;
int TIMER ;

int AUTO_FWD = 0;         //
int AUTO_FWD_START = 0;         //
int AUTO_REV = 0;         //

void setup() {

  Serial.begin(9600);   //
  irrecv.enableIRIn();  //
  irrecv.blink13(true); //

  pinMode(OUT_FWD, OUTPUT); //
  pinMode(OUT_REV, OUTPUT); //

  digitalWrite(OUT_FWD, HIGH); //
  digitalWrite(OUT_REV, HIGH); //

}

void loop() {

  Serial.print("HEX: ");
  Serial.print(results.value, HEX);

  int TIMER = map(POT_TD, 0, 1023, 1500, 3000);

  if (irrecv.decode(&results))

  {
    switch (results.value) {
      case 0x410:  //
        digitalWrite(OUT_FWD, LOW); //
        delay(PULSE); //
        digitalWrite(OUT_FWD, HIGH); //
        break;

      case 0x15:  //
        if (AUTO_FWD == 0) {                  //
          digitalWrite(AUTO_FWD_START, HIGH); //
          AUTO_FWD = 1;                       //
        }
        else {
          digitalWrite(AUTO_FWD_START, LOW);  //
          AUTO_FWD = 0;                       //
        }
        {
        while  ( digitalRead(AUTO_FWD_START) == 1 ) //
          digitalWrite(OUT_FWD, LOW); //
        delay(PULSE); //
        digitalWrite(OUT_FWD, HIGH); //
        delay(TIMER); //
        }
        //
        //
        break;
    }

    irrecv.resume();
  }

}

thanks

The curly brackets enclose a block of code. Without curly brackets, the while loop is ended by the first semicolon. So in that while statement only the line:

digitalWrite(OUT_FWD, LOW); //

is part of the while loop. The rest of the statements:

delay(PULSE); //
digitalWrite(OUT_FWD, HIGH); //
delay(TIMER); //

Are outside of the while.
With curly brackets the whole block is part of the while loop.

while ( digitalRead(AUTO_FWD_START) == 1 )
          {
            digitalWrite(OUT_FWD, LOW); //
            delay(PULSE); //
            digitalWrite(OUT_FWD, HIGH); //
            delay(TIMER); //
           }

, could you please explain the

Here is the original while loop after auto format.

while ( digitalRead(AUTO_FWD_START) == 1 )
     digitalWrite(OUT_FWD, LOW); //
delay(PULSE); //
digitalWrite(OUT_FWD, HIGH); //
delay(TIMER); //

Note how the first statement after the while is indented farther than the rest and the rest are indented the same as the while. That tells me that only the first statement after the while will be part of the while and the rest are outside the while and will execute unconditionally. Hence I think that the brackets to enclose the rest are missing.

All clear now.
Thanks for the explanation, now your initial advice makes sense.

As per the remaining code, I'm assuming that there's nothing unusual, :grinning: :grinning: am I right?

Thanks again

I'm assuming that there's nothing unusual, am I right?

Yes, as far as I can see.

You might want to read a button (or something) in that while loop so that you can use it to exit the while loop, otherwise you will need to reset the Arduino to exit the while loop.

The next step would be to learn how to do the timing without using the blocking delay() function.
Non-blocking timing tutorials:
Several things at a time.
Beginner's guide to millis().
Blink without delay().

You might want to read a button (or something) in that while loop so that you can use it to exit the while loop, otherwise you will need to reset the Arduino to exit the while loop.

This is how I was solving this:
The following code should toggle the bit AUTO_FWD every time I press the same button on the remote
(first press start the sequence, second press stop the sequence).

The change of state of AUTO_FWD will force the AUTO_FWD_START to change as well, and this will get the while loop going.

So, the moment AUTO_FWD_START goes to 0, the while loop should stop.

Did I get it right?

 case 0x15:  //
        if (AUTO_FWD == 0) {                  //
          digitalWrite(AUTO_FWD_START, HIGH); //
          AUTO_FWD = 1;                       //
        }
        else {
          digitalWrite(AUTO_FWD_START, LOW);  //
          AUTO_FWD = 0;                       //
        }

        while  ( digitalRead(AUTO_FWD_START) == 1 ) //
        {
          digitalWrite(OUT_FWD, LOW); //
          delay(PULSE); //
          digitalWrite(OUT_FWD, HIGH); //
          delay(TIMER); //
        }

The change of state of AUTO_FWD will force the AUTO_FWD_START

The thing is that I don't see how the change in state of AUTO_FWD can be sensed while in the while loop. While in the while loop the remote is no longer being read.

When you post code, please post the whole sketch.

if (AUTO_FWD == 0)                    //
            {
               digitalWrite(AUTO_FWD_START, HIGH); //
               AUTO_FWD = 1;                       //
            }
            else
            {
               digitalWrite(AUTO_FWD_START, LOW);  //
               AUTO_FWD = 0;                       //
            }
int AUTO_FWD_START = 0;

AUTO_FWD_START is a variable, not a pin. Using digitalWrite() there is just writing to pin 0, not changing the value of AUTO_FWD_START.

and here:

while  ( digitalRead(AUTO_FWD_START)

you read the value of pin 0, not the value of AUTO_FWD_START.

Here is an example of how to do what (I think) that you want. Once in AUTO, press any remote button (except FWD or REV) to stop the slide show. Tested on my Uno. You will need to change the IR codes to match your remote.

#include <IRremote.h>
const int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);
decode_results results;

#define OUT_FWD 2   //
#define OUT_REV 4   //

#define POT_TD A0  //

int PULSE = 350;

int TIMER ;

const unsigned long RPT = 0xffffffff; // repeat code
const unsigned long FWD = 0x4eb39a65;
const unsigned long REV = 0x4eb3f807;
const unsigned long AUTO = 0x4eb3ba45;

unsigned long IRin = 0;

void setup()
{
   Serial.begin(115200);   //
   irrecv.enableIRIn();  //
   irrecv.blink13(true); //


   pinMode(OUT_FWD, OUTPUT); //
   pinMode(OUT_REV, OUTPUT); //

   digitalWrite(OUT_FWD, HIGH); //
   digitalWrite(OUT_REV, HIGH); //
}

void loop()
{
   unsigned long TIMER = map(analogRead(POT_TD), 0, 1023, 1500, 10000); // unsigned long cause we use it for timing (millis()).

   readIR();

   switch (IRin)
   {
      case FWD:  // forward one slide
         advanceOneSlide();
         IRin = 0;
         break;

      case REV:  // back one slide
         reverseOneSlide();
         IRin = 0;
         break;

      case AUTO:  // auto advance
         static unsigned long slideTimer = 0;
         if (millis() - slideTimer >= TIMER)
         {
            slideTimer = millis();
            advanceOneSlide();
            //delay(TIMER);
         }
         break;
   }

}

void readIR()
{
   if (irrecv.decode(&results))
   {
      Serial.print("HEX: ");
      Serial.println(results.value, HEX);
      if (results.value == RPT) // ignore repeat code
      {
         irrecv.resume();
         return;
      }
      IRin = results.value;
      irrecv.resume();
   }
}


void advanceOneSlide()
{
   digitalWrite(OUT_FWD, LOW); //
   delay(PULSE); //
   digitalWrite(OUT_FWD, HIGH); //
}

void reverseOneSlide()
{
   digitalWrite(OUT_REV, LOW); //
   delay(PULSE); //
   digitalWrite(OUT_REV, HIGH); //
}

EDIT: I had to fix this.

int TIMER = map(POT_TD, 0, 1023, 1500, 3000);

Need to read the pot with analogRead().

And changed this:

     case AUTO:  // auto advance
         advanceOneSlide();
         delay(TIMER);
         break;

To use millis() for timing between slides to make the program more responsive.

.......what can I say...... I'm impressed !! :o :o

Thanks for the help, and for the brand new code !!

I see that some instructions are written in a way that is new to me, I'll do my own research, in order to understand why.

Thanks again

What on earth is a slide projector?