-
Notifications
You must be signed in to change notification settings - Fork 36
/
NewPing.h
167 lines (155 loc) · 8.88 KB
/
NewPing.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// ---------------------------------------------------------------------------
// NewPing Library - v1.5 - 08/15/2012
//
// AUTHOR/LICENSE:
// Created by Tim Eckel - [email protected]
// Copyright 2012 License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html
//
// LINKS:
// Project home: http://code.google.com/p/arduino-new-ping/
// Blog: http://arduino.cc/forum/index.php/topic,106043.0.html
//
// DISCLAIMER:
// This software is furnished "as is", without technical support, and with no
// warranty, express or implied, as to its usefulness for any purpose.
//
// BACKGROUND:
// When I first received an ultrasonic sensor I was not happy with how poorly
// it worked. Quickly I realized the problem wasn't the sensor, it was the
// available ping and ultrasonic libraries causing the problem. The NewPing
// library totally fixes these problems, adds many new features, and breaths
// new life into these very affordable distance sensors.
//
// FEATURES:
// * Works with many different ultrasonic sensor models: SR04, SRF05, SRF06, DYP-ME007 & Parallax PING)))™.
// * Interface with all but the SRF06 sensor using only one Arduino pin.
// * Doesn't lag for a full second if no ping/echo is received.
// * Ping sensors consistently and reliably at up to 30 times per second.
// * Timer interrupt method for event-driven sketches.
// * Built-in digital filter method ping_median() for easy error correction.
// * Uses port registers for a faster pin interface and smaller code size.
// * Allows you to set a maximum distance where pings beyond that distance are read as no ping "clear".
// * Ease of using multiple sensors (example sketch with 15 sensors).
// * More accurate distance calculation (cm, inches & uS).
// * Doesn't use pulseIn, which is slow and gives incorrect results with some ultrasonic sensor models.
// * Actively developed with features being added and bugs/issues addressed.
//
// CONSTRUCTOR:
// NewPing sonar(trigger_pin, echo_pin [, max_cm_distance])
// trigger_pin & echo_pin - Arduino pins connected to sensor trigger and echo.
// NOTE: To use the same Arduino pin for trigger and echo, specify the same pin for both values.
// max_cm_distance - [Optional] Maximum distance you wish to sense. Default=500cm.
//
// SYNTAX:
// sonar.ping() - Send a ping and get the echo time (in microseconds) as a result.
// sonar.ping_in() - Send a ping and get the distance in whole inches.
// sonar.ping_cm() - Send a ping and get the distance in whole centimeters.
// sonar.ping_median(iterations) - Do multiple pings (default=5), discard out of range pings and return median in microseconds.
// sonar.convert_in(echoTime) - Convert echoTime from microseconds to inches (rounds to nearest inch).
// sonar.convert_cm(echoTime) - Convert echoTime from microseconds to centimeters (rounds to nearest cm).
// sonar.ping_timer(function) - Send a ping and call function to test if ping is complete.
// sonar.check_timer() - Check if ping has returned within the set distance limit.
// NewPing::timer_us(frequency, function) - Call function every frequency microseconds.
// NewPing::timer_ms(frequency, function) - Call function every frequency milliseconds.
// NewPing::timer_stop() - Stop the timer.
//
// HISTORY:
// 08/15/2012 v1.5 - Added ping_median() method which does a user specified
// number of pings (default=5) and returns the median ping in microseconds
// (out of range pings ignored). This is a very effective digital filter.
// Optimized for smaller compiled size (even smaller than skteches that
// don't use a library).
//
// 07/14/2012 v1.4 - Added support for the Parallax PING)))™ sensor. Interface
// with all but the SRF06 sensor using only one Arduino pin. You can also
// interface with the SRF06 using one pin if you install a 0.1uf capacitor
// on the trigger and echo pins of the sensor then tie the trigger pin to
// the Arduino pin (doesn't work with Teensy). To use the same Arduino pin
// for trigger and echo, specify the same pin for both values. Various bug
// fixes.
//
// 06/08/2012 v1.3 - Big feature addition, event-driven ping! Uses Timer2
// interrupt, so be mindful of PWM or timing conflicts messing with Timer2
// may cause (namely PWM on pins 3 & 11 on Arduino, PWM on pins 9 and 10 on
// Mega, and Tone library). Simple to use timer interrupt functions you can
// use in your sketches totaly unrelated to ultrasonic sensors (don't use if
// you're also using NewPing's ping_timer because both use Timer2 interrupts).
// Loop counting ping method deleted in favor of timing ping method after
// inconsistant results kept surfacing with the loop timing ping method.
// Conversion to cm and inches now rounds to the nearest cm or inch. Code
// optimized to save program space and fixed a couple minor bugs here and
// there. Many new comments added as well as line spacing to group code
// sections for better source readability.
//
// 05/25/2012 v1.2 - Lots of code clean-up thanks to Adruino Forum members.
// Rebuilt the ping timing code from scratch, ditched the pulseIn code as it
// doesn't give correct results (at least with ping sensors). The NewPing
// library is now VERY accurate and the code was simplified as a bonus.
// Smaller and faster code as well. Fixed some issues with very close ping
// results when converting to inches. All functions now return 0 only when
// there's no ping echo (out of range) and a positive value for a successful
// ping. This can effectively be used to detect if something is out of range
// or in-range and at what distance. Now compatible with Arduino 0023.
//
// 05/16/2012 v1.1 - Changed all I/O functions to use low-level port registers
// for ultra-fast and lean code (saves from 174 to 394 bytes). Tested on both
// the Arduino Uno and Teensy 2.0 but should work on all Arduino-based
// platforms because it calls standard functions to retrieve port registers
// and bit masks. Also made a couple minor fixes to defines.
//
// 05/15/2012 v1.0 - Initial release.
// ---------------------------------------------------------------------------
#ifndef NewPing_h
#define NewPing_h
#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#include <pins_arduino.h>
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
// Shoudln't need to changed these values unless you have a specific need to do so.
#define MAX_SENSOR_DISTANCE 500 // Maximum sensor distance can be as high as 500cm, no reason to wait for ping longer than sound takes to travel this distance and back.
#define US_ROUNDTRIP_IN 146 // Microseconds (uS) it takes sound to travel round-trip 1 inch (2 inches total), uses integer to save compiled code space.
#define US_ROUNDTRIP_CM 57 // Microseconds (uS) it takes sound to travel round-trip 1cm (2cm total), uses integer to save compiled code space.
#define DISABLE_ONE_PIN false // Set to "true" to save up to 26 bytes of compiled code space if you're not using one pin sensor connections.
// Probably shoudln't change these values unless you really know what you're doing.
#define NO_ECHO 0 // Value returned if there's no ping echo within the specified MAX_SENSOR_DISTANCE or max_cm_distance.
#define MAX_SENSOR_DELAY 18000 // Maximum uS it takes for sensor to start the ping (SRF06 is the highest measured, just under 18ms).
#define ECHO_TIMER_FREQ 24 // Frequency to check for a ping echo (every 24uS is about 0.4cm accuracy).
#define PING_MEDIAN_DELAY 29 // Millisecond delay between pings in the ping_median method.
// Conversion from uS to distance (round result to nearest cm or inch).
#define NewPingConvert(echoTime, conversionFactor) (max((echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0)))
class NewPing {
public:
NewPing(uint8_t trigger_pin, uint8_t echo_pin, int max_cm_distance = MAX_SENSOR_DISTANCE);
unsigned int ping();
unsigned int ping_in();
unsigned int ping_cm();
unsigned int ping_median(uint8_t it = 5);
unsigned int convert_in(unsigned int echoTime);
unsigned int convert_cm(unsigned int echoTime);
void ping_timer(void (*userFunc)(NewPing *));
boolean check_timer();
unsigned long ping_result;
void *user_data; // allows to store custom user data, primarily for userFunc callbacks
/* internal */
void timer_us(unsigned int frequency, void (*userFunc)(NewPing *));
void timer_ms(unsigned long frequency, void (*userFunc)(NewPing *));
static void timer_stop();
private:
boolean ping_trigger();
boolean ping_wait_timer();
uint8_t _triggerBit;
uint8_t _echoBit;
volatile uint8_t *_triggerOutput;
volatile uint8_t *_triggerMode;
volatile uint8_t *_echoInput;
unsigned int _maxEchoTime;
unsigned long _max_time;
static void timer_setup();
static void timer_ms_cntdwn();
static void call_user_func();
};
#endif