Pages: [1]   Go Down
Author Topic: pulseIn timeout not working  (Read 1519 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 77
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello!

I'm trying to use the pulseIn() function to read from a parallax ping() sensor.  It reads the pulse length from the sensor great, but the optional timeout part of it is not working.

My ping outputs a pulse length of about 9000 when I point it at empty space.  I'd like to set pulseIn to give up at around 2600, which would give me a speed boost because I wouldn't have to wait the extra 6.4mS for the ping to time out.

Here is the test code:
Code:

long pulselength = 0;
//float inches = 0;
int pulsepin = 2;


void setup() {
  

Serial.begin(57600);
  
  
} //end setup()


void loop() {
  
pinMode(pulsepin, OUTPUT);
digitalWrite(pulsepin, LOW);
delayMicroseconds(2);
digitalWrite(pulsepin, HIGH);  
delayMicroseconds(5);
digitalWrite(pulsepin, LOW);
  
pinMode(pulsepin, INPUT);
pulselength = pulseIn(pulsepin, HIGH, 2600);

Serial.println(pulselength);

} //end loop


Note: even if you don't have a ping, you can load this up and verify that it is returning higher numbers than 9000, instead of the expected 0.

Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17301
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

To test out your code without a ping wired in you might try wiring a pull down resistor to keep the digital pin from 'floating', as noise my be the cause of not detecting the time-out period.


Lefty

Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 77
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I tried replacing the ping with a resistor, and sure enough it started returning 0s.  I'm not sure why-- you mentioned 'noise' but I don't see how this would affect the operation of the timer.  If the pin was bouncing down to LOW, I would be seeing erroneously short pulses, but how could it affect the timeout variable?

I guess that I can just hack something together with a pair of while() loops and the micros() function, but it would be nice if the timeout worked, other than that pulseIn is very accurate and useful.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 77
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's the code from wiring_pulse.c
Code:
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
 * or LOW, the type of pulse to measure.  Works on pulses from 2-3 microseconds
 * to 3 minutes in length, but must be called at least a few dozen microseconds
 * before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
      // cache the port and bit of the pin in order to speed up the
      // pulse width measuring loop and achieve finer resolution.  calling
      // digitalRead() instead yields much coarser resolution.
      uint8_t bit = digitalPinToBitMask(pin);
      uint8_t port = digitalPinToPort(pin);
      uint8_t stateMask = (state ? bit : 0);
      unsigned long width = 0; // keep initialization out of time critical area
      
      // convert the timeout from microseconds to a number of times through
      // the initial loop; it takes 16 clock cycles per iteration.
      unsigned long numloops = 0;
      unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
      
      // wait for any previous pulse to end
      while ((*portInputRegister(port) & bit) == stateMask)
            if (numloops++ == maxloops)
                  return 0;
      
      // 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++;

      // convert the reading to microseconds. The loop has been determined
      // to be 10 clock cycles long and have about 16 clocks between the edge
      // and the start of the loop. There will be some error introduced by
      // the interrupt handlers.
      return clockCyclesToMicroseconds(width * 10 + 16);
}

I took a look at this, and then realized that I probably hadn't read the doc carefully enough, because it will return 0 if a pulse does not start before the timeout, but will not return 0 if the pulse does not end before the timeout.  Sure enough, from:
http://www.arduino.cc/en/Reference/PulseIn
"Gives up and returns 0 if no pulse starts within a specified time out."

So that's all cleared up.

Now, adding the ability to return 0 if the pulse does not end before the timeout is easy enough:
Code:
     // wait for the pulse to stop
      while ((*portInputRegister(port) & bit) == stateMask)
            if (numloops++ == maxloops)
                  return 0;
                width++;

but how do I adjust the width-to-microseconds conversion so that it will be accurate with the new while loop time?  I understand you can look at the assembly code and then look up how many clock cycles each command takes, but I've never done it and I need some hand holding, if you don't mind.

thanks,
Max
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 29
turtle gum
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This might come a bit late, but did you finally figure out how to do that?
I have precisely the same problem: I want to limit the amount of time PING))) is waiting with timeout. How can I rewrite the pulseIn() function so that  the sensor gives up waiting for an echo after timeout's duration in microseconds?
« Last Edit: November 06, 2010, 10:03:34 am by hellsinki » Logged

Rome
Offline Offline
God Member
*****
Karma: 1
Posts: 989
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As far as I can understand:
- locate wiring_pulse.c file in your Arduino folder
- locate these lines:

