[solved] IR LED @ 38kHz using interrupts

I am trying to create breakbeam sensors for a stair project. However I have encountered a strange gremlin. When I use a separate arduino to power the IRLED, it all acts as it should. The blue and yellow LEDs light up when I shine the IRLED at the sensors, and turn off when I block it or shine it elsewhere. The code on the IRLED powering arduino is as follows:

#include <Arduino.h>

//interrupt for turning the 38Hz IR signal on/off
ISR (TIMER1_COMPA_vect)
{
  TCCR2A ^= _BV (COM2A0) ;  // Toggle OC2A on Compare Match  
  if ((TCCR2A & _BV (COM2A0)) == 0)
    digitalWrite (11, LOW);  // ensure off   
}  // end of TIMER1_COMPA_vect

void setup() {
    // put your setup code here, to run once:
    pinMode(11, OUTPUT); //OC2A pin
    TCCR1A = _BV(COM1A0); //CTC
    TCCR1B = _BV(WGM12) | _BV(CS12); //CTC, prescaler 256
    OCR1A = 1875; //This value probably doesn't matter that much, but it works so why change it?
    TIMSK1 = _BV (OCIE1A);   // enable Timer1 Interrupt
    //Set up timer 2 for 38kHz PWM. toggles on OCR1A value
    TCCR2A = _BV(WGM21) | _BV (COM2A0);    //CTC
    TCCR2B = _BV (CS20);   // No prescaler
    OCR2A =  209;          //frequency 38kHz
}

void loop() {
    // put your main code here, to run repeatedly:
}

Using the same timer interrupt code, but adding in the logic for the IR sensors and indicator LEDs I get this:

#include <Arduino.h>

#define LED_Y 4
#define LED_B 5
//outputs from VS838 IR sensors
#define SEN_Y 6
#define SEN_B 7
unsigned long t;
unsigned long blueCount;
unsigned long yellowCount;
unsigned long timeCount;

//interrupt for turning the 38Hz IR signal on/off
ISR (TIMER1_COMPA_vect)
{
  TCCR2A ^= _BV (COM2A0) ;  // Toggle OC2A on Compare Match  
  if ((TCCR2A & _BV (COM2A0)) == 0)
    digitalWrite (11, LOW);  // ensure off   
}  // end of TIMER1_COMPA_vect

void setup() {
    // put your setup code here, to run once:
    // Serial.begin(9600);
    pinMode(LED_Y, OUTPUT);
    pinMode(LED_B, OUTPUT);
    pinMode(SEN_Y, INPUT_PULLUP);
    pinMode(SEN_B, INPUT_PULLUP);
    t = millis();
    blueCount = 0;
    yellowCount = 0;
    timeCount = 0;
        // create 38kHz signal on pin 11 with 50% duty cycle
    pinMode(11, OUTPUT); //OC2A pin
    TCCR1A = _BV(COM1A0); //CTC
    TCCR1B = _BV(WGM12) | _BV(CS12); //CTC, prescaler 256
    OCR1A = 1875; //This value probably doesn't matter that much, but it works so why change it?
    TIMSK1 = _BV (OCIE1A);   // enable Timer1 Interrupt
    //Set up timer 2 for 38kHz PWM. toggles on OCR1A value
    TCCR2A = _BV(WGM21) | _BV (COM2A0);    //CTC
    TCCR2B = _BV (CS20);   // No prescaler
    OCR2A =  209;          //frequency 38kHz
}

