Counting number of RISING edge pulse in a given time interval

Hi, I'm absolutely new to Arduino programming and all but i've been messing around with it for awhile now so most of the basic arduino functions, im able to understand and use. Currently, I wan to able to count the number of pulses in a given time interval(Let say 1sec), at the same time I also want to ensure that this time interval I can change it as i wish.

I tried using attachinterrupt(pin,ISR,RISING) to increase the count every time it detects a RISING pulse, however i realise that this doesn't allow me to select the gating/time interval as I wish.

Is there any way i can work with without it being too complicated? I would like to keep it as simple as possible. Thanks!

It will be easier to help if you post your program.

How many pulses are you expecting in a second?

Have a look at how millis() is used to manage timing without blocking in Several things at a time. If you need more precision the same technique works with micros().

...R

Robin2:
It will be easier to help if you post your program.

unsigned long period,periodHI,periodLO,gatinginterval;
volatile long int pulsecount = 0;

int specialpin = 9;
int strobepin = 6;

int count = 0;
float frequency,frequency1,radar_speed;
float ave_radar_speed;


unsigned period_array[200];

void setup() 
{
  // put your setup code here, to run once:
  Serial.begin (9600);
    
      pinMode(strobepin,INPUT);
      pinMode(specialpin,INPUT);
}

