How to use NPN proximity sensor to give interrupt to arduino or AVR microcontroller?

In one of my project , I am thinking to use NPN proximity sensor. I need suggestion for best professional circuit diagram for interfacing Proximity Sensor with AVR microcontroller.

Problem Statement:
I bolt/NUT is connect to shaft of a slow motor (say 20 RMP speed), and when Metal NUT comes in front of Proximity Sensor , it will trigger interrupt and rotation of motor will stopped.

More Details : Motor is not ROTATING continuously , Motor is standing at some position and it will ROTATE ONCE ( 1 rotation) , after some given time say 12 minute and then it will come in contact with proximity sensor after 1 rotation through metal NUT and proximity sensor will stop the motor at exact desired location (for rough example say 60 degree) and so on.

  1. I am thinking to use a optocoupler to interface Sensor with microcontroller.

  2. Is it safe to trigger a interrupt through proximity sensor ? ( to stop motor)

As I saw lot of people facing issue when proximity sensor is used for interrupt.
Some people say NOISE or EMI trigger interrupt. ( for example Near by machines, or switching of contractors or Air conditioner )
What is the solution ?

  1. Suppose Interrupt get triggered due to NOISE and it goes into ISR.
    Can I Double check in ISR function, its due to NOISE or its actually due to Proximity sensor ?
    Can I use digitalRead() to double check proximity sensor status in ISR ?
    Is digitalRead() is allowed in ISR ?
    Inductive-Proximity-Sensor-10

The datasheet of the optcoupler PC817 says

maximum collector current 50 mA.
If you set a current of 20 mA to keep some distance to the maximum-rating
the resistor could be reduced to

5V / 0.020 A = 250 Ohm.

20mA is even save for the IO-pin if you would accidently configure as output-pin

Power-dissipation in the resistor
P = 5V * 0.020 A = 0.100 Watts safe even for small resistors (usually minimum 125 mW most of them 250 mW)

The lower the pullup-resistor the more insensitive the wire becomes against electromagnetic noise

same safety or unsafety as using the sensor outside an interrupt

20 RPM = 20 rotations per minute = one pulse every 3 seconds

You could add a low-pass-filter with a pretty high time-constant to reduce noise.

Yes for sure

If you describe your complete project an estimation about potential electromagnetic noise can be made and suggestions on how to protect against or filter away electromganetic noise.

As long as you do not use plasma-cutting with HF-ignition the electromagnetic noise protection will be pretty easy

Depending on your overall application it might be not nescessary to use an interrupt.
But instead it might be sufficient to have a fast running void loop() that checks for the proximity-signal and then it becomes easier to filter away noise just in software.

best regards Stefan

1 Like

I guess the sensor is something like this: https://www.mpja.com/download/32086hd.pdf
It looks like is switches on, that is pulls the black terminal low during the entire detection.

You can use digital read in an ISR but it probably does not help here.
As has already been pointed out, 20 RPM, that is 1 pulse every 3 seconds is very slow so there is no real justification for using an interrupt. You simply set a polling interval, say every 10ms, to check the sensor. If you are concerned about spurious pulses you can poll several times before you determine if the pulse is valid. In an ISR, you cannot block while waiting for a series of pulses.

Your interrupt signal would be normally high and there could be transition noise when falling or rising or both (as the Metal NUT passes in front of Proximity Sensor).

Here's an example that demonstrates using CHANGE interrupt mode for a very, very "noisy-transition" signal (not random noise).

  • I've set the Frequency to 0.33333 Hz, 90% duty, 5ms noise or "bounce" on both falling and on rising signal transition.

Here's what it looks like ...

In this Wokwi Example, you can see how many "bounces" occur by looking at how the "Samples" count on the Logic Analyzer jumps to a higher sample count on each transition ...

The code ...

/* 
Measuring a Noisy Signal using CHANGE Mode Interrupt
David Lloyd, May 2023.
*/

const uint8_t inputPin = 2;
const uint16_t stablePeriod = 5000;
uint32_t pulsePeriod, pulseWidth, t00, t11, t22;
volatile uint32_t us, stableUs, t0, t1, t2; // isr
uint8_t inputLevel;
bool ready;
float hz, duty, rpm;

