Incrementing every other pulses

Hi - I have an optical sensor detecting pulses in a machine. It's a very precise Keyence amplifier with fiber optic laser.

The code I currently have detects every pulse and prints them to serial as they come.

I would like to be able to print a number every time the sensor reads 4 pulses.

Example: sensor gets pulses 1,2,3,4 then prints "1", reads 5,6,7,8 then prints "2" etc..

Any help is appreciated, I'm a novice - this is the code I'm using to detect single pulses:

const int input = 23;
int pulse = 0; 
int var = 0;

void setup(){
pinMode(input, INPUT_PULLUP);

Serial.begin(9600);
Serial.println("No pulses yet...");
}

void loop(){
if(digitalRead(input) > var)
{
var = 1;
pulse++;

Serial.print(pulse);
Serial.print(" pulse");

Serial.println(" detected.");
}

if(digitalRead(input) == 0) {var = 0;}

delay(1);
}

Before getting any further, please define the length of your "pulse". If it is longer than the time for your loop to execute, you will count more than once because the read will still be high.
Paul

Well the speed required for standard mode is 96 pulses per second. slow mode is 72 pulses per second. The sensor def can output faster than that but not sure Arduino can keep up.. I also have Teensy which is faster maybe that could help?

That is fine, but does not tell us HOW LONG each pulse lasts.
Paul

Not sure how I could get that value, sorry about that - I did plug it in a cheapo digital oscciloscope and I see the pulses but not sure how to read for how long each pulses are.

see pic

A few changes, not tested.

const byte input = 23;
unsigned long pulses = 0; 
byte pinState = 0;
byte lastPinState = 0;

void setup()
{
  pinMode(input, INPUT_PULLUP);

  Serial.begin(115200); // really, 9600 is wayyyy slow
  Serial.println("No pulses yet...");
}

void loop()
{
  pinState = digitalRead(input);
  if( pinState != lastPinState )
  {
    if ( lastPinState == 0 )
    {
      pulse++;
      Serial.print("pulse ");
      Serial.print(pulse);
      Serial.println(" start detected.");
    }
    lastPinState = pinState;
  }
}

The screen tells me each horizontal box is 10ms. I estimate one pulse is 17.5millisesonds in width, which matches the PW, pulse width, on the scope of 0,017seconds.
The conclusion is your program will read one pulse as being high for several passes through loop(). And will give a false count, right away.
The only nicely defined change on your pulse is when it goes low. May I suggest you investigate the use of interrupts on some pin set to read "low" and count one for each interrupt. Time for you to look at the many examples of using interrupts on your Arduino.
Paul

Hi @marvguitar,

in order to have good help, it is very important to provide good information to those who help.
Which arduino are you using in this sketch? Apparently it's a mega Arduino.
What type of sensor is connected to pin (23?)?
If possible post a schematic of your project.

RV mineirin

1 Like

With crappy code you read 1 signal as many but when you only count every other transition then there's no need to use an interrupt.

void loop()
{
  pinState = digitalRead(input);
  if( pinState != lastPinState )
  {
    if ( lastPinState == 0 )
    {
      pulse++;
      Serial.print("pulse ");
      Serial.print(pulse);
      Serial.println(" start detected.");
    }
    lastPinState = pinState;
  }
}

You can make it simple by using the library

#include <ezButton.h>

ezButton button(7);  // create ezButton object that attach to pin 7;
unsigned long lastCount = 0

void setup() {
  Serial.begin(9600);
  button.setCountMode(COUNT_FALLING);
}

void loop() {
  button.loop(); // MUST call the loop() function first

  unsigned long count = button.getCount();
  if (lastCount != count) {
    Serial.println(count / 4);
    lastCount = count;
  }
}

See more on Arduino Button Count

Just to answer your question the simplest way is to divide the pulse detected by 4 and save it on an int. This will automatically truncate the decimal value.

const int input = 23;
int pulse = 0;
int var = 0;

void setup() {
  pinMode(input, INPUT_PULLUP);

  Serial.begin(9600);
  Serial.println("No pulses yet...");
}

void loop() {
  if (digitalRead(input) > var)
  {
    var = 1;
    pulse++;

//MOD GERRY
    int nibbleCount = pulse / 4;
    Serial.print(nibbleCount);
    Serial.print(" nibbles ");

    Serial.print(pulse);
    Serial.print(" pulse");

    Serial.println(" detected.");
  }

  if (digitalRead(input) == 0) {
    var = 0;
  }

  delay(1);
}

1 Like

I'm using Arduino Mega but I also have Teensy 4.1 which is faster, maybe better for this but for now I'm on Arduino Mega.

Sensor is fiber optic laser (Keyence FU-20) unit connected to sensor amplifier (Keyence FS-N41P)

Here's a schematic of the sensor setup.

Actually, any of the slow Arduino boards would be fast enough for your project.
Paul

2 Likes

Even at 8MHz an AVR is way ahead of that signal.

1 Like

I made a version of the code using an interrupt. Would this work better like this?

const int input = 23;
int pulse = 0; 
int var = 0;

void setup() {
  pinMode(21, INPUT_PULLDOWN);
  attachInterrupt(digitalPinToInterrupt(input), count, LOW);
}



void count() {
  if(digitalRead(input) > var)
{
var = 1;
pulse++;

Serial.print(pulse);
Serial.print(" pulse");

Serial.println(" detected.");
}

if(digitalRead(input) == 0) {var = 0;}

delay(1);
}




void loop() {
  
}

Well, no. Interrupting on low would be CONTINUOUS as long as low was true. What you want to use is: FALLING for when the pin goes from high to low.

Paul

1 Like

I modified your program. So basically you want to count the number of high pulses. Maybe take a look at the code.

const int input = 23;
int pulse = 0;

void setup() {
  Serial.begin(9600);
  pinMode(input, INPUT_PULLDOWN);
  attachInterrupt(digitalPinToInterrupt(input), count, RISING);
  //attachInterrupt(digitalPinToInterrupt(input), count, FALLING);
}

void count() {
  pulse++;
}

void loop() {
  Serial.print("Pulse Counted: ");
  Serial.println(pulse);
  int nibbleCount = pulse / 4;
  Serial.print(nibbleCount);
  Serial.println(" nibbles.");
  Serial.println("Reset Counter waiting for pulses");
  Serial.println("");
  pulse = 0;
  delay(3000);
}
1 Like

I got the code working well now but the "delay" is causing trouble in my project.

..in this section:

if(digitalRead(sensor) == 0) {
    var = 0;}
delay(1);

I think I should be using Millis but not sure how to get there.

This is the latest working code, how could I alter it to use millis instead of delay?


const int sensor = 23;
int perf = 0; 
int var = 0;
int frame_counting = 0;

void setup() {
   Serial.begin(115200);
    attachInterrupt(digitalPinToInterrupt(sensor), count, FALLING);

}

void count() {
  if(digitalRead(sensor) > var)
{
var = 1;
perf++;
if((perf % 4) == 0){
  frame_counting++;
Serial.print(frame_counting);
Serial.print(" frame");
Serial.println(" detected.");
}

}

if(digitalRead(sensor) == 0) {
    var = 0;}
delay(1);

}


void loop() {
 
}

Where do you ever call this function?
Paul

Right now - nowhere, I just use the serial monitor to display "frame_counting"

Serial.print(frame_counting);