|
| 1 | +// --------------------------------------------------------------------------- |
| 2 | +// NewPingESP8266 Library - v1.8 - 07/30/2016 |
| 3 | +// |
| 4 | +// AUTHOR/LICENSE: |
| 5 | +// Created by Tim Eckel - [email protected] |
| 6 | +// Copyright 2016 License: GNU GPL v3 http://www.gnu.org/licenses/gpl.html |
| 7 | +// |
| 8 | +// LINKS: |
| 9 | +// Project home: https://bitbucket.org/teckel12/arduino-new-ping/wiki/Home |
| 10 | +// Blog: http://arduino.cc/forum/index.php/topic,106043.0.html |
| 11 | +// |
| 12 | +// DISCLAIMER: |
| 13 | +// This software is furnished "as is", without technical support, and with no |
| 14 | +// warranty, express or implied, as to its usefulness for any purpose. |
| 15 | +// |
| 16 | +// BACKGROUND: |
| 17 | +// When I first received an ultrasonic sensor I was not happy with how poorly |
| 18 | +// it worked. Quickly I realized the problem wasn't the sensor, it was the |
| 19 | +// available ping and ultrasonic libraries causing the problem. The NewPingESP8266 |
| 20 | +// library totally fixes these problems, adds many new features, and breaths |
| 21 | +// new life into these very affordable distance sensors. |
| 22 | +// |
| 23 | +// FEATURES: |
| 24 | +// * Works with many different ultrasonic sensors: SR04, SRF05, SRF06, DYP-ME007, URM37 & Parallax PING))). |
| 25 | +// * Compatible with the entire Arduino line-up (and clones), Teensy family (including $19 96Mhz 32 bit Teensy 3.2) and non-AVR microcontrollers. |
| 26 | +// * Interface with all but the SRF06 sensor using only one Arduino pin. |
| 27 | +// * Doesn't lag for a full second if no ping/echo is received. |
| 28 | +// * Ping sensors consistently and reliably at up to 30 times per second. |
| 29 | +// * Timer interrupt method for event-driven sketches. |
| 30 | +// * Built-in digital filter method ping_median() for easy error correction. |
| 31 | +// * Uses port registers for a faster pin interface and smaller code size. |
| 32 | +// * Allows you to set a maximum distance where pings beyond that distance are read as no ping "clear". |
| 33 | +// * Ease of using multiple sensors (example sketch with 15 sensors). |
| 34 | +// * More accurate distance calculation (cm, inches & uS). |
| 35 | +// * Doesn't use pulseIn, which is slow and gives incorrect results with some ultrasonic sensor models. |
| 36 | +// * Actively developed with features being added and bugs/issues addressed. |
| 37 | +// |
| 38 | +// CONSTRUCTOR: |
| 39 | +// NewPingESP8266 sonar(trigger_pin, echo_pin [, max_cm_distance]) |
| 40 | +// trigger_pin & echo_pin - Arduino pins connected to sensor trigger and echo. |
| 41 | +// NOTE: To use the same Arduino pin for trigger and echo, specify the same pin for both values. |
| 42 | +// max_cm_distance - [Optional] Maximum distance you wish to sense. Default=500cm. |
| 43 | +// |
| 44 | +// METHODS: |
| 45 | +// sonar.ping([max_cm_distance]) - Send a ping and get the echo time (in microseconds) as a result. [max_cm_distance] allows you to optionally set a new max distance. |
| 46 | +// sonar.ping_in([max_cm_distance]) - Send a ping and get the distance in whole inches. [max_cm_distance] allows you to optionally set a new max distance. |
| 47 | +// sonar.ping_cm([max_cm_distance]) - Send a ping and get the distance in whole centimeters. [max_cm_distance] allows you to optionally set a new max distance. |
| 48 | +// sonar.ping_median(iterations [, max_cm_distance]) - Do multiple pings (default=5), discard out of range pings and return median in microseconds. [max_cm_distance] allows you to optionally set a new max distance. |
| 49 | +// NewPingESP8266::convert_in(echoTime) - Convert echoTime from microseconds to inches (rounds to nearest inch). |
| 50 | +// NewPingESP8266::convert_cm(echoTime) - Convert echoTime from microseconds to centimeters (rounds to nearest cm). |
| 51 | +// sonar.ping_timer(function [, max_cm_distance]) - Send a ping and call function to test if ping is complete. [max_cm_distance] allows you to optionally set a new max distance. |
| 52 | +// sonar.check_timer() - Check if ping has returned within the set distance limit. |
| 53 | +// NewPingESP8266::timer_us(frequency, function) - Call function every frequency microseconds. |
| 54 | +// NewPingESP8266::timer_ms(frequency, function) - Call function every frequency milliseconds. |
| 55 | +// NewPingESP8266::timer_stop() - Stop the timer. |
| 56 | +// |
| 57 | +// HISTORY: |
| 58 | +// 07/30/2016 v1.8 - Added support for non-AVR microcontrollers. For non-AVR |
| 59 | +// microcontrollers, advanced ping_timer() timer methods are disabled due to |
| 60 | +// inconsistencies or no support at all between platforms. However, standard |
| 61 | +// ping methods are all supported. Added new optional variable to ping(), |
| 62 | +// ping_in(), ping_cm(), ping_median(), and ping_timer() methods which allows |
| 63 | +// you to set a new maximum distance for each ping. Added support for the |
| 64 | +// ATmega16, ATmega32 and ATmega8535 microcontrollers. Changed convert_cm() |
| 65 | +// and convert_in() methods to static members. You can now call them without |
| 66 | +// an object. For example: cm = NewPingESP8266::convert_cm(distance); |
| 67 | +// |
| 68 | +// 09/29/2015 v1.7 - Removed support for the Arduino Due and Zero because |
| 69 | +// they're both 3.3 volt boards and are not 5 volt tolerant while the HC-SR04 |
| 70 | +// is a 5 volt sensor. Also, the Due and Zero don't support pin manipulation |
| 71 | +// compatibility via port registers which can be done (see the Teensy 3.2). |
| 72 | +// |
| 73 | +// 06/17/2014 v1.6 - Corrected delay between pings when using ping_median() |
| 74 | +// method. Added support for the URM37 sensor (must change URM37_ENABLED from |
| 75 | +// false to true). Added support for Arduino microcontrollers like the $20 |
| 76 | +// 32 bit ARM Cortex-M4 based Teensy 3.2. Added automatic support for the |
| 77 | +// Atmel ATtiny family of microcontrollers. Added timer support for the |
| 78 | +// ATmega8 microcontroller. Rounding disabled by default, reduces compiled |
| 79 | +// code size (can be turned on with ROUNDING_ENABLED switch). Added |
| 80 | +// TIMER_ENABLED switch to get around compile-time "__vector_7" errors when |
| 81 | +// using the Tone library, or you can use the toneAC, NewTone or |
| 82 | +// TimerFreeTone libraries: https://bitbucket.org/teckel12/arduino-toneac/ |
| 83 | +// Other speed and compiled size optimizations. |
| 84 | +// |
| 85 | +// 08/15/2012 v1.5 - Added ping_median() method which does a user specified |
| 86 | +// number of pings (default=5) and returns the median ping in microseconds |
| 87 | +// (out of range pings ignored). This is a very effective digital filter. |
| 88 | +// Optimized for smaller compiled size (even smaller than sketches that |
| 89 | +// don't use a library). |
| 90 | +// |
| 91 | +// 07/14/2012 v1.4 - Added support for the Parallax PING)))� sensor. Interface |
| 92 | +// with all but the SRF06 sensor using only one Arduino pin. You can also |
| 93 | +// interface with the SRF06 using one pin if you install a 0.1uf capacitor |
| 94 | +// on the trigger and echo pins of the sensor then tie the trigger pin to |
| 95 | +// the Arduino pin (doesn't work with Teensy). To use the same Arduino pin |
| 96 | +// for trigger and echo, specify the same pin for both values. Various bug |
| 97 | +// fixes. |
| 98 | +// |
| 99 | +// 06/08/2012 v1.3 - Big feature addition, event-driven ping! Uses Timer2 |
| 100 | +// interrupt, so be mindful of PWM or timing conflicts messing with Timer2 |
| 101 | +// may cause (namely PWM on pins 3 & 11 on Arduino, PWM on pins 9 and 10 on |
| 102 | +// Mega, and Tone library). Simple to use timer interrupt functions you can |
| 103 | +// use in your sketches totally unrelated to ultrasonic sensors (don't use if |
| 104 | +// you're also using NewPingESP8266's ping_timer because both use Timer2 interrupts). |
| 105 | +// Loop counting ping method deleted in favor of timing ping method after |
| 106 | +// inconsistent results kept surfacing with the loop timing ping method. |
| 107 | +// Conversion to cm and inches now rounds to the nearest cm or inch. Code |
| 108 | +// optimized to save program space and fixed a couple minor bugs here and |
| 109 | +// there. Many new comments added as well as line spacing to group code |
| 110 | +// sections for better source readability. |
| 111 | +// |
| 112 | +// 05/25/2012 v1.2 - Lots of code clean-up thanks to Arduino Forum members. |
| 113 | +// Rebuilt the ping timing code from scratch, ditched the pulseIn code as it |
| 114 | +// doesn't give correct results (at least with ping sensors). The NewPingESP8266 |
| 115 | +// library is now VERY accurate and the code was simplified as a bonus. |
| 116 | +// Smaller and faster code as well. Fixed some issues with very close ping |
| 117 | +// results when converting to inches. All functions now return 0 only when |
| 118 | +// there's no ping echo (out of range) and a positive value for a successful |
| 119 | +// ping. This can effectively be used to detect if something is out of range |
| 120 | +// or in-range and at what distance. Now compatible with Arduino 0023. |
| 121 | +// |
| 122 | +// 05/16/2012 v1.1 - Changed all I/O functions to use low-level port registers |
| 123 | +// for ultra-fast and lean code (saves from 174 to 394 bytes). Tested on both |
| 124 | +// the Arduino Uno and Teensy 2.0 but should work on all Arduino-based |
| 125 | +// platforms because it calls standard functions to retrieve port registers |
| 126 | +// and bit masks. Also made a couple minor fixes to defines. |
| 127 | +// |
| 128 | +// 05/15/2012 v1.0 - Initial release. |
| 129 | +// --------------------------------------------------------------------------- |
| 130 | + |
| 131 | +#ifndef NewPingESP8266_h |
| 132 | +#define NewPingESP8266_h |
| 133 | + |
| 134 | +#if defined (ARDUINO) && ARDUINO >= 100 |
| 135 | + #include <Arduino.h> |
| 136 | +#else |
| 137 | + #include <WProgram.h> |
| 138 | + #include <pins_arduino.h> |
| 139 | +#endif |
| 140 | + |
| 141 | +#if defined (__AVR__) |
| 142 | + #include <avr/io.h> |
| 143 | + #include <avr/interrupt.h> |
| 144 | +#endif |
| 145 | + |
| 146 | +// Shouldn't need to change these values unless you have a specific need to do so. |
| 147 | +#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. Default=500 |
| 148 | +#define US_ROUNDTRIP_CM 57 // Microseconds (uS) it takes sound to travel round-trip 1cm (2cm total), uses integer to save compiled code space. Default=57 |
| 149 | +#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. Defalult=146 |
| 150 | +#define ONE_PIN_ENABLED true // Set to "false" to disable one pin mode which saves around 14-26 bytes of binary size. Default=true |
| 151 | +#define ROUNDING_ENABLED false // Set to "true" to enable distance rounding which also adds 64 bytes to binary size. Default=false |
| 152 | +#define URM37_ENABLED false // Set to "true" to enable support for the URM37 sensor in PWM mode. Default=false |
| 153 | +#define TIMER_ENABLED true // Set to "false" to disable the timer ISR (if getting "__vector_7" compile errors set this to false). Default=true |
| 154 | + |
| 155 | +// Probably shouldn't change these values unless you really know what you're doing. |
| 156 | +#define NO_ECHO 0 // Value returned if there's no ping echo within the specified MAX_SENSOR_DISTANCE or max_cm_distance. Default=0 |
| 157 | +#define MAX_SENSOR_DELAY 5800 // Maximum uS it takes for sensor to start the ping. Default=5800 |
| 158 | +#define ECHO_TIMER_FREQ 24 // Frequency to check for a ping echo (every 24uS is about 0.4cm accuracy). Default=24 |
| 159 | +#define PING_MEDIAN_DELAY 29000 // Microsecond delay between pings in the ping_median method. Default=29000 |
| 160 | +#define PING_OVERHEAD 5 // Ping overhead in microseconds (uS). Default=5 |
| 161 | +#define PING_TIMER_OVERHEAD 13 // Ping timer overhead in microseconds (uS). Default=13 |
| 162 | +#if URM37_ENABLED == true |
| 163 | + #undef US_ROUNDTRIP_CM |
| 164 | + #undef US_ROUNDTRIP_IN |
| 165 | + #define US_ROUNDTRIP_CM 50 // Every 50uS PWM signal is low indicates 1cm distance. Default=50 |
| 166 | + #define US_ROUNDTRIP_IN 127 // If 50uS is 1cm, 1 inch would be 127uS (50 x 2.54 = 127). Default=127 |
| 167 | +#endif |
| 168 | + |
| 169 | +// Conversion from uS to distance (round result to nearest cm or inch). |
| 170 | +#define NewPingESP8266Convert(echoTime, conversionFactor) (max(((unsigned int)echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0))) |
| 171 | + |
| 172 | +// Detect non-AVR microcontrollers (Teensy 3.x, Arduino DUE, etc.) and don't use port registers or timer interrupts as required. |
| 173 | +#if (defined (__arm__) && defined (TEENSYDUINO)) |
| 174 | + #undef PING_OVERHEAD |
| 175 | + #define PING_OVERHEAD 1 |
| 176 | + #undef PING_TIMER_OVERHEAD |
| 177 | + #define PING_TIMER_OVERHEAD 1 |
| 178 | + #define DO_BITWISE true |
| 179 | +#elif !defined (__AVR__) |
| 180 | + #undef PING_OVERHEAD |
| 181 | + #define PING_OVERHEAD 1 |
| 182 | + #undef PING_TIMER_OVERHEAD |
| 183 | + #define PING_TIMER_OVERHEAD 1 |
| 184 | + #undef TIMER_ENABLED |
| 185 | + #define TIMER_ENABLED false |
| 186 | + #define DO_BITWISE false |
| 187 | +#else |
| 188 | + #define DO_BITWISE true |
| 189 | +#endif |
| 190 | + |
| 191 | +// Disable the timer interrupts when using ATmega128 and all ATtiny microcontrollers. |
| 192 | +#if defined (__AVR_ATmega128__) || defined (__AVR_ATtiny24__) || defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny84__) || defined (__AVR_ATtiny25__) || defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__) || defined (__AVR_ATtiny261__) || defined (__AVR_ATtiny461__) || defined (__AVR_ATtiny861__) || defined (__AVR_ATtiny43U__) |
| 193 | + #undef TIMER_ENABLED |
| 194 | + #define TIMER_ENABLED false |
| 195 | +#endif |
| 196 | + |
| 197 | +// Define timers when using ATmega8, ATmega16, ATmega32 and ATmega8535 microcontrollers. |
| 198 | +#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) || defined (__AVR_ATmega8535__) |
| 199 | + #define OCR2A OCR2 |
| 200 | + #define TIMSK2 TIMSK |
| 201 | + #define OCIE2A OCIE2 |
| 202 | +#endif |
| 203 | + |
| 204 | +class NewPingESP8266 { |
| 205 | + public: |
| 206 | + NewPingESP8266(uint32_t trigger_pin, uint32_t echo_pin, unsigned int max_cm_distance = MAX_SENSOR_DISTANCE); |
| 207 | + unsigned int ping(unsigned int max_cm_distance = 0); |
| 208 | + unsigned long ping_cm(unsigned int max_cm_distance = 0); |
| 209 | + unsigned long ping_in(unsigned int max_cm_distance = 0); |
| 210 | + unsigned long ping_median(uint32_t it = 5, unsigned int max_cm_distance = 0); |
| 211 | + static unsigned int convert_cm(unsigned int echoTime); |
| 212 | + static unsigned int convert_in(unsigned int echoTime); |
| 213 | +#if TIMER_ENABLED == true |
| 214 | + void ping_timer(void (*userFunc)(void), unsigned int max_cm_distance = 0); |
| 215 | + boolean check_timer(); |
| 216 | + unsigned long ping_result; |
| 217 | + static void timer_us(unsigned int frequency, void (*userFunc)(void)); |
| 218 | + static void timer_ms(unsigned long frequency, void (*userFunc)(void)); |
| 219 | + static void timer_stop(); |
| 220 | +#endif |
| 221 | + private: |
| 222 | + boolean ping_trigger(); |
| 223 | + void set_max_distance(unsigned int max_cm_distance); |
| 224 | +#if TIMER_ENABLED == true |
| 225 | + boolean ping_trigger_timer(unsigned int trigger_delay); |
| 226 | + boolean ping_wait_timer(); |
| 227 | + static void timer_setup(); |
| 228 | + static void timer_ms_cntdwn(); |
| 229 | +#endif |
| 230 | +#if DO_BITWISE == true |
| 231 | + uint32_t _triggerBit; |
| 232 | + uint32_t _echoBit; |
| 233 | + volatile uint32_t *_triggerOutput; |
| 234 | + volatile uint32_t *_echoInput; |
| 235 | + volatile uint32_t *_triggerMode; |
| 236 | +#else |
| 237 | + uint32_t _triggerPin; |
| 238 | + uint32_t _echoPin; |
| 239 | +#endif |
| 240 | + unsigned int _maxEchoTime; |
| 241 | + unsigned long _max_time; |
| 242 | +}; |
| 243 | + |
| 244 | + |
| 245 | +#endif |
0 commit comments