// functions
void input_ISR();
bool timer(uint32_t ms);

void setup() {
  Serial.begin(115200);
  pinMode(inputPin, INPUT); //Interrupt
  attachInterrupt(digitalPinToInterrupt(inputPin), input_ISR, CHANGE);
}

void loop() {
  if (timer(50)) {
    if (ready) {
      noInterrupts();
      t22 = t2;
      t11 = t1;
      t00 = t0;
      t2 = 0;
      t1 = 0;
      t0 = 0;
      ready = false;
      interrupts();

      pulsePeriod = t22 - t00;
      pulseWidth = t11 - t00;
      duty = 100.0 * pulseWidth / pulsePeriod;
      hz = 1000000.0 / pulsePeriod;
      rpm = hz * 60.0;
      Serial.print("  Duty = ");
      Serial.print(duty, 0);
      Serial.print("  Hz = ");
      Serial.print(hz, 2);
      Serial.print("  RPM = ");
      Serial.print(rpm, 0);
      Serial.println();
    }
  }
}

void input_ISR() {
  us = micros();
  if (us - stableUs > stablePeriod) {
    inputLevel = digitalRead(inputPin);
    if (inputLevel == HIGH) {
      if (!t0 && !t1 && !t2) t0 = us;
      else {
        if (t0 && t1 && !t2) {
          t2 = us;
          ready = true;
        }
      }
    } else {
      if (t0 && !t1 && !t2) t1 = us;
    }
  }
  stableUs = us;
}

bool timer(uint32_t ms) {
  volatile uint32_t prevMs, now;
  now = millis();
  if ((now - prevMs) >= ms) {
    prevMs = now;
    return true;
  }
  return false;
}

Sir, As you told Collector Current chosen is 20mA , so R = 5V/0.20 A = 250 ohm.
Please correct me, if I am not wrong ...........From Datasheet:
When "Collector Current" is 20mA , "Collector Emitter" Voltage will be 2V.
So R = { (5 - 2 ) / 20mA } = 150 ohm

Similarly (Input side of optocoupler)
When "Forward Current" is 20mA
"Forward Voltage" = 1.2 V
R = (5 - 1.2 ) / 20mA = 190 ohm

which datasheet which diagram says these numbers?

If you supply the IR-diode with a current = 20 mA

The collector-Emitter-voltage or will be approx. 0,2V on full saturation for a current of 1 mA

The voltage-drop for 20 mA will be higher but I estimate not above 0,5V
Above 6 mA of LED-current the saturation-voltage drops down.

This means the real current will be
(5V - 0,5V) / 250 Ohms = 18 mA

Powerdissipation in the phototransistor
0.5V * 0,018A = 9 mW
In the situation of driving the LED with nominal current of 15 to 20 mA.

If your LED-current is too low
you get a big voltage-drop on the phototransistor and this can exceed the maximum of power-dissipation inside the phototransistor.

You should use a digitalmultimeter to measure the real numbers in prelimary tests.
That is what I always do with such components.

Adjusting the current limiting resistor on the LED-side to get a current in the range of 10 to 15 mA supplying the proximitity-sensor with that voltage that you are using in the real application.

then measuring voltage-drop across collector-emitter with reducing the pullup-resistor in steps or using a fixed resistor of 250 Ohms and in series a potentiometer.

best regards Stefan
Optocoupler-sharp-PC817A.PDF (92.3 KB)

What is the question you are asking here? Did you mean to ask if using an optocoupler is a good idea? From your description of the circuit given so far, I can see no reason to use an optocoupler. It would be a waste. Perhaps you have some reason in mind that you forgot to share with us?

It is safe. But it is not appropriate to use an interrupt. If the motor speed was 20,000 RPM, an interrupt might be appropriate. At 20 RPM, which is one revolution every 3 seconds, your code can simply use digitalRead() in loop().

Use a stronger pull-up resistor, like 1K. But 10K might also be ok. Test it.