void loop() {
    // put your main code here, to run repeatedly:
    while(millis() - t < 100){
        timeCount++;
        if(!digitalRead(SEN_B)){
            blueCount++;
        }
        if(!digitalRead(SEN_Y)){
            yellowCount++;
        }
    }
    // Serial.println(timeCount);
    // Serial.println(blueCount);
    // Serial.println(yellowCount);
    // Serial.println("");
    // Serial.println(timeCount / blueCount);
    // Serial.println(timeCount / yellowCount);
    // Serial.println("");
    if(timeCount / blueCount < 3){
        digitalWrite(LED_B, LOW);
    }
    else{
        digitalWrite(LED_B, HIGH);
    }
    if(timeCount / yellowCount < 3){
        digitalWrite(LED_Y, LOW);
    }
    else{
        digitalWrite(LED_Y, HIGH);
    }
    t = millis();
    blueCount = 0;
    yellowCount = 0;
    timeCount = 0;
}

However, whenever I power the IRLED from the same arduino that I have the sensors plugged into, it doesn’t work at all. When I have the serial monitor stuff uncommented it tells me that the blueCount & yellowCount are half of the timeCount which is what I would expect if we connected pin 11 directly to these inputs. Where I point the IRLED is irrelevant, and the same thing happens if I use a non IRLED (green for example).

So it seems there is some sort of interference going on when I plug the IRLED into pin 11, but I am damned if I know how to stop it from happening. I would like to get the project done on one arduino, but failing that I guess I will just use another arduino (or some other circuit) to generate my 38kHz signal. I was wondering if it was to do with the timer interrupt pins being associated with the timers, but even if I use the pins A0-A5 as the input pins I get the same result. Another reason I don’t think the timer interrupt is the problem is because the circuit works if there is no load on pin 11.

I have tried both connecting the IRLED directly from pin 11 to ground, and connecting pin 11 to a transistor to drive the LED. There is no difference in the result.

Also, reason I have the 38kHz switching on and off is because if you send a constant 38kHz at the sensor, they saturate (is this the correct terminology?) and can’t give a constant output. Hence why I am dividing the timeCount by the blueCount & yellowCount.

I have attached the circuit diagram (oh actually I realise I forgot the current limiting resistors (220 ohm) for the blue and yellow LEDs in the diagram) plus it is also here: Imgur: The magic of the Internet

You should try to avoid having a blocking while loop within the loop(). Use an if then else construct and a flag instead. If the Ir sensors appear to be triggered by noise, power each separately via a say 100 ohm resistor and put a say 100nf capacitors between the power pins of each. You can use the tone() function to generate a 38kHz signal.

Thank you for your response. I realise that the blocking loop isn’t the best way to go about reading the sensors, but this is only for a stair light project and they are the break beam sensors, so a 100ms delay isn’t gonna kill me. Once I get this sorted out I will have a rethink about how to restructure that.

The reason I didn’t use tone() and went for a hardware setup for the 38kHz was so I can set and forget it, and it will not affect my code in any way. This forum post was where I got the original idea from. I will give it a shot using tone() and see how it goes.

When you say power each separately, do you mean a 100 ohm resistor between +5V and the VCC pin of the sensor? I have attached an image of how I interpret what you said, is this correct? Also here: Imgur: The magic of the Internet

The GPIO pins do not pump out much current and while you might get away with driving one or two LEDs all by themselves, when you start adding functionality to need to consider the total load budget. If you're going to power an IR LED and expect more than a few centimeters, high-side load an NPN transistor (2N2222 generally works well) and connect it to the +5V pin that is nailed to the regulator thereby bypassing the load limit on the pins.

Thank you for your response. I had considered that and actually had a set up on a breadboard using a transistor. I wasn't really sure about how to choose resistor values though, from a few things I read you need something to limit the current to the base coming from pin 11 (the 38kHz signal). I have 15 stairs, can I just connect them all between the emitter of the NPN transistor and ground, with a current limiting resistor between +5V and the collector?

Shouldn't, that's low-side loading. Connect your current-limiting resistor to +5, then your LED, connect to collector, emitter to ground. You'll also need a limiting resistor between the Arduino pin and the base. You can do the math but if the gain is 50 to 100, about 10K works out good. Just do a quick Google on high-side load. There's lots of diagrams that'll give you better info than me.