void loop() 
{
  // put your main code here, to run repeatedly:
  interrupts();
  
  while(digitalRead(specialpin) != 0); //loop and do nothing, wait for pulse back to 0 to start reading
  
  attachInterrupt(digitalPinToInterrupt(strobepin),pulseISR,RISING); //My attempt to use attachinterrupt to count the number of pulse in the time interval
  delay(gatinginterval);
  detachInterrupt(digitalPinToInterrupt(strobepin);

  do   
  {
    
    periodLO = pulseIn(strobepin, LOW);
    periodHI = pulseIn(strobepin, HIGH);
    
    if( (periodLO == 0) || (periodHI ==0) ) 
      Serial.println("Error");
      
    period = periodHI + periodLO;
    period_array[count++] = period;

   }while(digitalRead(specialpin) == 0);
    



    for (i=0,ave_radar_speed=0;i<count;i++)
    {
      period = period_array[i];
      frequency = (1.0/period);
      frequency1 = 1000000.0 * frequency; 
      radar_speed = (frequency1)/4.82;     
      ave_radar_speed += radar_speed;
  
   
    }
  Serial.print("Total count is ");
  Serial.print(count);
  Serial.print(" ");
  Serial.print("Total speed is ");
  Serial.print(constrain(ave_radar_speed/count,0.0,99.0));
  Serial.print(" ");
  Serial.print("km/hr");
  Serial.println("");

 
  
  count = 0;
  gatinginterval = pulseIn(specialpin,LOW); //This pin is connected to a variable resistor on a separate PCB which adjust my gating/time interval

}

void pulseISR()
{
  pulsecount++;
}

You don't want to mix pulseIn and attachInterrupt on the same pin.

You could use something like this.

void loop() {
    static unsigned long lastPeriodMs = 0 ;
    if (millis() - lastPeriodMs > gatinginterval ) {   // gatinginterval in mS
         Serial.print( "pulses received in gatinginterval = " ;
         Serial.print( pulsecount ) ;
         pulsecount = 0 ;  // should be volatile
         lastPeriodMs = millis() ;
    }

}

Are you attempting to set gatinginterval by an analogRead() operation on a potential divider ?

Imgur

So what i'm actually trying to do is, to count the number of pulses that occur in that time interval. This gating interval can be adjusted with a variable resistor that is connected on a separate PCB board where it is wired to the digital pin on the Arduino UNO for the measurement of the timing interval.

I suppose this actually makes sense and i can try doing this :confused:

6v6gt:

void loop() {

static unsigned long lastPeriodMs = 0 ;
   if (millis() - lastPeriodMs > gatinginterval ) {   // gatinginterval in mS
        Serial.print( "pulses received in gatinginterval = " ;
        Serial.print( pulsecount ) ;
        pulsecount = 0 ;  // should be volatile
        lastPeriodMs = millis() ;
   }

}

There are 3 hardware timers/counters in Arduino Uno.
TC0 is used for millis(), TC2 cannot be clocked externaly while using external main clock but TC1 is free to use and very suitable for this job.
Look into Datasheet or some internet guides how to use it, it should be quite easy.

I would attachInterrupt() in setup() and leave it attached. I would create pulseCount as unsigned long and I would never reset it in my code - eventually it will rollover, but that won't cause a problem

Then I would use code pretty much like @6v6gt has suggested

if (millis() - lastPeriodMs > gatinginterval ) {   // gatinginterval in mS
         previousPulseCount = latestPulseCount; // save the previous value
         noInterrupts();
            latestPulseCount = pulseCount;  // take a copy of the current value while interrupts are off
         interrupts();
         Serial.print( "pulses received in gatinginterval = " ;
         Serial.print( latestPulseCount - previousPulseCount );
         lastPeriodMs += gatinginterval;
 }

Note that it is essential to pause the interrupts while reading any value that is bigger than a single byte to prevent the possibility that the value is updated by the ISR while you are reading it.

...R

Ah yes. Much more elegant. The only slight improvement I would suggest is moving the statement:

previousPulseCount = latestPulseCount; // save the previous value

somewhere after:

Serial.print( latestPulseCount - previousPulseCount );

So the user sees values other that 0 on the serial console.

6v6gt:
Ah yes. Much more elegant. The only slight improvement I would suggest is moving the statement:

....

So the user sees values other that 0 on the serial console.

I don't understand.

...R

Elegant? I consider counting events via ISR quite crude. It is slow, may miss pulses easily etc. It has some uses but in general using (internal) hardware counter is beter. If you don't need PWM on pins 9 and 10 (you can still use those pins, you just cannot analogWrite them) this code:

TCCR1A=0; //disable previous PWM settings
TCCR1B=(1<<CS12)|(1<<CS11)|(1<<CS10); //set external clock on rising edge

will setup Timer/Counter 1 to be externaly clocked by rising edge on pin 5 (another PWM pin!). In 16 bit register TCNT1 there is current value of the counter. It can be written and read without need of disabling interrupts, it counts even in Idle sleep mode without need to wake up.

Robin2:
I don't understand.

...R

I looked too quickly at your logic and I am now sure that it will work as intended. Sorry for the false alarm.

Id partially fully unload this from software and use the Timers/Counters.

You could use the 16bit counter for accurate timing I guess...with an iterrupt on MAX that triggers an ISR to take the counter's value and assign it to a global variable...then resetting the counter to 0 ready for the next interrupt.

Then in main() you can just poll the global variable at your leisure.

6v6gt:
I looked too quickly at your logic and I am now sure that it will work as intended. Sorry for the false alarm.

No problem. I do that all the time :slight_smile:

...R

Hey all, thanks for helping me out on this. But for some reason, when i tested out the program, it keeps giving me an output "ovf". I didnt connect anything to pin6 for it to receive any pulses thus theoretically it should be giving me output of 0 instead of ovf or 99.

unsigned long gatinginterval;
unsigned long int pulseCount = 0,previousPulseCount = 0, latestPulseCount = 0, savedPulseCount = 0;
static unsigned long lastPeriodMs = 0 ;
float frequency,frequency1,radar_speed;

int specialpin = 9;
int strobepin = 6;

void setup() 
{
  // put your setup code here, to run once:
  Serial.begin (9600);
      attachInterrupt(digitalPinToInterrupt(strobepin),pulseISR,RISING); 
      pinMode(strobepin,INPUT);
      pinMode(specialpin,INPUT);
}

void loop() 
{
  // put your main code here, to run repeatedly:
  interrupts();
  
  while(digitalRead(specialpin) != 0); //loop and do nothing, wait for pulse back to 0 to start reading
  

 
    if (millis() - lastPeriodMs > gatinginterval ) {   // gatinginterval in mS
         
         previousPulseCount = latestPulseCount; // save the previous value
         noInterrupts();
            latestPulseCount = pulseCount;  // take a copy of the current value while interrupts are off
         interrupts();
         savedPulseCount = latestPulseCount - previousPulseCount;
         lastPeriodMs += gatinginterval;
    } else {
      return;
    }


    frequency = (savedPulseCount / gatinginterval);
    frequency1 = 1000000.0 * frequency;
    radar_speed = (frequency1) / 4.82;
    Serial.print("The speed is ");
    Serial.print(constrain(radar_speed,0.0,99.0));
    Serial.print(" ");
    Serial.print("km/hr");
    Serial.println("");
 
   
    gatinginterval = pulseIn(specialpin,LOW); //This pin is connected to a variable resistor on a separate PCB which adjust my gating/time interval

}

void pulseISR()
{
  pulseCount++;
}

Print also the value of gatinginterval to see if it is as you expect. It should be a value in units of one millisecond. A division by zero can cause an overflow.

Variables modified in ISR must be declared as volatile.

What value are you getting for savedPulseCount ?

What is the purpose of the line while(digitalRead(specialpin) != 0);? If it is intended to halt everything and only start the count when specialpin is triggered then I don't think the rest of your code will work because you are not initiating anything when the trigger occurs. It's a bit like timing the end of a race without timing the start.

As I'm not sure what you really want to do I won't say any more.

...R