0
Offline
Jr. Member
Karma: 0
Posts: 75
Arduino rocks
|
 |
« on: June 02, 2009, 11:51:22 pm » |
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: 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
Brattain Member
Karma: 279
Posts: 15314
Measurement changes behavior
|
 |
« Reply #1 on: June 03, 2009, 01:42:29 am » |
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
Jr. Member
Karma: 0
Posts: 75
Arduino rocks
|
 |
« Reply #2 on: June 03, 2009, 06:46:06 pm » |
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
Jr. Member
Karma: 0
Posts: 75
Arduino rocks
|
 |
« Reply #3 on: June 03, 2009, 07:39:48 pm » |
Here's the code from wiring_pulse.c /* 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: // 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
Newbie
Karma: 0
Posts: 29
turtle gum
|
 |
« Reply #4 on: November 06, 2010, 10:03:01 am » |
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
God Member
Karma: 1
Posts: 972
Arduino rocks
|
 |
« Reply #5 on: December 07, 2010, 04:04:27 pm » |
As far as I can understand: - locate wiring_pulse.c file in your Arduino folder - locate these lines: // wait for the pulse to stop while ((*portInputRegister(port) & bit) == stateMask) width++; - change them in this way: // 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
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 89
Posts: 9393
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #6 on: December 07, 2010, 04:18:38 pm » |
think you need some brackets too otherwise width will only be incremented once  // wait for the pulse to stop while ((*portInputRegister(port) & bit) == stateMask) { if (numloops++ == maxloops) return 0; width++; }
|
|
|
|
|
Logged
|
|
|
|
|
Rome
Offline
God Member
Karma: 1
Posts: 972
Arduino rocks
|
 |
« Reply #7 on: December 07, 2010, 04:21:59 pm » |
That's right. ohnoezitasploded, what the heck are you writing?!? ;D 
|
|
|
|
|
Logged
|
|
|
|
|
Rome
Offline
God Member
Karma: 1
Posts: 972
Arduino rocks
|
 |
« Reply #8 on: December 07, 2010, 05:28:45 pm » |
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
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 89
Posts: 9393
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #9 on: December 07, 2010, 05:32:40 pm » |
I like the modification but the max value of PulseIn is shortened by a factor 2 is quite costly. So undecided... :-/
|
|
|
|
|
Logged
|
|
|
|
|
Rome
Offline
God Member
Karma: 1
Posts: 972
Arduino rocks
|
 |
« Reply #10 on: December 07, 2010, 05:47:56 pm » |
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
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 89
Posts: 9393
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #11 on: December 08, 2010, 03:25:07 am » |
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
|
|
|
|
|
Rome
Offline
God Member
Karma: 1
Posts: 972
Arduino rocks
|
 |
« Reply #12 on: December 08, 2010, 05:18:50 am » |
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: 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... 
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 89
Posts: 9393
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #13 on: December 08, 2010, 08:16:10 am » |
bit-indipendent codes (does it exist a name for this?!? bit-flags? 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! 
|
|
|
|
|
Logged
|
|
|
|
|
|