Multiple inputs/functions to control single pin

I'm working on a project where I need three inputs to control a single pin. The inputs are

  • IR Sensor
  • Serial
  • Physical button

To get things started I've tried to get serial and the IR sensor working but my code is buggy. I've written two functions one for the IR and one for the serial. These functions work independently but when I try to use them in tandem no beans. How can I get these to work and what needs to be done to include a button?

Thanks for looking!
Rich

int statLED5 = 13;
int irPin = A0; //Sensor pin 1 wired to Arduino's pin A5
int statLED_state5 = LOW;  //mac

// IR sensor variables
int start_bit = 2200; //Start bit threshold (Microseconds)
int bin_1 = 1000; //Binary 1 threshold (Microseconds)
int bin_0 = 400; //Binary 0 threshold (Microseconds)
int incomingByte = 0;

void setup(){
  Serial.begin(9600);
  pinMode(statLED5, OUTPUT);
  pinMode(irPin, INPUT);
  digitalWrite(statLED5, statLED_state5);  //mac
} 

void loop(){
  while (Serial.available() == 0);

  //Read the Input
  int val = Serial.read() - '0';

  switch(val)
  {
  case 2:
    Serial.println("Circuit 5 Serial");
    if(statLED_state5 != LOW)
      statLED_state5 = LOW;
    else
      statLED_state5 = HIGH;
    digitalWrite(statLED5, statLED_state5);  //mac
    Serial.println("OFF");
    delay(250);
    break;
  }  

  int key = getIRKey(); //Fetch the key
  if(key != 0) //Ignore keys that are zero
  {
    Serial.print("Key ");
    Serial.print(key);
    Serial.println(" Recieved: ");

    switch(key)
    {
    case 1302:  // Button 1 AXD7381 Pioneer AV Remote
      Serial.println("Circuit 5 IR");
      if(statLED_state5 != LOW)
        statLED_state5 = LOW;
      else
        statLED_state5 = HIGH;
      digitalWrite(statLED5, statLED_state5);  //mac
      delay(250);
      break;  

    }
  }
}

int getIRKey() {
  int data[12];
  int i;

  while(pulseIn(irPin, LOW) < start_bit); //Wait for a start bit

    for(i = 0 ; i < 11 ; i++)
    data[i] = pulseIn(irPin, LOW); //Start measuring bits, I only want low pulses

  for(i = 0 ; i < 11 ; i++) //Parse them
  {
    if(data[i] > bin_1) //is it a 1?
      data[i] = 1;
    else if(data[i] > bin_0) //is it a 0?
      data[i] = 0;
    else
      return -1; //Flag the data as invalid; I don't know what it is! Return -1 on invalid data
  }

  int result = 0;
  for(i = 0 ; i < 11 ; i++) //Convert data bits to integer
      if(data[i] == 1) result |= (1<<i);

  return result; //Return key number
}

So you need to AND those two facts together?- the facts that val is 2 and key is 1302?

You could use an if like this:

if (val==2 && key==1302)
{
if(statLED_state5 != LOW)
        statLED_state5 = LOW;
      else
        statLED_state5 = HIGH;
      digitalWrite(statLED5, statLED_state5);  //mac
      delay(250);
}

Later you add the button for say:

if (val==2) && (key==1302 && button==LOW)

(Preceded by a button = digitalRead(pinNum); or similar.....)

EDIT... Ooops I had the brackets wrong, fixed now. I had

if (val==2) && (key==1302)

Should be

if (val==2 && key==1302)

See man page

Cool, that makes sense but it's not working yet. I think what I need is an or statement so something like

if (val==2 || key==1302)

So far neither one works.

When I test it I'm able to read from the IR sensor one time and that's it, it's not able to recieve additional signals and the it seems to ignore serial terminal input.

Here's what the code looks like now.

int statLED5 = 13;
int irPin = A0; //Sensor pin 1 wired to Arduino's pin A5
int statLED_state5 = LOW;  //mac

