How to read a pulse train asynchronously

I have a simple (cooperative) multitasking system in place that runs through the tasks in my program. Each task is called until it yields back to the main loop where then another (next) task is called etc.

Now I want to create a task that reads the data stream out of an ultrasonic sensor. This sensor spews a pusle-train signal of max 50 millis. The amount of time the signal lasts is related to the distance of an object the sensor is detecting. Long pulse =far away, short pulse= close by.

The sample code reads this pulse-train by using the pulseIn() method. But that is a synchronous method that will wait for the end of the pulse and will possibly lock my processing for max 50 ms.

I am trying to figure out how to read this pusle-train signal in such a way that it will not block my other running tasks. I thought that perhaps using an interrupt that just counts periods would do the trick. But then I would also have to have something to know when the signal stopped (last updated time perhaps?). Then I could create a task that just deals with that information and comes up with the appropriate data for my program.

I would not mind to loose accuracy on the long distance sensing (long pulse) but shorter pulses must be very accurate. 50 micros represents 1 cm.

Are there any other ways of reading in a pulse-train with a resolution of 50 us asynchronously? I wouldn't mind a hardware solution either, perhaps using some counter chips?

Thanx.

Try this - http://rcarduino.blogspot.ae/2012/01/how-to-read-rc-receiver-with.html

Duane B rcarduino.blogspot.com

Thanx.

Your pulses are a lot further apart than the 50 us this sensor puts out. If I would trigger an interrupt on this signal it would call that function each 50 uSecs. That would probably put a dent in the processing of the normal program.

Meanwhile I've been looking for counting IC's but so far nothing that can measure a pulse and report its length over a serial bus...

Have a look at 'input capture' or turn the interrupt off as soon as you have a reading, process the reading and then turn interrupts back on

Duane B rcarduino.blogspot.com

Agree with DuaneB.

interrupts is the way to go for fast pulses. Instead of instantaneous processing of the pulse you might put the timing of the edges in an array for offline processing. (might need a MEGA for that)

Ok, I understand that it could be done with an ISR although I fear it might interrupt so often the normal code would suffer.

I was also interested if there were other ways of doing this for instance using some hardware/chip?

I need to interface a sensor and 2 encoders (also a pulse train although much slower) so if I could build something that would offload this task from my Arduino, I wouldn't mind doing that (assuming the chip is not overly expensive).

(Yes I'm building a robot car 8) )

Ok, I understand that it could be done with an ISR although I fear it might interrupt so often the normal code would suffer.

Not a problem if you do it correctly. Unfortunately the usual examples use pulseIn() In my view pulseIn() and delay() are evil for the very reason you give.

I use the HC-SR04 with hardware Interrupt 0 on the 328. The trick is to use the FALLING edge, then subtract out the leading dead time.

I have included my short test program and 2 oscilloscope traces to show what is happening. You can ignore the LED blink routine except to notice that it does not use delay()

The traces suggest that the dead time is 450usec. Calibration gives 600usec as more accurate perhaps due to Arduino overhead. I always use calibrations with sensors. Theoretical values are rarely accurate.

Joe

Ping_Int0.ino (2.57 KB)

[quote author=joe mcd link=topic=165317.msg1234179#msg1234179 date=1368056961] [..] The trick is to use the FALLING edge, then subtract out the leading dead time. [..][/quote]

What is the benefit of that? Not that it would matter for a pulse train on which edge you trigger...

Thanx.

The falling edge represents the Return time of the echo. We need this for the distance computation. We can subtract out the start time which is always the same.

Could this be simply done with a pin change interrupt that notes the millis() value on a rising edge and then subtract this from millis() on the falling edge and stores the result for the main thread to pick-up at leisure.

Could this be simply done with a pin change interrupt that notes the millis() value on a rising edge and then subtract this from millis() on the falling edge and stores the result for the main thread to pick-up at leisure.

Please use micros(). You need the higher resolution.

In principal a pin change interrupt can also work. Pin change is slower and may not be as precise. The important point is to avoid pulsein().

My code has an oversight. pingUsec and echoUsec should be declared volatile since they are changed in the interrupt routine.