IR Break Beam Timer Coding Question

Hello, I am making a simple dual break beam sensor with IR LEDS and Sensors (TSOP4038). Everything is working well but it is printing multiple values in the Serial Monitor. Im pretty sure it is reading the sensor values multiple times. I am struggling what to add to the code to just get it to display the one (first) .

Below is the code

// IR Break Beam Sensors with Timer

int IR_LED1 = 3; // IR LED for Sensor 1
int IR_LED2 = 5; // IR LED for Sensor 2
int IR_Receiver1 = 4; // IR Receiver for Sensor 1
int IR_Receiver2 = 2; // IR Receiver for Sensor 2
int state1 = 0; // State of Sensor 1
int state2 = 0; // State of Sensor 2
unsigned long startTime = 0; // Start time
unsigned long duration = 0; // Duration of beam break

void setup() {
  pinMode(IR_LED1, OUTPUT); // Set IR LED 1 pin as output
  pinMode(IR_LED2, OUTPUT); // Set IR LED 2 pin as output
  pinMode(IR_Receiver1, INPUT); // Set IR Receiver 1 pin as input
  pinMode(IR_Receiver2, INPUT); // Set IR Receiver 2 pin as input
  Serial.begin(9600); // Initialize serial communication

  tone (IR_LED1, 38000);
}

void loop() {
  // Check if beam for Sensor 1 is broken
  digitalWrite(IR_LED1, HIGH); // Turn on IR LED 1
  delay(10); // Wait for 10 milliseconds
  state1 = digitalRead(IR_Receiver1); // Read state of IR Receiver 1
  if (state1 == HIGH) { // If IR beam is broken for Sensor 1
    startTime = millis(); // Start timer
    Serial.println("IR beam broken for Sensor 1!"); // Print message
  }
  digitalWrite(IR_LED1, LOW); // Turn off IR LED 1

  // Check if beam for Sensor 2 is broken
  digitalWrite(IR_LED2, HIGH); // Turn on IR LED 2
  delay(10); // Wait for 10 milliseconds
  state2 = digitalRead(IR_Receiver2); // Read state of IR Receiver 2
  if (state2 == HIGH) { // If IR beam is broken for Sensor 2
    duration = millis() - startTime; // Calculate duration of beam break
    Serial.print("IR beam broken for Sensor 2! Duration: "); // Print message
    Serial.print(duration); // Print duration in milliseconds
    Serial.println("ms");
  }
  digitalWrite(IR_LED2, LOW); // Turn off IR LED 2

  delay(10); // Wait for 10 milliseconds before repeating
}

Below is what I see in the serial monitor when I wave my hand through the timing system.

IR beam broken for Sensor 1!
IR beam broken for Sensor 1!
IR beam broken for Sensor 1!
IR beam broken for Sensor 2! Duration: 432ms
IR beam broken for Sensor 2! Duration: 463ms
IR beam broken for Sensor 2! Duration: 494ms

Thanks for your help

Please post a photo of a hand drawn wiring diagram, with pins and connections clearly labeled. Also, post links to the sensor product pages or data sheets.

Look for when there is a change in the sensor signal, not the level of the signal.

1 Like

Gap between fingers?

1 Like

I think it is due to the time it takes to go around loop().

Each 'Duration' is 31ms longer than the previous one.
There are 3 x delay(10); in loop(), giving a 30ms delay plus 1ms to do the work.

1 Like

The TSOP4038 is a 38kHz receiver, you need to generate a 38kHz signal.
Use tone(pinno, 38000) to pulse the IR_LED1 and IR_LED2

Should I be putting some sort of a delay when there is a signal change?

Makes sense. Should I increase the delay then so it doesnt double read? I only need a read of an object going through the beam for less than 0.4 seconds.

Suggest you sample the sensor every now and then (example, every 50ms).

Any blocking delay(xxx) is not needed.

See post 6

I am already using tone in my code

You need to use tone( pinno,38000) and noTone(pinno) to turn the LEDs on/off

Help :slight_smile: Youve helped me on a previous project before just FYI. I do appreciate it

For beambreak you should use a TSSPxxxx sensor, not a TSOPxxxx.
TSSP are designed for continuous IR, the TSOP for intermittend (remote control) IR.
Has to do the the chip's internal AGC (Automatic Gain Control).

What is the TX/RX distance, and environmental (light) conditions.
What is the IR LED current (CL resistor value).
Post a picture ar drawing of your setup, with dimensions.
Leo..

Interestingly, although an (old) member of the TSOP range, the TSOP4038, which the OP is using, is described as a light barrier IR receiver and, if a genuine part, should be suitable here : https://www.vishay.com/docs/81926/tsop4038.pdf
However, it should be send bursts of the 38kHz carrier, not a continuous carrier. The data sheet shows a test signal of 600us carrier on, 600us carrier off for a minimum duration of 10 bursts. Newer TSOP device specify also a maximum duration and a mandatory pause to avoid saturating the device.

Doesn't the use of digitalWrite end any action of tone run in setup?

Wuth micros timing, one function at the end of void loop could change every other flicker-rate interval to OFF.

Another thing that can be done is to put a phototransistor at the back end of a tube with flat black inside so no light but "the beam" aka any source either bigger than the tube view or on a dark background that big.
If you arrange conditions like that, you can use "beams" that can't be detected across bright sunshine without blocking.

Ever look through a telescope or paper tube? A lit spot on a wall can be my beam.

I thought it would, until I made a simple sketch to check - It DOESN'T.

it specifically needs a noTone() command to stop the tone being generated.

1 Like

It is picking up the signal really accurately.

Its just continuously reading the broken beam, and therefore continuing to report the beam is broken. I want it just to read it once when it is broken, regardless of how long the object is breaking the beam for.

I had a similar project (which Larry helped with) and it did just read only once. Can't really figure out how to replicate that on this one

Does that mean detect the state but only report change/transition?

Like compare each read to the one before for not being the same?

if last == now there was no change

You could probably use your phone camera to verify the LED1 really goes LOW when the beam is broken.