OK thanks, looking something like figure 1 in this diagram? https://electronics.stackexchange.com/questions/368350/activation-of-multiple-leds-with-one-or-several-transistors

That's it! The difference of course between the two diagrams is single vs. individual control. If you choose the 2N2222, it is spec'd at about 1A, which means about 600mA at 100% duty cycle which I wouldn't load at more than 300mA. This would be plenty for about 15 LEDs.

Legend. Obviously since the IR LEDs are being used for a break beam sensor I do not need individual control. If I choose a current limiting resistor size of 220ohms, that would give me a current per LED of about 15mA. (Assuming a forward voltage of 1.5V, so voltage over the resistor is 5 - 1.5 = 3.5V. 3.5 / 220 = 0.015). With this current through 15 LEDs that's around 225mA, well below 1A. And that's at 100% duty cycle which is not the case here since I have them flashing at 38kHz.

Now to test out the resistor and capacitors to see if I can get the IR sensors working.

Let us know how it goes.

The diagram in #2 is not what I meant. Look at figure 4 in this document: http://www.mouser.com/catalog/specsheets/vs_82606.pdf For two sensors, it requires 2 resistors and 2 capacitors.

For a beam break application, IR leds with a narrow viewing angle are better (say 8 degrees) because these give a longer range, but need more accurate alignment with the sensor(s).

I simplified this down to one sensor and have updated the code and circuit diagram as follows, along with the recommended resistor and capacitor values.

#include <Arduino.h>

unsigned long t;
unsigned long sensorCount;
unsigned long timeCount;

//interrupt for turning the 38Hz IR signal on/off
ISR (TIMER1_COMPA_vect)
{
  TCCR2A ^= _BV (COM2A0) ;  // Toggle OC2A on Compare Match  
  if ((TCCR2A & _BV (COM2A0)) == 0)
    digitalWrite (11, LOW);  // ensure off   
}  // end of TIMER1_COMPA_vect

void setup() {
    Serial.begin(9600);
    pinMode(4, OUTPUT);
    pinMode(5, INPUT_PULLUP);
    // put your setup code here, to run once:
    pinMode(11, OUTPUT); //OC2A pin
    TCCR1A = _BV(COM1A0); //CTC
    TCCR1B = _BV(WGM12) | _BV(CS12); //CTC, prescaler 256
    OCR1A = 1875; //This value probably doesn't matter that much, but it works so why change it?
    TIMSK1 = _BV (OCIE1A);   // enable Timer1 Interrupt
    //Set up timer 2 for 38kHz PWM. toggles on OCR1A value
    TCCR2A = _BV(WGM21) | _BV (COM2A0);    //CTC
    TCCR2B = _BV (CS20);   // No prescaler
    OCR2A =  209;          //frequency 38kHz
    t = millis();
    timeCount = 0;
    sensorCount = 0;
}

void loop() {
    // put your main code here, to run repeatedly:
    while(millis() - t < 500){ // using 500 so it's easier to read the Serial data
        timeCount++;
        if(!digitalRead(5)){
            sensorCount++;
        }
    }
    t = millis();
    Serial.println(timeCount);
    Serial.println(sensorCount);
    Serial.println("");
    if(timeCount / sensorCount < 3){
        digitalWrite(4,HIGH);
    }
    else{
        digitalWrite(4,LOW);
    }
    timeCount = 0;
    sensorCount = 0;
}

Circuit diagram is here: Imgur: The magic of the Internet and also attached.

As before, the circuit works nicely when I upload this to two arduinos, and connect the IR circuitry to one and the sensor and indicator LED to the other. However, I am still getting the interference from the 38kHz signal once I use it all together on one arduino. It is not a proximity/blocking problem, because even if I plug in a green LED in place of the IR one, I get the same reading (sensorCount is half of timeCount), but it works out once I separate the 38kHz off to the other arduino.

I’m no electronics engineer (mechanical actually), so I don’t really know what’s going on here. Is there some sort of filter I have to design to stop the 38kHz signal appearing on my IR sensors?

