Multiple pulses per pass through with IR pulse meter

I am using a velleman vma347 IR sensor for the purpose of obtaining the speed of a DC motor. When I had connected and programmed the sensor, the rpm seemed to be very high. I then wrote a program to see what comes in (see below) and per pass I get several pulses 3,4,5 depend from time to time, every pass i wait some time. The connection in +5V DC, GND and signal on pin 2. Does anyone know why this is and how I can fix this?

serial monitor:
afbeelding

Program:

const int sensorPin = 2;   
volatile int pulseCount = 0; 
volatile unsigned long lastTime = 0;  
volatile int rpm = 0;       

void setup() {
  Serial.begin(9600);  
  attachInterrupt(digitalPinToInterrupt(sensorPin), countPulse, RISING); 
}

void loop() {

  if (millis() - lastTime >= 1000) {
    rpm = pulseCount;
    
    Serial.print(rpm);
    Serial.println(" Pulses");
 
    pulseCount = 0;
        
    lastTime = millis(); 
  }

}

void countPulse() {
  pulseCount = pulseCount+1; 
}
const int sensorPin = 2;
volatile int pulseCount = 0;
unsigned long lastTime = 0;

void setup() {
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(sensorPin), countPulse, RISING);
}

void loop() {
  if (millis() - lastTime >= 1000) {
    Serial.print(pulseCount);
    Serial.println(" Pulses");
    pulseCount = 0;
    lastTime += 1000;
  }
}

void countPulse() {
  pulseCount = pulseCount + 1;
}

or better

const int sensorPin = 2;
volatile int pulseCount = 0;
unsigned long lastTime = 0;

void setup() {
  attachInterrupt(digitalPinToInterrupt(sensorPin), countPulse, RISING);
  delay(1000);
  detachInterrupt(digitalPinToInterrupt(sensorPin));
  Serial.begin(115200);
  Serial.print(pulseCount);
  Serial.println(" Pulses");
}

void loop() {}

void countPulse() {
  pulseCount = pulseCount + 1;
}

Is pin 2 connected to the sensor DO ouput?

Something like this would work better for a noisy input on rising (not falling). Your code updated ...

const int sensorPin = 2;
const unsigned long riseTime = 250; // us
const unsigned long refreshPeriod = 1000; // ms

volatile unsigned long pulseCount = 0;
volatile unsigned long thisTime = 0; // us
volatile unsigned long lastTime = 0; // us
unsigned long lastRefresh = 0; // ms
volatile int rpm = 0;

void setup() {
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(sensorPin), countPulse, RISING);
}

void loop() {

  if (millis() - lastRefresh >= refreshPeriod) {
    lastRefresh = millis();

    noInterrupts();
    rpm = pulseCount;
    pulseCount = 0;
    interrupts();

    Serial.print(rpm);
    Serial.println(" Pulses");
  }
}

void countPulse() {
  thisTime = micros();
  if (thisTime - lastTime > riseTime) {
    lastTime = thisTime;
    pulseCount = pulseCount + 1;
  }
}

Same result.

afbeelding

Code does compile but does not run anything.

Yes it is.

this code works but counts 2x per passage so I guess on a positive and negative flank? When I hold an object between IR connection, it gives 1 pulse. When I remove this I get back 1 pulse.

Many of the low cost hobby sensors have comparators based on the LM393 without any hysteresis feedback, and it is not uncommon to experience multiple interrupts/noise troubles with these basic lm393 comparator modules.

Performance is often improved with a cap between D0 and ground. That solution and other possible circuit mods for hysteresis improved response are discussed here

https://forum.arduino.cc/index.php?topic=342650.0

A software approach for noisy transitions (rising or falling) input using CHANGE interrupt mode. This approach waits for stability in the signal while still using the initial transition for calculations. Also works for a wide range in duty cycle with the input ...

const uint8_t inputPin = 2;
const uint16_t stablePeriod = 200; //us
const uint16_t printPeriod = 100;  // ms

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(printPeriod)) {
    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, 0);
      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;
}

What are you using to break the IR beam and produce pulses? A slotted wheel or similar? How many slots / pulses per revolution? What RPM range? Post a picture.

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