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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
| #include <LiquidCrystal_I2C.h> // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2); // use LiquidCrystal_I2C lcd(0x3f, 20, 4); for a 20x4
#define USE_SW_SERIAL
#ifdef USE_SW_SERIAL
#include <SoftwareSerial.h>
const uint8_t RXPin = 2; // the arduino pin on which to receive serial data from your GPS
const uint8_t TXPin = 3; // the arduino pin on which to transmit serial data to your GPS
SoftwareSerial gpsSerial(RXPin, TXPin);
#else
#define gpsSerial Serial1 // otherwise define here which Hardware Serial Port to use
#endif
// define your GPS baud rate (9600 is the default for GPS Neo 7M)
const uint32_t GPSBaud = 9600;
// The pins setting the distance threshold
const uint8_t pinDistance1 = 4;
const uint8_t pinDistance2 = 5;
const uint16_t distanceThreshold[3] = {20, 30, 50}; // define the 3 thresholds in meters
// the pin triggering the alert. HIGH by default, turns LOW when distance is above threshold
const uint8_t alertPin = 9;
// the pin for the sound (a simple piezo) pin --- (piezo +) [piezo] (piezo -) ---- GND
const uint8_t piezoPin = 10;
// --------------------------------------------------------------
#include <TinyGPS++.h> // download from https://github.com/mikalhart/TinyGPSPlus
TinyGPSPlus gps;
double recordedLatitude;
double recordedLongitude;
double HaversineDistance(const double lat1, const double long1, const double lat2, const double long2)
{
double latRad1 = radians(lat1);
double latRad2 = radians(lat2);
double lonRad1 = radians(long1);
double lonRad2 = radians(long2);
double half_diffLa = (latRad2 - latRad1) / 2.0;
double s_half_diffLa = sin(half_diffLa);
double half_doffLo = (lonRad2 - lonRad1) / 2.0;
double s_half_doffLo = sin(half_doffLo);
double computation = asin(sqrt(s_half_diffLa * s_half_diffLa + cos(latRad1) * cos(latRad2) * s_half_doffLo * s_half_doffLo));
return 2.0 * 6372795.0 * computation;
}
bool feedGPS()
{
bool gotFix = false;
while (gpsSerial.available() > 0)
if (gps.encode(gpsSerial.read())) {
gotFix = true;
break;
}
return gotFix;
}
void updateLcdGPS()
{
static double previousLat = -1, previousLong = -1;
double lcdLat = gps.location.lat();
double lcdLong = gps.location.lng();
char tmpBuffer[16];
Serial.print(F("Position: ")); Serial.print(lcdLat, 6);
Serial.write(','); Serial.println(lcdLong, 6);
if (lcdLat != previousLat) {
dtostrf(lcdLat, 10, 6, tmpBuffer);
lcd.setCursor(0, 0);
lcd.print(tmpBuffer);
previousLat = lcdLat;
}
if (lcdLong != previousLong) {
dtostrf(lcdLong, 10, 6, tmpBuffer);
lcd.setCursor(0, 1);
lcd.print(tmpBuffer);
previousLong = lcdLong;
}
}
void updateLcdThreshold(uint16_t t)
{
static uint16_t previousThreshold = 1000;
char tmpBuffer[16];
if (t != previousThreshold) {
dtostrf(t, 3, 0, tmpBuffer);
lcd.setCursor(11, 0);
lcd.print(F("S"));
lcd.print(tmpBuffer);
lcd.write('m');
Serial.print(F("Alert @")); Serial.print(t); Serial.println(F(" m"));
previousThreshold = t;
}
}
void updateLcdDistance(double distance)
{
static uint16_t previousDistance = 10000;
char tmpBuffer[16];
if (((uint16_t) distance) != previousDistance) {
Serial.print(F("Distance from origin: ")); Serial.println(distance);
dtostrf(distance, 3, 0, tmpBuffer);
lcd.setCursor(11, 1);
lcd.print(F("D"));
lcd.print(tmpBuffer);
lcd.write('m');
previousDistance = distance;
}
}
uint8_t thresholdIndex()
{
uint8_t dipSwitchByte = (digitalRead(pinDistance2) << 1) | digitalRead(pinDistance1);
switch (dipSwitchByte) {
case 0b10: return 1; // distanceThreshold[1] = 30m
case 0b01: return 2; // distanceThreshold[2] = 50m
}
return 0; // distanceThreshold[0] = 20m
}
void checkThreshold()
{
static uint8_t oldIndex = 255;
uint8_t tidx = thresholdIndex();
if (tidx != oldIndex) {
updateLcdThreshold(distanceThreshold[tidx]);
for (uint8_t i = 0; i < tidx + 1; i++) { // 1 beep for Threshold 0, 2 beeps for Threshold 1 and 3 beeps for Threshold 2
tone(piezoPin, 2000, 100);
delay(150);
}
oldIndex = tidx;
}
}
void checkPosition()
{
static bool firstFix = true;
static bool alert = false;
if (gps.location.isValid()) {
uint8_t tidx = thresholdIndex();
if (firstFix) {
recordedLatitude = gps.location.lat();
recordedLongitude = gps.location.lng();
Serial.print(F("Recorded "));
updateLcdGPS();
updateLcdDistance(0);
tone(piezoPin, 1000, 200);
delay(210);
tone(piezoPin, 1000, 200);
firstFix = false;
} else {
// we already recorded our start position
double distance = HaversineDistance(gps.location.lat(), gps.location.lng(), recordedLatitude, recordedLongitude);
updateLcdGPS();
updateLcdDistance(distance);
if (distance >= distanceThreshold[tidx]) {
if (!alert) {
digitalWrite(alertPin, LOW);
alert = true;
for (uint8_t i = 0; i < tidx + 1; i++) { // 1 beep for Threshold 0, 2 beeps for Threshold 1 and 3 beeps for Threshold 2
tone(piezoPin, 300, 100);
delay(150);
tone(piezoPin, 100, 100);
delay(150);
}
Serial.print(F("Distance alert = ")); Serial.println(distance);
}
} else {
if (alert) {
digitalWrite(alertPin, HIGH);
tone(piezoPin, 300, 100);
delay(120);
tone(piezoPin, 600, 100);
Serial.print(F("Distance back in range : ")); Serial.println(distance);
}
alert = false;
}
}
}
}
void setup() {
pinMode(pinDistance1, INPUT_PULLUP);
pinMode(pinDistance2, INPUT_PULLUP);
pinMode(alertPin, OUTPUT);
pinMode(piezoPin, OUTPUT);
digitalWrite(alertPin, HIGH); // will go low in case of Alert
Serial.begin(115200);
gpsSerial.begin(GPSBaud);
lcd.begin();
lcd.backlight();
lcd.print(F(" GPS ALERT V2.0"));
delay(1000);
lcd.clear();
}
void loop() {
checkThreshold();
if (feedGPS()) checkPosition();
} |