diff --git a/Examples/SonarMote/SonarMote_DistanceSensor/SonarMote_DistanceSensor.ino b/Examples/SonarMote/SonarMote_DistanceSensor/SonarMote_DistanceSensor.ino
new file mode 100644
index 0000000..000e220
--- /dev/null
+++ b/Examples/SonarMote/SonarMote_DistanceSensor/SonarMote_DistanceSensor.ino
@@ -0,0 +1,97 @@
+// Sample sketch for the SonarMote - Simple distance reading
+// http://lowpowerlab.com/sonar
+// Ultrasonic sensor (HC-SR04) connected to D6 (Trig), D7 (Echo), and power enabled through D5
+// Make sure you adjust the settings in the configuration section below !!!
+// **********************************************************************************
+// Copyright Felix Rusu, LowPowerLab.com
+// Library and code by Felix Rusu - felix@lowpowerlab.com
+// **********************************************************************************
+// License
+// **********************************************************************************
+// This program is free software; you can redistribute it
+// and/or modify it under the terms of the GNU General
+// Public License as published by the Free Software
+// Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A
+// PARTICULAR PURPOSE. See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General
+// Public License along with this program.
+// If not, see .
+//
+// Licence can be viewed at
+// http://www.gnu.org/licenses/gpl-3.0.txt
+//
+// Please maintain this license information along with authorship
+// and copyright notices in any redistribution of this code
+// **********************************************************************************
+#define TRIG 6
+#define ECHO 7
+#define EN 5
+
+void setup() {
+ pinMode (TRIG,OUTPUT);//attach pin 2 to vcc
+ pinMode (ECHO,OUTPUT);//attach pin 2 to vcc
+ pinMode (EN,OUTPUT);//attach pin 5 to GND
+ pinMode (ECHO, INPUT);//attach pin 4 to Echo
+ // initialize serial communication:
+ Serial.begin(115200);
+ digitalWrite(EN, LOW);
+}
+
+long cm;
+void loop()
+{
+ cm = readDistanceCM();
+ Serial.print(cm); Serial.println("cm");
+ delay(500);
+}
+
+long readDistanceCM()
+{
+ digitalWrite(EN, HIGH);
+ delay(75);
+ // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
+ // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
+ digitalWrite(TRIG, LOW);
+ delayMicroseconds(2);
+ digitalWrite(TRIG, HIGH);
+ delayMicroseconds(5);
+ digitalWrite(TRIG, LOW);
+ pulseIn(ECHO, HIGH);
+ delay(16);
+ digitalWrite(TRIG, LOW);
+ delayMicroseconds(2);
+ digitalWrite(TRIG, HIGH);
+ delayMicroseconds(5);
+ digitalWrite(TRIG, LOW);
+ // The same pin is used to read the signal from the PING))): a HIGH
+ // pulse whose duration is the time (in microseconds) from the sending
+ // of the ping to the reception of its echo off of an object.
+ long duration = pulseIn(ECHO, HIGH);
+ digitalWrite(EN, LOW);
+ return microsecondsToCentimeters(duration);
+}
+
+long microsecondsToInches(long microseconds)
+{
+ // According to Parallax's datasheet for the PING))), there are
+ // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
+ // second). This gives the distance travelled by the ping, outbound
+ // and return, so we divide by 2 to get the distance of the obstacle.
+ // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
+ return microseconds / 74 / 2;
+}
+
+long microsecondsToCentimeters(long microseconds)
+{
+ // The speed of sound is 340 m/s or 29 microseconds per centimeter.
+ // The ping travels out and back, so to find the distance of the
+ // object we take half of the distance travelled.
+ return microseconds / 29 / 2;
+}
diff --git a/Examples/SonarMote/SonarMote_InventoryTracking/SonarMote_InventoryTracking.ino b/Examples/SonarMote/SonarMote_InventoryTracking/SonarMote_InventoryTracking.ino
new file mode 100644
index 0000000..fd15b46
--- /dev/null
+++ b/Examples/SonarMote/SonarMote_InventoryTracking/SonarMote_InventoryTracking.ino
@@ -0,0 +1,277 @@
+// Sample RFM69 sender/node sketch for the SonarMote - Distance tracker
+// Can be used for inventory control - ex to measure distance in a multi lane cigarette pack rack
+// More info/photos at: http://lowpowerlab.com/sonar
+// Ultrasonic sensor (HC-SR04) connected to D6 (Trig), D7 (Echo), and power enabled through D5
+// This sketch sleeps the Moteino and sensor most of the time. It wakes up every few seconds to take
+// a distance reading. If it detects an approaching object (car) it increases the sampling rate
+// and starts lighting up the LED (from green to yellow to red to blinking red). Once there is no more
+// motion the LED is turned off and the cycle is back to a few seconds in between sensor reads.
+// Button is connected on D3. Holding the button for a few seconds enters the "red zone adjust" mode (RZA).
+// By default the red zone limit is at 25cm (LED turns RED below this and starts blinking faster and faster).
+// In RZA, readings are taken for 5 seconds. In this time you have the chance to set a new red zone limit.
+// Valid new red zone readings are between the RED__LIMIT_UPPER (default 25cm) and MAX_ADJUST_DISTANCE (cm).
+// In RZA mode the BLU Led blinks fast to indicate new red limit distance. It blinks slow if the readings are invalid
+// If desired this value could be saved to EEPROM to persist if unit is turned off
+// Get the RFM69 at: https://github.com/LowPowerLab/
+// Make sure you adjust the settings in the configuration section below !!!
+// **********************************************************************************
+// Copyright Felix Rusu, LowPowerLab.com
+// Library and code by Felix Rusu - felix@lowpowerlab.com
+// **********************************************************************************
+// License
+// **********************************************************************************
+// This program is free software; you can redistribute it
+// and/or modify it under the terms of the GNU General
+// Public License as published by the Free Software
+// Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A
+// PARTICULAR PURPOSE. See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General
+// Public License along with this program.
+// If not, see .
+//
+// Licence can be viewed at
+// http://www.gnu.org/licenses/gpl-3.0.txt
+//
+// Please maintain this license information along with authorship
+// and copyright notices in any redistribution of this code
+// **********************************************************************************
+#include
+#include //get it here: https://www.github.com/lowpowerlab/rfm69
+#include //get it here: https://github.com/LowPowerLab/SPIFlash
+#include //get library from: https://github.com/lowpowerlab/lowpower
+ //writeup here: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/
+
+//*********************************************************************************************
+//************ IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
+//*********************************************************************************************
+#define NODEID 22 //unique for each node on same network
+#define NETWORKID 100 //the same on all nodes that talk to each other
+#define GATEWAYID 1
+//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
+//#define FREQUENCY RF69_433MHZ
+//#define FREQUENCY RF69_868MHZ
+#define FREQUENCY RF69_915MHZ
+#define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W!
+#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
+#define SENDLOOPS 80 //default:80 //if no message was sent for this many sleep loops/cycles, then force a send
+#define READ_SAMPLES 3
+//*********************************************************************************************
+//#define BUZZER_ENABLE //uncomment this line if you have the BUZZER soldered and want the sketch to make sounds
+#define SERIAL_EN //uncomment if you want serial debugging output
+//*********************************************************************************************
+#define SLEEP_FASTEST SLEEP_15MS
+#define SLEEP_FAST SLEEP_250MS
+#define SLEEP_SEC SLEEP_1S
+#define SLEEP_LONG SLEEP_2S
+#define SLEEP_LONGER SLEEP_4S
+#define SLEEP_LONGEST SLEEP_8S
+period_t sleepTime = SLEEP_LONGEST; //period_t is an enum type defined in the LowPower library (LowPower.h)
+//*********************************************************************************************
+#ifdef __AVR_ATmega1284P__
+ #define LED 15 // Moteino MEGAs have LEDs on D15
+ #define FLASH_SS 23
+#else
+ #define LED 9 // Moteinos have LEDs on D9
+ #define FLASH_SS 8
+#endif
+#define TRIG 6 // digital pin wired to TRIG pin of ultrasonic sensor
+#define ECHO 7 // digital pin wired to ECHO pin of ultrasonic sensor
+#define SENSOR_EN 5 // digital pin that enables power to ultrasonic sensor
+#define BUZZER 4 // digital pin that is connected to onboard buzzer
+#define MAX_DISTANCE 150 // maximum valid distance
+#define MIN_DISTANCE 2 // minimum valid distance
+#define MAX_ADJUST_DISTANCE (MAX_DISTANCE-GRN_LIMIT_UPPER) //this is the amount by which the RED_LIMIT_UPPER can by increased
+
+//
+#ifdef SERIAL_EN
+ #define SERIAL_BAUD 115200
+ #define DEBUG(input) {Serial.print(input);}
+ #define DEBUGln(input) {Serial.println(input);}
+ #define SERIALFLUSH() {Serial.flush();}
+#else
+ #define DEBUG(input);
+ #define DEBUGln(input);
+ #define SERIALFLUSH();
+#endif
+
+#define BATT_MONITOR A7 // Sense VBAT_COND signal (when powered externally should read ~3.25v/3.3v (1000-1023), when external power is cutoff it should start reading around 2.85v/3.3v * 1023 ~= 883 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier)
+#define BATT_CYCLES SENDLOOPS // read and report battery voltage every this many sleep cycles (ex 30cycles * 8sec sleep = 240sec/4min). For 450 cycles you would get ~1 hour intervals between readings
+#define BATT_FORMULA(reading) reading * 0.00322 * 1.475 // >>> fine tune this parameter to match your voltage when fully charged
+#define BATT_LOW 3.3
+
+byte sendLen;
+byte sendLoops=SENDLOOPS;
+float distance=0;
+float prevDistance=0;
+float batteryVolts = 5;
+char buff[50]; //this is just an empty string used as a buffer to place the payload for the radio
+char* BATstr="BAT:5.00v"; //longest battery voltage reading message = 9chars
+char* DISTstr="99999.99cm"; //longest distance reading message = 5chars
+void checkBattery(byte samples=10); //take 10 samples by default
+float readDistance(byte samples=1); //take 1 samples by default
+SPIFlash flash(FLASH_SS, 0xEF30); //EF30 for 4mbit Windbond chip (W25X40CL)
+RFM69 radio;
+
+void setup() {
+#ifdef SERIAL_EN
+ Serial.begin(SERIAL_BAUD); // Open serial monitor at 115200 baud to see ping results.
+#endif
+
+ radio.initialize(FREQUENCY,NODEID,NETWORKID);
+#ifdef IS_RFM69HW
+ radio.setHighPower(); //uncomment only for RFM69HW!
+#endif
+ radio.encrypt(ENCRYPTKEY);
+ //sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
+ sprintf(buff, "\nTransmitting at %d Mhz, id:%d nid:%d gid:%d", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915, NODEID, NETWORKID, GATEWAYID);
+ DEBUG(buff);
+ for (byte i=0;i 1 || diff < -1) || (--sendLoops==0)) //only send a new message if the distance has changed by at least 1cm
+ {
+ if (distance > MAX_DISTANCE || distance < MIN_DISTANCE)
+ DISTstr = "0"; // zero, out of range
+ else dtostrf(distance,3,2, DISTstr);
+
+ sprintf(buff, "%scm BAT:%s", DISTstr, BATstr);
+ sendLen = strlen(buff);
+
+ digitalWrite(LED, HIGH);
+ DEBUG(buff);
+ if (radio.sendWithRetry(GATEWAYID, buff, sendLen))
+ {
+ prevDistance = distance;
+ DEBUG(" - ACK:OK! RSSI:");
+ DEBUGln(radio.RSSI);
+ }
+ else DEBUGln(" - ACK:NOK...");
+ digitalWrite(LED, LOW);
+ sendLoops = SENDLOOPS; //reset loop counter
+ }
+ radio.sleep();
+ SERIALFLUSH();
+
+// if (radio.sendWithRetry(1, "123 TEST", 8))
+// {
+// //prevDistance = distance;
+// DEBUG(" - ACK:OK! RSSI:");
+// DEBUGln(radio.RSSI);
+// }
+// else DEBUGln(" - ACK:NOK...");
+// SERIALFLUSH();
+
+ LowPower.powerDown(sleepTime, ADC_OFF, BOD_OFF); //put microcontroller to sleep to save battery life
+}
+
+float readDistance(byte samples)
+{
+ if (samples == 0) samples = 1;
+ if (samples > 10) samples = 10;
+ digitalWrite(SENSOR_EN, HIGH);
+ //need about 60-75ms after power up before HC-SR04 will be usable, so just sleep in the meantime
+ LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF);
+ LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);
+ PING();
+ LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);
+
+ unsigned long duration = 0;
+ for (byte i=0; i 1) LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);
+ }
+ digitalWrite(SENSOR_EN, LOW);
+ return microsecondsToCentimeters(duration / samples);
+}
+
+long PING()
+{
+ digitalWrite(TRIG, LOW);
+ delayMicroseconds(2);
+ digitalWrite(TRIG, HIGH);
+ delayMicroseconds(5);
+ digitalWrite(TRIG, LOW);
+ return pulseIn(ECHO, HIGH);
+}
+
+byte cycleCount=BATT_CYCLES;
+void checkBattery(byte samples)
+{
+ if (cycleCount++ == BATT_CYCLES) //only read battery every BATT_CYCLES sleep cycles
+ {
+ unsigned int readings=0;
+ for (byte i=0; i0) delay(repeatsDelay);
+ }
+}
+#endif
+
+void Blink(byte pin)
+{
+ pinMode(pin, OUTPUT);
+ digitalWrite(pin, HIGH);
+ delay(2);
+ digitalWrite(pin, LOW);
+}
diff --git a/Examples/SonarMote/SonarMote_Parking/SonarMote_Parking.ino b/Examples/SonarMote/SonarMote_Parking/SonarMote_Parking.ino
new file mode 100644
index 0000000..f1f7718
--- /dev/null
+++ b/Examples/SonarMote/SonarMote_Parking/SonarMote_Parking.ino
@@ -0,0 +1,417 @@
+// Sample sketch for the SonarMote - Standalone parking assist with RGB LED indicator
+// This example uses the NewPing library from https://code.google.com/p/arduino-new-ping/
+// but that could be replaced by raw reading of the sonar sensor as seen in other SonarMote examples
+// More info/photos at: http://lowpowerlab.com/sonar
+// Ultrasonic sensor (HC-SR04) connected to D6 (Trig), D7 (Echo), and power enabled through D5
+// This sketch sleeps the Moteino and sensor most of the time. It wakes up every few seconds to take
+// a distance reading. If it detects an approaching object (car) it increases the sampling rate
+// and starts lighting up the LED (from green to yellow to red to blinking red). Once there is no more
+// motion the LED is turned off and the cycle is back to a few seconds in between sensor reads.
+// Button is connected on D3. Holding the button for a few seconds enters the "red zone adjust" mode (RZA).
+// By default the red zone limit is at 25cm (LED turns RED below this and starts blinking faster and faster).
+// In RZA, readings are taken for 5 seconds. In this time you have the chance to set a new red zone limit.
+// Valid new red zone readings are between the RED__LIMIT_UPPER (default 25cm) and MAX_ADJUST_DISTANCE (cm).
+// In RZA mode the BLU Led blinks fast to indicate new red limit distance. It blinks slow if the readings are invalid
+// If desired this value could be saved to EEPROM to persist if unit is turned off
+// Make sure you adjust the settings in the configuration section below !!!
+
+// **********************************************************************************
+// Copyright Felix Rusu, LowPowerLab.com
+// Library and code by Felix Rusu - felix@lowpowerlab.com
+// **********************************************************************************
+// License
+// **********************************************************************************
+// This program is free software; you can redistribute it
+// and/or modify it under the terms of the GNU General
+// Public License as published by the Free Software
+// Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A
+// PARTICULAR PURPOSE. See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General
+// Public License along with this program.
+// If not, see .
+//
+// Licence can be viewed at
+// http://www.gnu.org/licenses/gpl-3.0.txt
+//
+// Please maintain this license information along with authorship
+// and copyright notices in any redistribution of this code
+// **********************************************************************************
+#include // get this library at: https://code.google.com/p/arduino-new-ping/
+#include // get this library at: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/
+
+#define TRIG 6 // digital pin wired to TRIG pin of ultrasonic sensor
+#define ECHO 7 // digital pin wired to ECHO pin of ultrasonic sensor
+#define SENSOR_EN 5 // digital pin that enables power to ultrasonic sensor
+#define RED A0 // pin connected to red LED
+#define GRN A1 // pin connected to green LED
+#define BLU A2 // pin connected to blue LED
+#define BUTTON_INT 1 // user button on interrupt 1 (D3)
+#define BUTTON_PIN 3 // user button on interrupt 1 (D3)
+#define BUTTON_HOLD_MS 3000 // hold button this many ms before entering red zone adjust
+#define MOTEINOLED 9 // moteino onboard LED
+#define MAX_DISTANCE 220 // maximum valid distance
+#define MIN_DISTANCE 2 // minimum valid distance
+
+#define GRN_LIMIT_UPPER 180+redZoneAdjust // upper limit distance for GREEN
+#define YLW_LIMIT_UPPER 40+redZoneAdjust // upper limit distance for YELLOW
+#define RED_LIMIT_UPPER 25+redZoneAdjust // upper limit distance for RED
+
+#define MAX_ADJUST_DISTANCE (MAX_DISTANCE-GRN_LIMIT_UPPER) //this is the amount by which the RED_LIMIT_UPPER can by increased
+
+//possible states of LED status
+#define STATE_SOLID 0
+#define STATE_BLINK 1
+
+//possible states for LED color
+#define STATE_OFF 0
+#define STATE_GRN 1
+#define STATE_YLW 2
+#define STATE_RED 3
+
+byte state_LED = STATE_SOLID;
+byte state_LEDCOLOR = STATE_OFF;
+byte state_LEDONOFF = LOW;
+byte redZoneAdjust = 0; //this is adjustable via the button (press button for a few seconds, then take a reading)
+
+#define LED_RED {digitalWrite(RED,HIGH);digitalWrite(GRN,LOW);}
+#define LED_GRN {digitalWrite(RED,LOW);digitalWrite(GRN,HIGH);}
+#define LED_YLW {digitalWrite(RED,HIGH);digitalWrite(GRN,HIGH);}
+#define LED_OFF {digitalWrite(RED,LOW);digitalWrite(GRN,LOW);}
+
+#define SERIAL_EN //uncomment if you want serial debugging output
+#ifdef SERIAL_EN
+ #define SERIAL_BAUD 115200
+ #define DEBUG(input) {Serial.print(input);}
+ #define DEBUGln(input) {Serial.println(input);}
+ #define SERIALFLUSH() {Serial.flush();}
+#else
+ #define DEBUG(input);
+ #define DEBUGln(input);
+ #define SERIALFLUSH();
+#endif
+
+#define SLEEP_MINILOOP SLEEP_15MS
+#define SLEEP_LOOP SLEEP_250MS
+#define SLEEP_LONG SLEEP_2S
+#define SLEEP_LOBATT SLEEP_4S
+#define SLEEP_HIBERNATE SLEEP_8S
+
+#define BATT_MONITOR A7 // Sense VBAT_COND signal (when powered externally should read ~3.25v/3.3v (1000-1023), when external power is cutoff it should start reading around 2.85v/3.3v * 1023 ~= 883 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier)
+#define BATT_CYCLES 120 // read and report battery voltage every this many sleep cycles (ex 30cycles * 8sec sleep = 240sec/4min). For 450 cyclesyou would get ~1 hour intervals
+#define BATT_FORMULA(reading) reading * 0.00322 * 1.475 // >>> fine tune this parameter to match your voltage when fully charged
+#define BATT_LOW 3.35
+
+NewPing sensor(TRIG, ECHO, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
+float readDistance(byte samples=3); //take 3 samples by default
+void checkBattery(byte samples=10); //take 10 samples by default
+float batteryVolts = 5;
+
+void setup() {
+#ifdef SERIAL_EN
+ Serial.begin(SERIAL_BAUD); // Open serial monitor at 115200 baud to see ping results.
+#endif
+ pinMode(TRIG, OUTPUT);
+ pinMode(ECHO, INPUT);
+ pinMode(RED, OUTPUT);
+ pinMode(GRN, OUTPUT);
+ pinMode(BLU, OUTPUT);
+ pinMode(SENSOR_EN, OUTPUT);
+ digitalWrite(SENSOR_EN, LOW);
+ pinMode(BUTTON_PIN, INPUT_PULLUP);
+ attachInterrupt(BUTTON_INT, buttonInterrupt, FALLING);
+}
+
+#define FLAG_INTERRUPT 0x01
+volatile int mainEventFlags = 0;
+boolean buttonPressed = false;
+void buttonInterrupt()
+{
+ mainEventFlags |= FLAG_INTERRUPT;
+}
+
+long distance=0;
+long lastDistance=0;
+long lastSigDistance=0;
+byte loops=0;
+byte miniLoops=0;
+byte skipBlinkingLoops=5;
+unsigned long now=0;
+period_t sleepTime = SLEEP_LONG; //period_t is an enum type defined in the LowPower library (LowPower.h)
+
+void loop() {
+ if (mainEventFlags & FLAG_INTERRUPT)
+ {
+ LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_ON);
+ mainEventFlags &= ~FLAG_INTERRUPT;
+ if (!digitalRead(BUTTON_PIN)) {
+ buttonPressed=true;
+ }
+ }
+
+ if (buttonPressed)
+ {
+ detachInterrupt(BUTTON_INT);
+ DEBUGln("BUTTON PRESS!");
+ unsigned long timestamp = millis();
+ while (millis() - timestamp < BUTTON_HOLD_MS)
+ {
+ if (digitalRead(BUTTON_PIN))
+ {
+ buttonPressed = false;
+ break;
+ }
+ DEBUG('.');SERIALFLUSH();
+ LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_ON);
+ timestamp-=40;
+ }
+
+ //if it's still pressed after BUTTON_HOLD_MS then enter red zone adjust mode
+ if (buttonPressed)
+ {
+ DEBUG("STILL_PRESSED");SERIALFLUSH();
+ handleRedZoneAdjust();
+ }
+ else
+ {
+ DEBUG("ABORTED");SERIALFLUSH();
+ }
+ attachInterrupt(BUTTON_INT, buttonInterrupt, FALLING);
+ }
+
+
+ if (miniLoops>0)
+ {
+ miniLoops--;
+ sleepTime = SLEEP_MINILOOP;
+ //when looping fast we need to wake the sensor about 60-75ms before doing a reading (about 5 miniloops assuming 1 miniloop=15ms)
+ //otherwise there will be a visible delay in the LED blinking
+ if (miniLoops == 5) digitalWrite(SENSOR_EN, HIGH);
+ }
+ else if (loops > 0)
+ {
+ loops--;
+ miniLoops=16; //16 mini loops translate
+ sleepTime = SLEEP_MINILOOP;
+ }
+ else
+ //sleep longer when no significant state changes happened
+ //if battery is low, sleep even longer to try to squeeze more life
+ sleepTime = (batteryVolts > BATT_LOW ? SLEEP_LONG : SLEEP_LOBATT);
+
+ if ((loops == 0 && miniLoops == 0) || ((miniLoops % skipBlinkingLoops) == 0))
+ {
+ DEBUG('*');
+ handleLEDState();
+ }
+
+ SERIALFLUSH(); //flush any characters in the serial buffer before sleeping otherwise they get lost or garbled
+ LowPower.powerDown(sleepTime, ADC_OFF, BOD_OFF); //put microcontroller to sleep to save battery life
+ if (miniLoops > 0) { DEBUG('.');return; } //as long as we still have miniloops we skip readings
+ //only proceed to a reading every loop
+ now = millis();
+ distance = readDistance();
+
+ DEBUGln();
+ DEBUG("Read: ");
+ DEBUG(distance); // Convert ping time to distance in cm and print result (0 = outside set distance range)
+ DEBUG("cm");
+ DEBUG(" [");
+ DEBUG(millis()-now);
+ DEBUGln("]ms");
+
+ if (distance > MAX_DISTANCE || distance < MIN_DISTANCE)
+ {
+ DEBUGln("Out of range");
+ loops=0;
+ lastDistance = distance;
+ return;
+ }
+
+ if (distance < GRN_LIMIT_UPPER && distance > YLW_LIMIT_UPPER && abs(lastSigDistance-distance)>20)
+ {
+ if (distance < lastSigDistance)
+ loops=12; //begin looping fast only when object is approaching
+ lastSigDistance = distance;
+ }
+ else if (distance < YLW_LIMIT_UPPER && abs(lastSigDistance-distance)>5)
+ {
+ if (distance < lastSigDistance)
+ loops=12; //begin looping fast only when object is approaching
+ lastSigDistance = distance;
+ }
+
+ //if the looping was started, determine the state we're in
+ if (loops > 0)
+ {
+ if (distance >= YLW_LIMIT_UPPER) { state_LEDCOLOR = STATE_GRN; state_LED = STATE_SOLID; }
+ else if (distance >= RED_LIMIT_UPPER) { state_LEDCOLOR=STATE_YLW; state_LED = STATE_SOLID; }
+ else { state_LEDCOLOR=STATE_RED; state_LED = STATE_BLINK; }
+ }
+ else { state_LEDCOLOR=STATE_OFF; state_LED = STATE_SOLID; }
+
+ //adjust the blinking rate based on the distance to the object
+ if (state_LEDCOLOR==STATE_RED)
+ {
+ if (distance > RED_LIMIT_UPPER-2)
+ skipBlinkingLoops = 8;
+ else if (distance > RED_LIMIT_UPPER-6)
+ skipBlinkingLoops = 6;
+ else if (lastDistance > RED_LIMIT_UPPER-10)
+ skipBlinkingLoops = 4;
+ else if (lastDistance > RED_LIMIT_UPPER-14)
+ skipBlinkingLoops = 2;
+ else
+ {
+ skipBlinkingLoops = 1;
+ state_LED = STATE_SOLID;
+ }
+ }
+ else skipBlinkingLoops = 1;
+ lastDistance = distance; //remember the last reading
+ checkBattery();
+ if (batteryVolts < BATT_LOW)
+ Blink(BLU);
+ else Blink(MOTEINOLED);
+ DEBUG("Batt: ");
+ DEBUG(batteryVolts);
+ DEBUGln("v");
+}
+
+//reads the ultrasonic sensor, takes 3 samples by default
+float uS;
+float readDistance(byte samples)
+{
+ uS = 0;
+ if (loops == 0 && miniLoops == 0)
+ {
+ digitalWrite(SENSOR_EN, HIGH);
+ //need about 60-75ms after power up before HC-SR04 will be usable, so just sleep in the meantime
+ LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF);
+ LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);
+ }
+
+ sensor.ping();
+ for (byte i=0; i1) delay(4); //need a short delay between samples
+ }
+ digitalWrite(SENSOR_EN, LOW);
+ return (uS / samples) / US_ROUNDTRIP_CM;
+}
+
+
+////reads the ultrasonic sensor, takes 3 samples by default
+//float readDistance(byte samples)
+//{
+// long duration, distance;
+// digitalWrite(SENSOR_EN, HIGH);
+// delay(75);
+//
+// digitalWrite(TRIG, LOW); // Added this line
+// delayMicroseconds(2); // Added this line
+// digitalWrite(TRIG, HIGH);
+// delayMicroseconds(10); // Added this line
+// digitalWrite(TRIG, LOW);
+// pulseIn(ECHO, HIGH);
+//
+// digitalWrite(TRIG, LOW); // Added this line
+// delayMicroseconds(2); // Added this line
+// digitalWrite(TRIG, HIGH);
+// delayMicroseconds(10); // Added this line
+// digitalWrite(TRIG, LOW);
+// duration = pulseIn(ECHO, HIGH);
+// distance = (duration/2) / 29.1;
+// digitalWrite(SENSOR_EN, LOW);
+// return distance;
+//}
+
+//handles the status and color of the LED depending what state we are in
+void handleLEDState()
+{
+ switch(state_LEDCOLOR)
+ {
+ case STATE_OFF: LED_OFF; break;
+ case STATE_GRN: LED_GRN; break;
+ case STATE_YLW: LED_YLW; break;
+ case STATE_RED:
+ if (state_LED == STATE_BLINK)
+ {
+ if (state_LEDONOFF == HIGH)
+ {
+ LED_OFF;
+ state_LEDONOFF = LOW;
+ }
+ else
+ {
+ LED_RED;
+ state_LEDONOFF = HIGH;
+ }
+ }
+ else LED_RED;
+ break;
+ }
+}
+
+void Blink(byte pin)
+{
+ pinMode(pin, OUTPUT);
+ digitalWrite(pin, HIGH);
+ delay(2);
+ digitalWrite(pin, LOW);
+}
+
+byte cycleCount=BATT_CYCLES;
+void checkBattery(byte samples)
+{
+ if (cycleCount++ == BATT_CYCLES) //only read battery every BATT_CYCLES sleep cycles
+ {
+ unsigned int readings=0;
+ for (byte i=0; i MAX_ADJUST_DISTANCE + RED_LIMIT_UPPER-redZoneAdjust)
+ delay(300);
+ else if (distance <= RED_LIMIT_UPPER-redZoneAdjust)
+ state = HIGH; //keep LED on
+ else
+ delay (distance);
+
+ DEBUG(distance);DEBUGln("cm");SERIALFLUSH();
+ Blink(MOTEINOLED);
+ }
+
+ digitalWrite(BLU, LOW); //turn LED off
+ if (distance > RED_LIMIT_UPPER-redZoneAdjust && distance <= MAX_ADJUST_DISTANCE + RED_LIMIT_UPPER-redZoneAdjust)
+ {
+ redZoneAdjust = distance - RED_LIMIT_UPPER - redZoneAdjust;
+ DEBUG("New RED_ZONE_SHIFT = "); DEBUGln(redZoneAdjust);SERIALFLUSH();
+ }
+}
diff --git a/Examples/SonarMote/SonarMote_Parking_Sound_OLED/SonarMote_Parking_Sound_OLED.ino b/Examples/SonarMote/SonarMote_Parking_Sound_OLED/SonarMote_Parking_Sound_OLED.ino
new file mode 100644
index 0000000..43f41b7
--- /dev/null
+++ b/Examples/SonarMote/SonarMote_Parking_Sound_OLED/SonarMote_Parking_Sound_OLED.ino
@@ -0,0 +1,511 @@
+// Sample sketch for the SonarMote - Standalone parking assist with RGB LED indicator, piezo buzzer and OLED display
+// This example uses the NewPing library from https://code.google.com/p/arduino-new-ping/
+// but that could be replaced by raw reading of the sonar sensor as seen in other SonarMote examples
+// More info/photos at: http://lowpowerlab.com/sonar
+// Ultrasonic sensor (HC-SR04) connected to D6 (Trig), D7 (Echo), and power enabled through D5
+// This sketch sleeps the Moteino and sensor most of the time. It wakes up every few seconds to take
+// a distance reading. If it detects an approaching object (car) it increases the sampling rate
+// and starts lighting up the LED (from green to yellow to red to blinking red). Once there is no more
+// motion the LED is turned off and the cycle is back to a few seconds in between sensor reads.
+// Button is connected on D3. Holding the button for a few seconds enters the "red zone adjust" mode (RZA).
+// By default the red zone limit is at 25cm (LED turns RED below this and starts blinking faster and faster).
+// In RZA, readings are taken for 5 seconds. In this time you have the chance to set a new red zone limit.
+// Valid new red zone readings are between the RED__LIMIT_UPPER (default 25cm) and MAX_ADJUST_DISTANCE (cm).
+// In RZA mode the BLU Led blinks fast to indicate new red limit distance. It blinks slow if the readings are invalid
+// If desired this value could be saved to EEPROM to persist if unit is turned off
+// Make sure you adjust the settings in the configuration section below !!!
+
+// **********************************************************************************
+// Copyright Felix Rusu, LowPowerLab.com
+// Library and code by Felix Rusu - felix@lowpowerlab.com
+// **********************************************************************************
+// License
+// **********************************************************************************
+// This program is free software; you can redistribute it
+// and/or modify it under the terms of the GNU General
+// Public License as published by the Free Software
+// Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A
+// PARTICULAR PURPOSE. See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General
+// Public License along with this program.
+// If not, see .
+//
+// Licence can be viewed at
+// http://www.gnu.org/licenses/gpl-3.0.txt
+//
+// Please maintain this license information along with authorship
+// and copyright notices in any redistribution of this code
+// **********************************************************************************
+#include // get this library at: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/
+//#define BUZZER_ENABLE //uncomment this line if you have the BUZZER soldered and want the sketch to make sounds
+//#define OLED_ENABLE //uncomment this line if you have an OLED attached on the SonarMote and want to see the distance printed on it
+ //the OLED drawing will cause a visible delay in the LED blinking, nothing much to do about it without complicating the sketch a lot more
+
+#ifdef OLED_ENABLE
+ #include "U8glib.h" //get library from: https://code.google.com/p/u8glib/
+#endif
+
+#ifdef __AVR_ATmega1284P__
+ #define LED 15 // Moteino MEGAs have LEDs on D15
+#else
+ #define LED 9 // Moteinos have LEDs on D9
+#endif
+
+#define TRIG 6 // digital pin wired to TRIG pin of ultrasonic sensor
+#define ECHO 7 // digital pin wired to ECHO pin of ultrasonic sensor
+#define SENSOR_EN 5 // digital pin that enables power to ultrasonic sensor
+#define RED A0 // pin connected to red LED
+#define GRN A1 // pin connected to green LED
+#define BLU A2 // pin connected to blue LED
+#define BUZZER 4
+#define BUTTON_INT 1 // user button on interrupt 1 (D3)
+#define BUTTON_PIN 3 // user button on interrupt 1 (D3)
+#define BUTTON_HOLD_MS 3000 // hold button this many ms before entering red zone adjust
+#define MAX_DISTANCE 220 // maximum valid distance
+#define MIN_DISTANCE 2 // minimum valid distance
+
+#define GRN_LIMIT_UPPER 180+redZoneAdjust // upper limit distance for GREEN
+#define YLW_LIMIT_UPPER 40+redZoneAdjust // upper limit distance for YELLOW
+#define RED_LIMIT_UPPER 25+redZoneAdjust // upper limit distance for RED
+
+#define MAX_ADJUST_DISTANCE (MAX_DISTANCE-GRN_LIMIT_UPPER) //this is the amount by which the RED_LIMIT_UPPER can by increased
+
+//possible states of LED status
+#define STATE_SOLID 0
+#define STATE_BLINK 1
+
+//possible states for LED color
+#define STATE_OFF 0
+#define STATE_GRN 1
+#define STATE_YLW 2
+#define STATE_RED 3
+
+byte state_LED = STATE_SOLID;
+byte state_LEDCOLOR = STATE_OFF;
+byte state_LEDONOFF = LOW;
+byte redZoneAdjust = 0; //this is adjustable via the button (press button for a few seconds, then take a reading)
+
+#define LED_RED {digitalWrite(RED,HIGH);digitalWrite(GRN,LOW);}
+#define LED_GRN {digitalWrite(RED,LOW);digitalWrite(GRN,HIGH);}
+#define LED_YLW {digitalWrite(RED,HIGH);digitalWrite(GRN,HIGH);}
+#define LED_OFF {digitalWrite(RED,LOW);digitalWrite(GRN,LOW);}
+
+#define SERIAL_EN //uncomment if you want serial debugging output
+#ifdef SERIAL_EN
+ #define SERIAL_BAUD 115200
+ #define DEBUG(input) {Serial.print(input);}
+ #define DEBUGln(input) {Serial.println(input);}
+ #define SERIALFLUSH() {Serial.flush();}
+#else
+ #define DEBUG(input);
+ #define DEBUGln(input);
+ #define SERIALFLUSH();
+#endif
+
+#define SLEEP_MINILOOP SLEEP_15MS
+#define SLEEP_LOOP SLEEP_250MS
+#define SLEEP_LONG SLEEP_2S
+#define SLEEP_LOBATT SLEEP_4S
+#define SLEEP_HIBERNATE SLEEP_8S
+
+#define BATT_MONITOR A7 // Sense VBAT_COND signal (when powered externally should read ~3.25v/3.3v (1000-1023), when external power is cutoff it should start reading around 2.85v/3.3v * 1023 ~= 883 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier)
+#define BATT_CYCLES 120 // read and report battery voltage every this many sleep cycles (ex 30cycles * 8sec sleep = 240sec/4min). For 450 cyclesyou would get ~1 hour intervals
+#define BATT_FORMULA(reading) reading * 0.00322 * 1.475 // >>> fine tune this parameter to match your voltage when fully charged
+#define BATT_LOW 3.35
+
+#ifdef OLED_ENABLE
+ U8GLIB_SSD1306_128X64 OLED(U8G_I2C_OPT_NONE); // I2C / TWI SSD1306 OLED 128x64
+#endif
+void checkBattery(byte samples=10); //take 10 samples by default
+float batteryVolts = 5;
+char buff[50];
+
+void setup() {
+#ifdef SERIAL_EN
+ Serial.begin(SERIAL_BAUD); // Open serial monitor at 115200 baud to see ping results.
+#endif
+ pinMode(TRIG, OUTPUT);
+ pinMode(ECHO, INPUT);
+ pinMode(RED, OUTPUT);
+ pinMode(GRN, OUTPUT);
+ pinMode(BLU, OUTPUT);
+ pinMode(SENSOR_EN, OUTPUT);
+ pinMode(BUZZER, OUTPUT);
+ digitalWrite(SENSOR_EN, LOW);
+ pinMode(BUTTON_PIN, INPUT_PULLUP);
+ attachInterrupt(BUTTON_INT, buttonInterrupt, FALLING);
+
+#ifdef OLED_ENABLE
+ OLED.setRot180(); //flip screen
+ // assign default color value
+ if (OLED.getMode() == U8G_MODE_R3G3B2 )
+ OLED.setColorIndex(255); // white
+ else if (OLED.getMode() == U8G_MODE_GRAY2BIT)
+ OLED.setColorIndex(3); // max intensity
+ else if (OLED.getMode() == U8G_MODE_BW)
+ OLED.setColorIndex(1); // pixel on
+ else if (OLED.getMode() == U8G_MODE_HICOLOR)
+ OLED.setHiColorByRGB(255,255,255);
+ OLED.begin();
+
+ OLED.firstPage();
+ OLED.setFont(u8g_font_unifont);
+ do {
+ OLED.drawStr(0, 10, "SonarMote");
+ } while(OLED.nextPage());
+#endif
+
+#ifdef BUZZER_ENABLE
+ buzzer(50,2,100);
+#endif
+
+ readDistance(); //first reading seems to always be low
+}
+
+#define FLAG_INTERRUPT 0x01
+volatile int mainEventFlags = 0;
+boolean buttonPressed = false;
+void buttonInterrupt()
+{
+ mainEventFlags |= FLAG_INTERRUPT;
+}
+
+long distance=0;
+long lastDistance=0;
+long lastSigDistance=0;
+byte loops=0;
+byte miniLoops=0;
+byte skipBlinkingLoops=5;
+unsigned long now=0;
+period_t sleepTime = SLEEP_LONG; //period_t is an enum type defined in the LowPower library (LowPower.h)
+
+void loop() {
+ if (mainEventFlags & FLAG_INTERRUPT)
+ {
+ LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_ON);
+ mainEventFlags &= ~FLAG_INTERRUPT;
+ if (!digitalRead(BUTTON_PIN)) {
+ buttonPressed=true;
+ }
+ }
+
+ if (buttonPressed)
+ {
+ detachInterrupt(BUTTON_INT);
+ DEBUGln("BUTTON PRESS!");
+ unsigned long timestamp = millis();
+ while (millis() - timestamp < BUTTON_HOLD_MS)
+ {
+ if (digitalRead(BUTTON_PIN))
+ {
+ buttonPressed = false;
+ break;
+ }
+ DEBUG('.');SERIALFLUSH();
+ LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_ON);
+ timestamp-=40;
+ }
+
+ //if it's still pressed after BUTTON_HOLD_MS then enter red zone adjust mode
+ if (buttonPressed)
+ {
+ DEBUG("STILL_PRESSED");SERIALFLUSH();
+ handleRedZoneAdjust();
+ }
+ else
+ {
+ DEBUG("ABORTED");SERIALFLUSH();
+ }
+ attachInterrupt(BUTTON_INT, buttonInterrupt, FALLING);
+ }
+
+ if (miniLoops>0)
+ {
+ miniLoops--; //miniloops starts at
+ sleepTime = SLEEP_MINILOOP;
+ //EARLY SENSOR WAKEUP
+ //When looping fast we need to wake the sensor about 60-75ms before doing a reading (about 5 miniloops assuming 1 miniloop=15ms)
+ //otherwise there will be a visible delay in the LED blinking
+ if (miniLoops == 6) digitalWrite(SENSOR_EN, HIGH);
+ else if (miniLoops == 1) sacrificialPing(); //need 5 miniloops (75ms) between wakeup and dummy reading and another 15ms (1 miniloop) to real reading
+ //reading will happen when miniLoops==0
+ }
+ else if (loops > 0)
+ {
+ loops--;
+ miniLoops=16; //16 "miniloops" form 1 "loop" (~240ms)
+ sleepTime = SLEEP_MINILOOP;
+ }
+ else
+ //sleep longer when no significant state changes happened
+ //if battery is low, sleep even longer to try to squeeze more life
+ sleepTime = (batteryVolts > BATT_LOW ? SLEEP_LONG : SLEEP_LOBATT);
+
+ if ((loops == 0 && miniLoops == 0) || ((miniLoops % skipBlinkingLoops) == 0))
+ {
+ DEBUG('*');
+ handleLEDState();
+ }
+
+ SERIALFLUSH(); //flush any characters in the serial buffer before sleeping otherwise they get lost or garbled
+ LowPower.powerDown(sleepTime, ADC_OFF, BOD_OFF); //put microcontroller to sleep to save battery life
+ if (miniLoops > 0) { DEBUG('.');return; } //as long as we still have miniloops we skip readings
+ //only proceed to a reading every loop
+ now = millis();
+ distance = readDistance();
+ byte d = millis()-now;
+#ifdef OLED_ENABLE
+ draw(distance);
+#endif
+
+ DEBUG("Read: ");
+ DEBUG(distance); // Convert ping time to distance in cm and print result (0 = outside set distance range)
+ DEBUG("cm");
+ DEBUG(" [");
+ DEBUG(d);
+ DEBUGln("]ms");
+
+ if (distance > MAX_DISTANCE || distance < MIN_DISTANCE)
+ {
+ DEBUGln("Out of range");
+ loops=0;
+ lastDistance = distance;
+ return;
+ }
+
+ if (distance < GRN_LIMIT_UPPER && distance > YLW_LIMIT_UPPER && abs(lastSigDistance-distance)>20)
+ {
+ if (distance < lastSigDistance)
+ loops=12; //begin looping fast only when object is approaching
+ lastSigDistance = distance;
+ }
+ else if (distance < YLW_LIMIT_UPPER && abs(lastSigDistance-distance)>5)
+ {
+ if (distance < lastSigDistance)
+ loops=12; //begin looping fast only when object is approaching
+ lastSigDistance = distance;
+ }
+
+ //if the looping was started, determine the state we're in
+ if (loops > 0)
+ {
+ if (distance >= YLW_LIMIT_UPPER) { state_LEDCOLOR = STATE_GRN; state_LED = STATE_SOLID; }
+ else if (distance >= RED_LIMIT_UPPER) { state_LEDCOLOR=STATE_YLW; state_LED = STATE_SOLID; }
+ else { state_LEDCOLOR=STATE_RED; state_LED = STATE_BLINK; }
+ }
+ else { state_LEDCOLOR=STATE_OFF; state_LED = STATE_SOLID; }
+
+ //adjust the blinking rate based on the distance to the object
+ if (state_LEDCOLOR==STATE_RED)
+ {
+ if (distance > RED_LIMIT_UPPER-2)
+ skipBlinkingLoops = 8;
+ else if (distance > RED_LIMIT_UPPER-6)
+ skipBlinkingLoops = 6;
+ else if (lastDistance > RED_LIMIT_UPPER-10)
+ skipBlinkingLoops = 4;
+ else if (lastDistance > RED_LIMIT_UPPER-14)
+ skipBlinkingLoops = 2;
+ else
+ {
+ skipBlinkingLoops = 1;
+ state_LED = STATE_SOLID;
+ }
+ }
+ else skipBlinkingLoops = 1;
+ lastDistance = distance; //remember the last reading
+ checkBattery();
+ if (batteryVolts < BATT_LOW)
+ Blink(BLU);
+ else Blink(LED);
+ DEBUG("Batt: ");
+ DEBUG(batteryVolts);
+ DEBUGln("v");
+}
+
+float readDistance()
+{
+ //To save battery we need to sleep the HC-SR04 sonar sensor in between readings.
+ //However to get valid readings it requires special waking up and delay
+ //It needs to be powered up for ~75ms, then a dummy reading has to be made which is typically bogus
+ //Then another 15ms needs to pass before doing the real reading
+ //Because the main loop sleeps between readings and we want to avoid visible delays in the LED blinking
+ // we need to wake up the sensor in the main loop, look for "EARLY SENSOR WAKEUP".
+ // When looping fast in the main loop (aka minilooping, to allow fast LED blinking)
+ // each "miniloop" is about 15ms of sleep time. So we should wake up the sensor 5 miniloops before we do the reading
+ // and do the sacrificial dummy reading 1 miniloop before the real reading. See the "EARLY SENSOR WAKEUP" code in the main loop.
+
+ //when not looping fast in the main loop, just do the special sensor wakeup here
+ //first enable sensor power and sleep MCU while sensor settles (needs)75ms
+ if (loops == 0 && miniLoops == 0)
+ {
+ digitalWrite(SENSOR_EN, HIGH);
+ //need about 60-75ms after power up before HC-SR04 will be usable, so just sleep in the meantime
+ LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF);
+ LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);
+ // do a dummy reading first and wait another 15ms for the real reading
+ sacrificialPing();
+ LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);
+ }
+
+ // Now do the real reading
+ // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
+ // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
+ digitalWrite(TRIG, LOW);
+ delayMicroseconds(2);
+ digitalWrite(TRIG, HIGH);
+ delayMicroseconds(5);
+ digitalWrite(TRIG, LOW);
+ // The same pin is used to read the signal from the PING))): a HIGH
+ // pulse whose duration is the time (in microseconds) from the sending
+ // of the ping to the reception of its echo off of an object.
+ long duration = pulseIn(ECHO, HIGH);
+ digitalWrite(SENSOR_EN, LOW);
+ return microsecondsToCentimeters(duration);
+}
+
+void sacrificialPing()
+{
+ digitalWrite(TRIG, LOW);
+ delayMicroseconds(2);
+ digitalWrite(TRIG, HIGH);
+ delayMicroseconds(5);
+ digitalWrite(TRIG, LOW);
+ pulseIn(ECHO, HIGH);
+}
+
+//handles the status and color of the LED depending what state we are in
+void handleLEDState()
+{
+ switch(state_LEDCOLOR)
+ {
+ case STATE_OFF: LED_OFF; break;
+ case STATE_GRN: LED_GRN; break;
+ case STATE_YLW: LED_YLW; break;
+ case STATE_RED:
+ if (state_LED == STATE_BLINK)
+ {
+ if (state_LEDONOFF == HIGH)
+ {
+ LED_OFF;
+ state_LEDONOFF = LOW;
+ }
+ else
+ {
+ LED_RED;
+ state_LEDONOFF = HIGH;
+#ifdef BUZZER_ENABLE
+ buzzer(skipBlinkingLoops,0,0);
+#endif
+ }
+ }
+ else LED_RED;
+ break;
+ }
+}
+
+void Blink(byte pin)
+{
+ pinMode(pin, OUTPUT);
+ digitalWrite(pin, HIGH);
+ delay(2);
+ digitalWrite(pin, LOW);
+}
+
+byte cycleCount=BATT_CYCLES;
+void checkBattery(byte samples)
+{
+ if (cycleCount++ == BATT_CYCLES) //only read battery every BATT_CYCLES sleep cycles
+ {
+ unsigned int readings=0;
+ for (byte i=0; i MAX_ADJUST_DISTANCE + RED_LIMIT_UPPER-redZoneAdjust)
+ delay(300);
+ else if (distance <= RED_LIMIT_UPPER-redZoneAdjust)
+ state = HIGH; //keep LED on
+ else
+ delay (distance);
+
+ DEBUG(distance);DEBUGln("cm");SERIALFLUSH();
+ Blink(LED);
+ }
+
+ digitalWrite(BLU, LOW); //turn LED off
+ if (distance > RED_LIMIT_UPPER-redZoneAdjust && distance <= MAX_ADJUST_DISTANCE + RED_LIMIT_UPPER-redZoneAdjust)
+ {
+ redZoneAdjust = distance - RED_LIMIT_UPPER - redZoneAdjust;
+ DEBUG("New RED_ZONE_SHIFT = "); DEBUGln(redZoneAdjust);SERIALFLUSH();
+ }
+}
+
+float microsecondsToInches(long microseconds)
+{
+ // According to Parallax's datasheet for the PING))), there are
+ // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
+ // second). This gives the distance travelled by the ping, outbound
+ // and return, so we divide by 2 to get the distance of the obstacle.
+ // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
+ return microseconds / 74.0 / 2.0f;
+}
+
+float microsecondsToCentimeters(long microseconds)
+{
+ // The speed of sound is 340 m/s or 29 microseconds per centimeter.
+ // The ping travels out and back, so to find the distance of the
+ // object we take half of the distance travelled.
+ return (float)microseconds / 29.0f / 2.0f;
+}
+
+#ifdef OLED_ENABLE
+void draw(byte distance) {
+ OLED.firstPage();
+ OLED.setFont(u8g_font_unifont);
+ sprintf(buff, "Reading: %dcm", distance);
+
+ do {
+ OLED.drawStr(0, 10, buff);
+ } while(OLED.nextPage());
+}
+#endif
+
+#ifdef BUZZER_ENABLE
+void buzzer(byte soundTime, byte repeats, byte repeatsDelay)
+{
+ for (byte i=0;i<=repeats;i++)
+ {
+ tone(BUZZER, 4500); //4500hz makes a nice audible sound from a 3.3v Moteino digital pin
+ delay(soundTime);
+ noTone(BUZZER);
+ if (repeats>0) delay(repeatsDelay);
+ }
+}
+#endif