I am making a small project, and for that, I need to measure the time between 2 inputs. basically, a program to measure the time elapsed from when digital pin 2 is high to when it again becomes high.
2 Answers 2
The way to go depends on the time range, that the event will have. The Arduino framework already includes a function for timekeeping: millis()
. It returns the number of milliseconds since the startup (much like a clock) and measures the time via the hardware Timer0 and it's interrupts. This function will work good in the 2 digit millisecond range and above. With single digit millisecond or the microsecond domain, you should instead use micros()
with works similar, but returns the microseconds since startup. For the low microsecond range and below you would need to work directly with a dedicated hardware timer, configuring it via its hardware registers.
Here I would show the principle of millis()
/micros()
, since that is most likely what you need. In the following I will only write millis()
, but all the calculations can also be done with micros()
. The only difference for the calculations is the factor 1000 between milli- and microseconds.
When you look at your watch and want to measure a time difference, you take note of the start time and the end time. Then you calculate the difference to get the event duration. You can do the same with millis()
:
unsigned long starttime = millis(); // take note of start time
// here the event to measure
unsigned long endtime = millis(); // take note of end time
unsigned long duration = endtime - starttime; // duration of the event in ms
So in your code you need to check for a rising edge of your signal. On every rising edge you calculate the time difference between the last timestamp and the current time. Then you reset the timestamp. Something like this:
int last_input_state = LOW;
unsigned long timestamp;
//setup here
void loop(){
int current_input_state = digitalRead(2); // get current signal level
if(current_input_state && !last_input_state){ //check, if signal is now high and was low before
unsigned long current_time = millis(); // take note of the current time
unsigned long duration = current_time - timestamp; // calculate the duration and do something with it
timestamp = current_time; // update the timestamp with the current time
}
last_input_state = current_input_state; // update the last input state with the new measured one
}
Note:
- This code is non-blocking. It needs to run fast and continuously to work correctly. You cannot do long blocking things in the rest of your code, like using high
delay()
calls, but you shouldn't do that either way, since that will block anything from going on. - You can go even further to lift the weight from your CPU and use an interrupt to sense the rising edge. You could use
attachInterrupt(digitalPinToInterrupt(pin), service_function, RISING);
and provide avoid service_function()
, which does the timestamp measurement and calculation (basically the same code as in the if statement of the code above).
You could do something like this:
unsigned long startTime;
unsigned long elapsedTime;
// Any needed setup stuff
void setup()
{
...
}
void loop()
{
// Wait for input to go high
while(digitalRead(2) == LOW);
// Start timing
startTime = millis();
// Wait for input to go low
while(digitalRead(2) == HIGH);
// Now wait for it to go high again
while(digitalRead(2) == LOW);
// Now get the time interval
elapsedTime = millis() - startTime;
// Do whatever with the result.
...
}
Keep in mind that the millis() value will overflow every 50 days or so. If you need to run this continuously, you need to check for an overflow and adjust things accordingly.
-
elapsedTime = millis() - startTime;
even works well while millis passes 0 on "overflow". Nothing to adjust.DataFiddler– DataFiddler2020年12月30日 17:16:29 +00:00Commented Dec 30, 2020 at 17:16 -
Altough working with millis(), this is a blocking example, due to the while statements. (Even worse that the Arduino
pulseIn
function, which has a timeout)DataFiddler– DataFiddler2020年12月30日 17:19:26 +00:00Commented Dec 30, 2020 at 17:19 -
I did not see any requirement to do anything but measure the interval. Therefore a blocking solution is ok. Why complicate it if it's not needed? As is so often the case, there are many many possible solutions.jwh20– jwh202020年12月30日 17:49:36 +00:00Commented Dec 30, 2020 at 17:49
-
So one should compare your solution to standard
pulseIn
.DataFiddler– DataFiddler2020年12月31日 11:52:16 +00:00Commented Dec 31, 2020 at 11:52
millis()
function and the time measurement in theBlinkWithoutDelay
example? There are lots of tutorials aboutmillis()
on the web