Any ideas are much appreciated.

Is there some sort of filter I have to design to stop the 38kHz signal appearing on my IR sensors?

Normally you want only the 38kHz signal on your sensor, that is the point. The sensor should not respond to any other frequency like stray light, it should respond ONLY to 38kHz.

It depends on what sort of sensor you have. This will affect the code as well. Some sensors can not cope with more than about 50 bursts of modulated light, others can cope with a continuous 38kHz signal.

To narrow the angle you should put the diodes and sensors at the end of a tube.

Another trick you can employ is to only have one IR LED on at a time and only look at the sensor opposite.

C1 should be much bigger, the data sheets typically suggest 4u7F

Here you are not counting pulses from the sensor (where you would be looking for LOW/HIGH transitions in pin 5) you are counting the number of iterations of your while loop when pin 5 is low during the 500 mS period . That while loop will run very quickly.

while(millis() - t < 500){ // using 500 so it's easier to read the Serial data
        timeCount++;
        if(!digitalRead(5)){
            sensorCount++;
        }
}

Include a link to the data sheet for the IR sensor.

Do you see the same effect when you remove the sensor entirely from the circuit ?

Euhm - why wouldn't you just set up a timer in PWM mode to get the 38kHz signal for the LED?

That way, you don't have to worry about other stuff the microcontroller was doing interfering with the signal... (though the current issues mentioned above are of course still relevant)

Grumpy_Mike: Normally you want only the 38kHz signal on your sensor, that is the point. The sensor should not respond to any other frequency like stray light, it should respond ONLY to 38kHz.

Grumpy Mike, what I mean by the 38kHz signal on the sensor is not IR light at 38kHz, it's the voltage output from pin 11. So if any current passes through pin 11, my IR sensor gives a reading that it is seeing IR light when it is not. That is my problem. It senses perfectly when the IR LED is being driven from another arduino, but once I plug ANY LED into pin 11, the output of the sensor follows pin 11's voltage. Not just an IR LED but a red, green, colour doesn't matter.

Grumpy_Mike: It depends on what sort of sensor you have. This will affect the code as well. Some sensors can not cope with more than about 50 bursts of modulated light, others can cope with a continuous 38kHz signal.

It is a VS838, sourced cheaply of Amazon here in Japan. It doesn't seem to be able to cope with a continuous signal, hence I am modulating that at a 50% duty cycle with my interrupt on timer 1.

Grumpy_Mike: To narrow the angle you should put the diodes and sensors at the end of a tube.

Another trick you can employ is to only have one IR LED on at a time and only look at the sensor opposite.

Break beam is working, what is not is that the system breaks when I try to drive the IR LEDs from the same arduino as the sensors are connected to. I am also alternating sensor and LEDs as I go down the staircase (i.e. RHS has sensor, LED, sensor... and LHS has LED, sensor, LED...).

Grumpy_Mike: C1 should be much bigger, the data sheets typically suggest 4u7F

I will try a bigger capacitor when I get home.

Thank you for your advice.

6v6gt:
Here you are not counting pulses from the sensor (where you would be looking for LOW/HIGH transitions in pin 5) you are counting the number of iterations of your while loop when pin 5 is low during the 500 mS period . That while loop will run very quickly.

while(millis() - t < 500){ // using 500 so it's easier to read the Serial data

timeCount++;
        if(!digitalRead(5)){
            sensorCount++;
        }
}

That is my intention for the code. As the 38kHz signal is controlled through timer 1 at a 50% duty cycle, I expect that sensorCount should be approximately 50% of timeCount. I don’t care the number of pulses since I am not reading a code like one would read from a remote control, I only care if the sensor is seeing IR light or not. Do you agree with my logic?

6v6gt:
Include a link to the data sheet for the IR sensor.

Do you see the same effect when you remove the sensor entirely from the circuit ?

