1 | /* |
2 | wiring_pulse.c - pulseIn() function |
3 | Part of Arduino - http://www.arduino.cc/ |
4 | |
5 | Copyright (c) 2005-2006 David A. Mellis |
6 | |
7 | This library is free software; you can redistribute it and/or |
8 | modify it under the terms of the GNU Lesser General Public |
9 | License as published by the Free Software Foundation; either |
10 | version 2.1 of the License, or (at your option) any later version. |
11 | |
12 | This library is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | Lesser General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU Lesser General |
18 | Public License along with this library; if not, write to the |
19 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
20 | Boston, MA 02111-1307 USA |
21 | */ |
22 |
|
23 | #include "wiring_private.h" |
24 | #include "pins_arduino.h" |
25 |
|
26 | /* Measures the length (in microseconds) of a pulse on the pin; state is HIGH |
27 | * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds |
28 | * to 3 minutes in length, but must be called at least a few dozen microseconds |
29 | * before the start of the pulse. |
30 | * |
31 | * This function performs better with short pulses in noInterrupt() context |
32 | */ |
33 | unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) |
34 | { |
35 | // cache the port and bit of the pin in order to speed up the |
36 | // pulse width measuring loop and achieve finer resolution. calling |
37 | // digitalRead() instead yields much coarser resolution. |
38 | uint8_t bit = digitalPinToBitMask(pin); |
39 | uint8_t port = digitalPinToPort(pin); |
40 | uint8_t stateMask = (state ? bit : 0); |
41 |
|
42 | // convert the timeout from microseconds to a number of times through |
43 | // the initial loop; it takes approximately 16 clock cycles per iteration |
44 | unsigned long maxloops = microsecondsToClockCycles(timeout)/16; |
45 |
|
46 | unsigned long width = countPulseASM(portInputRegister(port), bit, stateMask, maxloops); |
47 |
|
48 | // prevent clockCyclesToMicroseconds to return bogus values if countPulseASM timed out |
49 | if (width) |
50 | return clockCyclesToMicroseconds(width * 16 + 16); |
51 | else |
52 | return 0; |
53 | } |
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 | unsigned long 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 | uint8_t bit = digitalPinToBitMask(pin); |
69 | uint8_t port = digitalPinToPort(pin); |
70 | uint8_t stateMask = (state ? bit : 0); |
71 |
|
72 | unsigned long startMicros = micros(); |
73 |
|
74 | // wait for any previous pulse to end |
75 | while ((*portInputRegister(port) & bit) == stateMask) { |
76 | if (micros() - startMicros > timeout) |
77 | return 0; |
78 | } |
79 |
|
80 | // wait for the pulse to start |
81 | while ((*portInputRegister(port) & bit) != stateMask) { |
82 | if (micros() - startMicros > timeout) |
83 | return 0; |
84 | } |
85 |
|
86 | unsigned long start = micros(); |
87 | // wait for the pulse to stop |
88 | while ((*portInputRegister(port) & bit) == stateMask) { |
89 | if (micros() - startMicros > timeout) |
90 | return 0; |
91 | } |
92 | return micros() - start; |
93 | } |
94 |
|