Skip to content

Commit 1bbe616

Browse files
committed
pulseIn: add alternative implementation based on micros()
1 parent 4ac9971 commit 1bbe616

File tree

2 files changed

+46
-2
lines changed

2 files changed

+46
-2
lines changed

cores/arduino/wiring_pulse.cpp

+45-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@
2222
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
2323
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
2424
* to 3 minutes in length, but must be called at least a few dozen microseconds
25-
* before the start of the pulse. */
25+
* before the start of the pulse.
26+
*
27+
* ATTENTION:
28+
* This function performs better with short pulses in noInterrupt() context
29+
*/
2630
uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout )
2731
{
2832
// cache the port and bit of the pin in order to speed up the
@@ -47,3 +51,43 @@ uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout )
4751
else
4852
return 0;
4953
}
54+
55+
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
56+
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
57+
* to 3 minutes in length, but must be called at least a few dozen microseconds
58+
* before the start of the pulse.
59+
*
60+
* ATTENTION:
61+
* this function relies on micros() so cannot be used in noInterrupt() context
62+
*/
63+
uint32_t pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
64+
{
65+
// cache the port and bit of the pin in order to speed up the
66+
// pulse width measuring loop and achieve finer resolution. calling
67+
// digitalRead() instead yields much coarser resolution.
68+
PinDescription p = g_APinDescription[pin];
69+
uint32_t bit = p.ulPin;
70+
uint32_t stateMask = state ? bit : 0;
71+
72+
// convert the timeout from microseconds to a number of times through
73+
// the initial loop; it takes 18 clock cycles per iteration.
74+
unsigned long maxloops = microsecondsToClockCycles(timeout) / 10;
75+
76+
// wait for any previous pulse to end
77+
while ((p.pPort->PIO_PDSR & bit) == stateMask)
78+
if (--maxloops == 0)
79+
return 0;
80+
81+
// wait for the pulse to start
82+
while ((p.pPort->PIO_PDSR & bit) != stateMask)
83+
if (--maxloops == 0)
84+
return 0;
85+
86+
unsigned long start = micros();
87+
// wait for the pulse to stop
88+
while ((p.pPort->PIO_PDSR & bit) == stateMask) {
89+
if (--maxloops == 0)
90+
return 0;
91+
}
92+
return micros() - start;
93+
}

cores/arduino/wiring_pulse.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ unsigned long countPulseASM(const volatile uint32_t *port, uint32_t bit, uint32_
3131
* before the start of the pulse.
3232
*/
3333
extern uint32_t pulseIn( uint32_t ulPin, uint32_t ulState, uint32_t ulTimeout = 1000000L ) ;
34-
34+
extern uint32_t pulseInLong( uint8_t pin, uint8_t state, unsigned long timeout = 1000000L ) ;
3535

3636
#ifdef __cplusplus
3737
}

0 commit comments

Comments
 (0)