The sensor did not come with a datasheet, but it has VS838 printed on the top. I found this datasheet on google: http://www.hyzt.com/manager/upimg/200987165432.pdf This was the closest to an English one that I found.

I will try and see what happens when I remove the sensor from the circuit but I run current through pin 11 when I get home.

Thank you for your continued advice.

DrAzzy: Euhm - why wouldn't you just set up a timer in PWM mode to get the 38kHz signal for the LED?

That way, you don't have to worry about other stuff the microcontroller was doing interfering with the signal... (though the current issues mentioned above are of course still relevant)

I have done that. That is what all the code to do with the timer counters, interrupts and registers in the setup is for. It is set and forget.

The code was copied and modified from this thread: https://forum.arduino.cc/index.php?topic=102430.0

Thank you for your input.

Metallor: That is my intention for the code. As the 38kHz signal is controlled through timer 1 at a 50% duty cycle, I expect that sensorCount should be approximately 50% of timeCount. I don't care the number of pulses since I am not reading a code like one would read from a remote control, I only care if the sensor is seeing IR light or not. Do you agree with my logic?

The sensor did not come with a datasheet, but it has VS838 printed on the top. I found this datasheet on google: http://www.hyzt.com/manager/upimg/200987165432.pdf This was the closest to an English one that I found.

I will try and see what happens when I remove the sensor from the circuit but I run current through pin 11 when I get home.

Thank you for your continued advice.

Timer2 is producing a 38kHz carrier at 50% duty cycle. Timer1 is runs at 33 Hz (also 50% duty cycle), that it switching that carrier alternately on and off every 30 mS. The idea is to generate bursts of 38kHz. However, your data sheet specifies much shorter bursts of around 600 nS with a 900 ns gap (see the diagram in the data sheet) and implies a > 5mS delay between a series of bursts. Naturally, the device can probably tolerate some deviation from this specification.

OK, so I did a bit of experimentation and created a little test with 3 "inputs". The first one is whether or not there is a capacitor (10uF, as that was what I had in my kit) between VCC and Ground of the sensor. The second was the colour of the LED connected to the 38kHz signal (pin 11), IR or green (the closest one on hand). The third was whether or not there was an obstruction (a highly scientific right hand) between the 38kHz LED and sensor. The logic of this is as follows:

| |Capacitor | |LED colour | |Obstruction | |Output | | - | - | - | - | | | No | | Green | | No | | ON | | | No | | Green | | Yes | | ON | | | No | | IR | | No | | ON | | | No | | IR | | Yes | | ON | | | Yes | | Green | | No | | OFF | | | Yes | | Green | | Yes | | OFF | | | Yes | | IR | | No | | ON | | | Yes | | IR | | Yes | | OFF |

As you can see from the table, if there is no capacitor in place, the output is high, whether there is IR light present on the sensor or not. Once the capacitor is in place, we get the expected results. The output remains low if the LED is green because it produces no IR light. The output goes on when there is IR light reaching the sensor and goes off when an obstruction is present.

You also mentioned trying to see what happened when I remove the sensor from the circuit entirely. This causes the output to go off.

Someone on another forum mentioned changing the 38kHz to as much as 45kHz to reduce sensitivity since we are not dependant on a perfect signal like we would be when reading remote control codes. Worth a look maybe if I have sensitivity problems further down, but will leave it as is for now.

Another thing I thought of was to increase the resistance of the current limiting resistor to reduce the amount of light coming from the IR LED to possibly decrease sensitivity. Something I may look into if I encounter further problems.

I will consider this as solved, putting the 10uF capacitor across the VCC and Ground pins of the IR sensor filtered out the rogue signal that was appearing on the output of the IR sensor and allows the break beam to work as expected. It seems that I need to work on my electronics theory, which I am rather rusty at not having touched it for around 10 years.

Thanks to everyone who helped me out in this thread, and I hope that if someone down the road has a similar problem can get it sorted quick smart if they stumble across this thread.