No. To the arduino, noise looks just like a signal, HIGH or LOW. It may be possible for your code to detect if a signal is noise through use of timing. For example, testing if the pulse too short, or too soon following the previous pulse.

Yes, but there would be no point. If the ISR is triggered by the input signal changing from LOW to HIGH or HIGH to LOW, digitalRead() will only give the expected answer. As I described, timing would be a good way to detect noise.

But do you even know if noise will be a problem? Maybe you should not be concerned about noise until you know for sure it is a problem.

1 Like

Yes exactly I want to know using optocoupler is good idea or not ?

Some of the doubt in my mind , so I need clarification on these points given below.

As proximity sensor working voltage range is 6-36V. So I need two power supplies one 5V for Microcontroller and other for Proximity Sensor, which will be 12V.

  1. Output of proximity sensor will be 12V (BLACK WIRE), which can't be given directly to microcontroller GPIO pins.

  2. So I need to use "resistor voltage divider" network for output of sensor. ( Please correct me, output current of proximity sensor is High ( upto 200mA) , which might can damage microcontroller ?

  3. proximity sensor are inductive type , So back EMF can cause problem ??

  4. Due to these reason , I was thinking to use optocoupler.

What your suggestion , What is the best way to interface proximity sensor with microcontroller?

Second I was thinking to use interrupt , boz I am doing some other work in loop.

  1. polling of buttons.
  2. temperature reading through SPI.
  3. RTC
  4. displaying data on LCD
  5. two relays
  6. few delay() functions

Please Note: Motor is not ROTATING continuously , Motor is standing and it will ROTATE ONCE ( 1 rotation) , after given time say 10 minute and then it will come in contact with proximity sensor after 1 rotation through metal NUT and proximity sensor will stop the motor at exact desired location and so on.

In your application, using an opto and an interrupt is highly appropriate. At only 1 pulse per 3 seconds, its really nice to get an accurate result on each and every calculation. Thats just not going to happen without interrupts and other blocking functions or delays exist in your code. With the MCU running at 16 MHz, 1 pulse per 3 seconds is basically nothing. Oh, don't forget to enable the opto isolation feature of your 2-relay module, it that's what you're using.

I want to bring one point in front of you for more clearity.

Please Note: Motor is not ROTATING continuously , Motor is standing at some position and it will ROTATE ONCE ( 1 rotation) , after some given time say 10 minute and then it will come in contact with proximity sensor after 1 rotation through metal NUT and proximity sensor will stop the motor at exact desired location (for rough example 60 degree) and so on.

Correct.

200mA is the maximum current that the sensor can withstand. When connected to the voltage divider and Arduino input, the current will be very small. It will not damage the Arduino.

The internal circuit of the sensor will not allow any back EMF to reach the output.

Do not use delay(). Then interrupts will not be required. If you need to control timing of Arduino outputs, use millis(). Using delay() will cause your code to miss button presses.

The other functions you describe in your code will not cause a problem because they all execute quickly.

Thanx for suggestion: I am using mills() at many places , delay() function is used with "buttons pressed"...to take care of denounce effect of buttons.

Short delays for button debouncing should not be a problem. You can just poll the sensor.

1 Like

I want to bring one point in front of you for more clearity.
Yeah, but changing the first post puts the flow of questioning into chaos.

How is this possible if reaction (response) time is not an issue?
Will something break if there's overshoot in the motor position?
I'm now thinking using interrupts is even more important.

Yes exactly , motor should stop immediate as soon as Metal NUT BOLD come in front of proximity sensor. ( normally proximity sensor diameter is 20+mm)

  1. as you said overshooting of motor position can broke something.

As you said previously , 20rpm means microcontroller will get one pulse after 3 second. ( motor will start rotation from NUT and will stop at NUT BOLT after 3 second)

What about duration of pulse:
if proximity sensor diameter is 20mm, what will be duration of pulse?

I think an image of your setup would be very helpful.

How about using a limit switch?

What then ... it stays there indefinitely? Does the motor have reverse?

While within proximity of a metal object, the signal would remain low.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.