// IR sensor variables
int start_bit = 2200; //Start bit threshold (Microseconds)
int bin_1 = 1000; //Binary 1 threshold (Microseconds)
int bin_0 = 400; //Binary 0 threshold (Microseconds)
int incomingByte = 0;

void setup(){
  Serial.begin(9600);
  pinMode(statLED5, OUTPUT);
  pinMode(irPin, INPUT);
  digitalWrite(statLED5, statLED_state5);  //mac
} 

void loop(){
  int key = getIRKey(); //Fetch the key

  while (Serial.available() == 0);

  //Read the Input
  int val = Serial.read() - '0';

if (val==2 || key==1302){
    Serial.println("Circuit 5 Serial");
    if(statLED_state5 != LOW)
      statLED_state5 = LOW;
    else
      statLED_state5 = HIGH;
    digitalWrite(statLED5, statLED_state5);  //mac
    Serial.println("OFF");
    delay(250);

  }  
 
}

int getIRKey() {
  int data[12];
  int i;

  while(pulseIn(irPin, LOW) < start_bit); //Wait for a start bit

    for(i = 0 ; i < 11 ; i++)
    data[i] = pulseIn(irPin, LOW); //Start measuring bits, I only want low pulses

  for(i = 0 ; i < 11 ; i++) //Parse them
  {
    if(data[i] > bin_1) //is it a 1?
      data[i] = 1;
    else if(data[i] > bin_0) //is it a 0?
      data[i] = 0;
    else
      return -1; //Flag the data as invalid; I don't know what it is! Return -1 on invalid data
  }

  int result = 0;
  for(i = 0 ; i < 11 ; i++) //Convert data bits to integer
      if(data[i] == 1) result |= (1<<i);

  return result; //Return key number
}

Add some extra serial prints to see what val and key are?