Code:
     // wait for the pulse to stop
      while ((*portInputRegister(port) & bit) == stateMask)
            width++;
- change them in this way:

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


....leave your sketch unchanged, upload it, and it should work (not tested).
« Last Edit: December 07, 2010, 04:05:41 pm by jumpjack » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 220
Posts: 13846
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

think you need some brackets too otherwise width will only be incremented once smiley

Code:
// wait for the pulse to stop
      while ((*portInputRegister(port) & bit) == stateMask)
        {
            if (numloops++ == maxloops)
                  return 0;
                width++;
        }
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Rome
Offline Offline
God Member
*****
Karma: 1
Posts: 989
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That's right.

ohnoezitasploded, what the heck are you writing?!?   ;D   smiley-wink
Logged

Rome
Offline Offline
God Member
*****
Karma: 1
Posts: 989
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Some additional slight changes allow identifying invalid values returned by PulseIn function:

unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)

becomes

signed long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)

and

     // wait for any previous pulse to end
      while ((*portInputRegister(port) & bit) == stateMask)
            if (numloops++ == maxloops)
                  return 0;
      
      // 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++;

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



becomes:

     // wait for any previous pulse to end
      while ((*portInputRegister(port) & bit) == stateMask)
            if (numloops++ == maxloops)
                 return -1;
      
      // wait for the pulse to start
      while ((*portInputRegister(port) & bit) != stateMask)
            if (numloops++ == maxloops)
                 return -2;
      
      // wait for the pulse to stop
//      while ((*portInputRegister(port) & bit) == stateMask)
//            width++;

// wait for the pulse to stop
      while ((*portInputRegister(port) & bit) == stateMask)
        {
            if (numloops++ == maxloops)
                 return -3;
                width++;
        }



But you'll also need to change two more files: wiring.h and WProgram.h, both containing
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)

which must be changed to

signed long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)

This way, at first running, PulseIn will return -2;  then, if your pulse-sensor starts running, a -3 will be returned as soon as it stops, and -1 will keep be returning as long as it remains stopped.

This was tested on a wind sensor connected to GND and Pin 2: it's a just a switch which gets closed and quickly reopened for each turn of a wheel.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 220
Posts: 13846
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I like the modification but the max value of PulseIn is shortened by a factor 2 is quite costly. So undecided... :-/
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Rome
Offline Offline
God Member
*****
Karma: 1
Posts: 989
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It's just an idea, you could also use 0xffff.ffff, 0xffff.fffe and 0xffff.fffd rather than -1, -2 and -3 .

edit:
using signed long, wouldn't 0xfff.ffff seconds be around 2.000.000.000 microseconds, i.e. 2000 seconds, i.e >0,5 hours?
« Last Edit: December 07, 2010, 05:50:34 pm by jumpjack » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 220
Posts: 13846
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That idea is better, all values starting with 0xFFFF.FFF- for error purpose => a simple & operation detects any errorflag.
« Last Edit: December 08, 2010, 03:29:02 am by robtillaart » Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Rome
Offline Offline
God Member
*****
Karma: 1
Posts: 989
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I guess we should use bit-indipendent codes (does it exist a name for this?!?  :-? ):
0xFFFF.FFF0
0xFFFF.FFF1
0xFFFF.FFF2
0xFFFF.FFF4
0xFFFF.FFF8

Anyway, from source comment:
Quote
Works on pulses from 2-3 microseconds to 3 minutes in length

3 minutes are 180.000.000 us, which is 0x0ABA.9500 , so we don't actually need an unsigned long, a signed one should be enough, and "-1", "-2" and "-3" are  quite more readable than 4294967284, 4294967288 and so on... (no need to convert to HEX for displaying).

Alternatively, we could keep using LONG type, and use first digit to represent if returned length is for high or low pulse, rather than specifying it in the second parameter.
E.G.:
500,000 us = 0x7A120 = 0x0007.A120
0x0007.A120 will mean "500,000 us up pulse",
0x1007.A120 will mean "500,000 us down pulse"

But it would be too complex for me to implement such a change...  smiley-sad
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 220
Posts: 13846
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
bit-indipendent codes (does it exist a name for this?!?
bit-flags?

Quote
But it would be too complex for me to implement such a change...  
You have almost finished the analysis of how you want it to behave including arguments, so you are closer to it than you think! Keep faith in yourself! smiley
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: [1]   Go Up
Jump to: