I did some google search but it too often points to the "login or register"

My question is, how to read the microsecond result from directly accessing registers. One project I'm doing needs a bit or performance boost. I was doing while (micros()-current<wait) but it was not as accurately as I wanted. From the other end of the project, a fluctuation indicates the loop wanders about +- 12us, which is translating to +- 2mm distance measurement error. I wonder if using register can make this drop down. I have heard of the micros only returns multiple of 4us boundary too so will register access make its accuracy any better? Thanks!

BTW, I would be comfortable with inserting assembly code too if you tell me how to write the C syntax to include them.

What range of time are you needing to measure? A simpler approach might just be to configure a timer and use the timer values. Input capture is another cool option if it fits whatever it is you're trying to do.

What range of time are you needing to measure? A simpler approach might just be to configure a timer and use the timer values. Input capture is another cool option if it fits whatever it is you're trying to do.

Jack,

Quick version: I want to detect an input to swing high and then wait for a period of time and set an output to high. The delay between detection and activating output is between 5.7ms and 11.4ms (round trip time for sound to travel between 1m distance and 2m distance), with as much accuracy as possible, or relative error of 0.1%, i.e. 1mm to 2mm, so right on the edge of 4us to 8us if possible.

Complete story here: I wanted to emulate a simple sonic ranger that works like the following (not like ping))))

1. The data acquisition system pulls the INIT digital line to HIGH to initiate the sonic ranger to start measurement.2. The ranger immediately sends out an ultrasonic.3. The ranger receives a reflected pulse from the nearest object and pulls the ECHO digital line to HIGH to indicate it has detected an object.4. The data acquisition system measures the delay between the start and the end of the measurement.5. It then uses the speed of sound to calculate round trip distance and only outputs the one-way distance to the user.

I emulated steps 3 and 4 with a different distance measurement device, my smart track. So every time my arduino is probed by INIT going from low to high, it measures distance and emulates a delay like the above-described sonic ranger, then gives a high on ECHO so the data acquisition system treats it like a sonic ranger and does its things happily.

But I noticed a fluction of the measurement that translates into +-12us fluctuation, could very well be the DAQ's timing being inaccurate, but I wanted to trust their +- 1mm accuracy which is translated into about 6us fluctuation (maybe I'm too picky). This makes me think my arduino C code is not time-accurate.

Timer/Counter1 has an input capture unit, that causes the timer value to be stored in the input capture register, ICR1. Actually it sounds like this could work well for you. I'd configure the timer just to run free at whatever frequency is needed. For sake of example, assuming a 16MHz system clock, set the prescaler to clk/8 and then each count would be 0.5µs. So save the timer value when pulling INIT high, and configure the input capture interrupt so the code knows when the return happened, i.e. wire the ECHO signal to the ICP1 pin. Subtract the ICR1 value from the previously saved value and that's it. Edit: Ummm, no. The other way 'round. Subtract the previously saved value from the ICR1 value.

That seems about as straightforward and clean as it could be, should be minimal error caused by processing, calculations, etc.

Oh section 16.6 in the ATmega328 datasheet gives all the gory details on input capture

PS: With the timer running at 2MHz, the counter would overflow about every 32mS if I did the maths right, so that would be the upper limit to the interval that could be measured.

Thank you! Sounds like quite a few tasks for me with not much timer experience. I'll read the section to get some understanding. So just to reiterate, I need the following skills to make it work:

1) Know how to set the prescalar of the timer12) Know how to read timer value so I can save it3) Know how to configure the input capture interrupt and which pin is the ICP1 pin (this sounds really restricting since my system is already built and few pins are available for this thing)4) Subtracting? I'm really clueless around timers.

SREG is the status register, it has the global interrupt enable bit in it. Without digging into the micros() code, I imagine that the interrupt bit is what's being manipulated there.

The other registers are for Timer0.

I haven't played with input capture myself, so I'd like to give it a try. The cool thing about it is once the setup is done (and that shouldn't be all that bad), then there's not much to do, like I said, very clean implementation.

I'd be game collaborating a bit if you would be. Should be able to hammer out a demo very quickly.

Actually a pin-change interrupt should work if the ICP1 pin is unavailable. A little more code but almost as good. Any pin can do a pin-change interrupt. Overall, no additional pins are required, just one for the INIT signal and one for the ECHO signal.

Well I couldn't help myself. Here's an input capture demo. One odd thing, I had to make sure I cleared the input capture flag in the Timer/Counter1 interrupt flag register [TIFR1 |= _BV(ICF1);]. Not sure why, might have had some switch bounce sneaking in there. That probably wouldn't be a problem with clean digital signals. Obviously the timer clock speed is not appropriate for your application, but that is easily altered.

//Input capture demo: Reaction timer.//Wire a tactile button switch from the Arduino D8 pin to ground.//To start, press and release the button when prompted to do so.//After a random 2-5 second delay, the LED will illuminate.//Press the button again as soon as the LED illuminates.//The reaction time between the LED illuminating and the second button press is displayed.//Reaction times over about four seconds will not be measured correctly.//Jack Christensen 08Jun2012 CC BY-SA

3) Know how to configure the input capture interrupt and which pin is the ICP1 pin (this sounds really restricting since my system is already built and few pins are available for this thing)

Opps, that'd be the only potential show-stopper. ICP1 is the same as the Arduino Uno D8 pin.

Darn, I used D8 already. All I have left are D9,10, 14-19. I guess this teaches me a lesson not to think I can do everything in software. So for my next hardware design iteration, which pins should I reserve for fancy things like ext interrupts and these timer driven functions? Now I know D0 and D1 are serial, D2 and D3 are for external interrupt and will keep them around. Also D9 for timer1. Anything else you would suggest me to keep? The arduino ADC isn't really awesome so I would not be devastated to use an external ADC (faster I2C 12bit or more) use A0-3 for digital pins, such as LCD data lines and reserve A4-5 for I2C bus. So what other fancy pins should I reserve? I'm not using SPI though.

Well I couldn't help myself. Here's an input capture demo. One odd thing, I had to make sure I cleared the input capture flag in the Timer/Counter1 interrupt flag register [TIFR1 |= _BV(ICF1);]. Not sure why, might have had some switch bounce sneaking in there. That probably wouldn't be a problem with clean digital signals. Obviously the timer clock speed is not appropriate for your application, but that is easily altered.

//Input capture demo: Reaction timer.//Wire a tactile button switch from the Arduino D8 pin to ground.//To start, press and release the button when prompted to do so.//After a random 2-5 second delay, the LED will illuminate.//Press the button again as soon as the LED illuminates.//The reaction time between the LED illuminating and the second button press is displayed.//Reaction times over about four seconds will not be measured correctly.//Jack Christensen 08Jun2012 CC BY-SA

Thanks for not being able to help yourself! I'll use this code on a regular Arduino dev board to see how it looks on that other end of the project.

At the moment I'm able to machine something to secure my sensors and the fluctuating readings have gone down a bit but this is still a very nice solution I'm going to try. I've been procrastinating on timers and interrupts.

@liudr, keep me in the loop as to how it works out. As for other "fancy pins", I keep the attached pinned to my bulletin board for easy reference. Basically just taken from the datasheet, but it's a good cross-reference between Arduino pin numbers, DIP package pin numbers, and the various functions of the pins.