void loop(){
  int key = getIRKey(); //Fetch the key
Serial.print(key); //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  while (Serial.available() == 0);

  //Read the Input
  int val = Serial.read() - '0';
Serial.print(val); //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
if (val==2 || key==1302){

Hmmm, no printing....

Perhaps I need a Serial.flush(); somewhere? I've tried but get the same results...

Perhaps I need a Serial.flush(); somewhere? I've tried but get the same results...

Then, that's a clue that you don't need Serial.flush(). In fact, 99.999% of the time it is used, it is not needed.

Why are there no Serial.print() statements in setup()? Why isn't there one before getIRKey()? If that function never ends, there will be no output.

Here it is with print statements. The setup print statement works.

When I first open the serial terminal I can't send IR signals but when I enter 2 into the terminal it's echoed on the screen. From there I can send 3 or 4 IR signals at which point it stops taking input from both sources ; IR or Serial.

int statLED5 = 13;
int irPin = A0; //Sensor pin 1 wired to Arduino's pin A5
int statLED_state5 = LOW;  //mac

// IR sensor variables
int start_bit = 2200; //Start bit threshold (Microseconds)
int bin_1 = 1000; //Binary 1 threshold (Microseconds)
int bin_0 = 400; //Binary 0 threshold (Microseconds)
int incomingByte = 0;

void setup(){
  Serial.begin(9600);
  pinMode(statLED5, OUTPUT);
  pinMode(irPin, INPUT);
  digitalWrite(statLED5, statLED_state5);  //mac
  Serial.print("Hey, is this thing on?");
} 

void loop(){
  while (Serial.available() == 0);

  //Read the Input
  int val = Serial.read() - '0';
  Serial.print(val);
 
  int key = getIRKey(); //Fetch the key
  Serial.print(key);

    if (val==2 || key==1302){
    Serial.println("Circuit 5 Serial");
    if(statLED_state5 != LOW)
      statLED_state5 = LOW;
    else
      statLED_state5 = HIGH;
    digitalWrite(statLED5, statLED_state5);  //mac
    Serial.println("OFF");
    delay(250);

  }  
}

int getIRKey() {
  int data[12];
  int i;

  while(pulseIn(irPin, LOW) < start_bit); //Wait for a start bit

    for(i = 0 ; i < 11 ; i++)
    data[i] = pulseIn(irPin, LOW); //Start measuring bits, I only want low pulses

  for(i = 0 ; i < 11 ; i++) //Parse them
  {
    if(data[i] > bin_1) //is it a 1?
      data[i] = 1;
    else if(data[i] > bin_0) //is it a 0?
      data[i] = 0;
    else
      return -1; //Flag the data as invalid; I don't know what it is! Return -1 on invalid data
  }

  int result = 0;
  for(i = 0 ; i < 11 ; i++) //Convert data bits to integer
      if(data[i] == 1) result |= (1<<i);

  return result; //Return key number
}

When I first open the serial terminal I can't send IR signals

Because loop() is blocked waiting for serial data. That is not a good way to write a responsive program. You can store the value received from the sensor and deal with it when there is serial input, without blocking.

It isn't clear why you have serial input or IR input controlling an LED. It isn't clear why you aren't using Ken Shirrif's IRremote library.

Wow that library is awesome! It will defensibility change the way I'm writing the code for this project. After checking out the examples I would highly recommend this for anyone using IR in their projects. Here's where you can get the library

Thanks for the heads up!

Getting Closer...

So I re wrote the code using the IR library which helped clean things up. Now I'm back to my main question how can I have serial and IR signals change the state of a pin? I have the IR and Serial working below in separate if statements. But what I'm after is something like the following; remember I would like to add a button in the future as well.

if (valSerial==1 || valIR==1302)
{
      Serial.println("Circuit 5 Serial");
      if(statLED_state5 != LOW)
        statLED_state5 = LOW;
      else
        statLED_state5 = HIGH;
      digitalWrite(statLED5, statLED_state5);  //mac
      Serial.println("OFF");
      delay(250);
    }
/*
 * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * Version 0.1 July, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

#include <IRremote.h>

int RECV_PIN = A0;

int x = 0;

int statLED5 = 13;
int statLED_state5 = LOW;  //mac

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  pinMode(statLED5, OUTPUT);
  irrecv.enableIRIn(); // Start the receiver
  Serial.println ("Send me some signals");
}

void loop() {
  if (Serial.available() == 0);
  {
    int valSerial = Serial.read() - '0';  //Read the serial port

    if(valSerial == 1){
      Serial.println("Circuit 5 Serial");
      if(statLED_state5 != LOW)
        statLED_state5 = LOW;
      else
        statLED_state5 = HIGH;
      digitalWrite(statLED5, statLED_state5);  //mac
      Serial.println("OFF");
      delay(250);
    }  

    if (irrecv.decode(&results)) {
      int valIR = (results.value);
      // Serial.println(results.value, HEX);
      Serial.println(valIR);

      if(valIR == 4064){
        Serial.println("Circuit 5 IR");
        if(statLED_state5 != LOW)
          statLED_state5 = LOW;
        else
          statLED_state5 = HIGH;
        digitalWrite(statLED5, statLED_state5);  //mac
        Serial.println("OFF");
        delay(250);
      }
      irrecv.resume(); // Receive the next value
    }
  }

}
  if (Serial.available() == 0);
  {
    int valSerial = Serial.read() - '0';  //Read the serial port

If NO serial data is available, read serial and interpret that?

As for inputs changing the state of the led, use one variable to hold the state of the led and have your sensing and serial code sections change that variable as desired then, last thing, use the variable to digitalWrite the led pin.

If you map your logic in comments before you write the code then you can work out the steps in simplified form before getting down to syntax AND your comments might actually help in debugging.

If NO serial data is available, read serial and interpret that?

The read() is done whether there is serial data available to read, or not. It is not conditional.

Only the NOP (:wink: at the end of the if statement is conditional.

Oh! I missed that semicolon!