Counting PulseIn

Hi everyone,

I've just started working with the Arduino today. Having a blast, but a little stuck and can't find a solution to this small issue I am having. Hope you can help point out where I am going wrong...

My current setup is 2 Arduino's. One is a Duemilanove, which I have successfully set up to send a pulse from pin 2, at 140Hz. Pin 2 output is going into Pin 2 into my second Arduino, the Nano.

The following code is counting the Hz of the pulse input on Pin 2.

int pinTachoInHz = 2; // D2 for Tacho Input - Measuring the Hz
int intTachoInHz = 0;
long intTachoInHz_Millis = 0;

void setup() {
  // Configure serial output
  Serial.begin(9600);
  
  //Configure pin modes
  pinMode(pinTachoInHz, INPUT);
  digitalWrite(pinTachoInHz, HIGH);  // Turn on pullup resistor
}

void loop(){
  MeasureTachoInHz();
  delay(500);
  }

void MeasureTachoInHz()
{  
  // Reset the count
  intTachoInHz = 0;
  // Reset the counter to 'now'
  intTachoInHz_Millis = millis();
    
  Serial.println("FunctionStart");
  
  // Loop for 1/4 of a second
  while (millis() < (intTachoInHz_Millis + 250))
  {
   Serial.println("Loop");
       
   // Everytime the pulse on the Tacho pin is HIGH, increment the counter
   if (pulseIn(pinTachoInHz,HIGH,1) != 0)
     {
       intTachoInHz++;
     }
   }
  
  if (intTachoInHz != 0)
  {
    // 0.975 = Adjust the count to match the multimeter
    intTachoInHz = ((intTachoInHz * 0.98) * 4);
  }
  Serial.println(intTachoInHz);
}

Essentially, this is working. But my problem is this, as soon as I disconnect the wire from input Pin 2 on the Nano, the code seems to hang where it loops for 1/4 of a second. So I put in a timeout on the pulseIn command on 1 microsecond - didn't help/hurt.

If I reset the Nano with the Pin 2 input wire disconnected, this is the output I get:
FunctionStart
Loop

I'd expect to receive:
FunctionStart
Loop
0
Loop
0
Loop
0

...250ms later

FunctionStart
Loop
0
Loop
0
Loop
0

etc.

Hope you can spare a sec to give me your thoughts...thanks!

Cheers,
Scott :slight_smile:

Use attachInterrupt instead of pulseIn http://www.arduino.cc/en/Reference/AttachInterrupt

You can increment your count in the interrupt handler , perhaps something like this (untested) code. You would need a little more code to disable and re-enable interrupts if TachoInHz count can be greater than 255 in your timing code in loop ( i.e greater than 1000hz if your delay time is 1/4 second)

int pinTachoInHz = 2; // D2 for Tacho Input - Measuring the Hz
byte TachoInHz = 0;  // declare this as a byte if the count is always less than 255
                        // so you don't have to disable interrupts when using in loop
long intTachoInHz_Millis = 0;

void setup() {
  // Configure serial output
  Serial.begin(9600);
  
  //Configure pin modes
  pinMode(pinTachoInHz, INPUT);
  digitalWrite(pinTachoInHz, HIGH);  // Turn on pullup resistor
  attachInterrupt(0, count, HIGH); // call count when pin 2 goes high
}

void loop(){
   TachoInHz= 0;
   delay(250); //wait 1/4 second
   byte tachoCount = TachoInHz;  // get a snapshot of the count
   float actualSpeed = tachoCount * 0.98 * 4; 
   Serial.print(int(actualSpeed));    
}

void count(){
   TachoInHz++;
}

FYI, you can avoid floating point in the above by using the following code:
long actualSpeed = (tachoCount * 98L) / 25;
Serial.print(actualSpeed);

Thanks for the response Mem.

Since my post I had discovered that I needed to have a resistor to ground to drop the input pin back to LOW. This actually resolved my never-ending pulseIn (even thought I was passing a timeout value to the function, which doesn't make any sense). I'm not an electronics whiz by any means, this is a bit of a steep learning curve!

Love the idea of using an interrupt, I'll have to look up the documentation in the Arduino Reference pages. I'm wondering what will happen with the rest of the inputs I need to read (mostly analog), given that this pulse input will actually be constant (this is from the tacho/RPMs of a boat engine). The frequency is likely to be between 100-300Hz.

What I wanted to do was take a 250 millisecond sample, so it didn't slow up the rest of the readings. It'd be nice to get at least 2 samples over serial per second for all 8 inputs (which will be read by a Dot Net application) for data logging etc. The analog inputs don't need any sampling, just one single read per loop, because the fluctuations in value will be very slow. They are like oil and water pressure/temperature etc.

At any rate, I'll do some research and give your code a whirl on Monday morning (this project is work related, I try not to work at home, too much!). Thanks again.

pulseIn(xx, HIGH) waits for a low to high transition to resume. That's why your code hangs in the if (pulseIn(pinTachoInHz,HIGH,1) != 0) statement

Even with a timeout specified? According to the documentation, this makes the function end prior to the pulse ending?

You're right but what's the behavior of pulseIn() if you disconnect the input while the pin is high and the function waiting for the high to low transition to resume?

That's a good question. Personally, as I'm very to new to Arduino and microcontrollers in general...I'm not really sure but I'm willing to take a guess! ::slight_smile:

According to this page: http://arduino.cc/en/Reference/PulseIn, if you disconnected an input while the pin is high and the pin remains high, then clearly the pulseIn function will continue to count the pulse up to the 3 minute mark.

After that, I'm not sure if the function times out and will return 3 minutes in microseconds or if it just hangs waiting for the low. Seems ridiculous that they wouldn't have a loop there ensuring after 3 minutes it times out anyway (why is there a 3 second limit when an unsigned long count technically increment about 71 minutes worth of microseconds?) - mind you they say "will probably show errors in longer pulses", so who knows.

Logically, I'd say that you'd have to have a pull-down resistor to ensure the input returned to low when the input disappeared physically and/or electrically. Personally that makes sense when I think about it, but practically this may not be the way to go.

This is based on zero experience and what little information I found (and possibly misinterpreted!) at Wikipedia: Pull-up resistor - Wikipedia

You probably know the answer and wanted me to think about this so I could learn something. What I will do on Monday though is try this out and I'll have an answer, of some description!

Cheers,
Scott

:stuck_out_tongue:

Well, at the moment i wrote my preceeding answer I had no idea of the answer. It was only deduction from the reference doc.
But since that time I have read the source of pulseIn() in wiring_pulse.c. Here is the interesting part.

      // wait for the pulse to start
      while ((*portInputRegister(port) & bit) != stateMask)
            if (numloops++ == maxloops)
                  return 0;
      
      // wait for the pulse to stop
      while ((*portInputRegister(port) & bit) == stateMask)
            width++;

As you can see in the code, there is only an out of time limit in the first while (the one waitings for the leading pulse). The second while loop only resumes on the trailing pulse so can be an infinite loop.

Wow, great thinking looking at their code. I didn't realise we had access to it...then again, it's open source, right?! :wink:

That's actually pretty lame, they could at least exit the function or return when the 'width' variable hits its limit (is that actually 4,294,967,295 with an Arduino?) and they should also have another parameter for the function so you can have a optional timeout for the pulse width in addition to the pulse 'start'.

Thanks for the feedback, I've definitely learned something here. Woo!