- Have to fix an issue with the log file time stamp
- Have to add in logic to sleep when speed ! >= 1
- Have to slow down the read (it's every .5 seconds right now)
- Bonus: add logic to put the device to sleep for 5 min when speed !>=.5, to save on battery power
After that, my next addition will be an APRS shield so I can start communicating geo-loc over radio. That is the base bundle for the balloon instrument pack.
Code:
// TrunkTracker sketch combines code from GPSTest_RMC and SD_GPSLogger
// Throw your Arduino in the trunk to see where your teens really go
// and how fast they really drive.
#include "Arduino.h"
//#include "GPSconfig.h"
#include <avr/sleep.h>
#include <SD.h>
// If running Arduino < 1.0, add references to WProgram.h and NewSoftSerial.h
#include "SoftwareSerial.h"
// Set this to 0 when in production; all serial output will be diasabled
#define DEBUG 0
// My shield is wired with RX/TX swapped
//SoftwareSerial mySerial = SoftwareSerial(2, 3);
SoftwareSerial mySerial = SoftwareSerial(3, 2);
// power saving modes
#define SLEEPDELAY 0 /* power-down time in seconds. Max 65535. Ignored if TURNOFFGPS == 0 */
#define TURNOFFGPS 0 /* set to 1 to enable powerdown of arduino and GPS. Ignored if SLEEPDELAY == 0 */
#define LOG_RMC_FIXONLY 0 /* set to 1 to only log to SD when GPS has a fix */
// Set up pins used
#define powerpin 4 // Use pin 4 to control power to GPS
#define led1Pin 5
#define led2Pin 6
// Set GPSRATE to 4800 for my GPS
#define GPSRATE 4800
// Create a buffer of 90 to store GPS data. Usually about 80 chars so 90 is plenty
#define BUFFSIZE 90
// Create an int for iterating
uint8_t i;
// Create instance of logfile
File logFile;
// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 10;
// Global variables
char buffer[BUFFSIZE]; // string buffer for the sentence
char *parseptr; // a character pointer for parsing the GPS sentence
char buffidx; // an indexer into the buffer
bool fix = false; // current fix on data
bool gotGPRMC = false; // true if current data is a GPRMC string
// The time date, location, data, etc.
uint8_t hour, minute, second, year, month, date;
uint32_t latitude, longitude;
uint8_t groundspeed, trackangle;
char latdir, longdir;
char validity;
// Setup the sketch
void setup()
{
// First set up GPS comms
if (powerpin)
{
pinMode(powerpin, OUTPUT);
}
// Use the pin 13 LED as an indicator
pinMode(13, OUTPUT);
// connect to the serial terminal at 9600 baud
Serial.begin(9600);
// connect to the GPS at the appropriate rate
// IF THIS IS WRONG for your GPS, change it above
mySerial.begin(GPSRATE);
// print title with ending line break
if (DEBUG)
Serial.println("GPS Parser started");
digitalWrite(powerpin, LOW); //pull low to turn on
// Now set up SD for logging
// This code lifted from "Datalogger" sample sketch
if (DEBUG)
Serial.println("Initializing SD card...");
// make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card init. failed!");
error(1);
}
// Now create a unique file
strcpy(buffer, "GPSLOG00.TXT");
for (i = 0; i < 100; i++) {
// Keep iterating till you find unique file name
// Create if does not exist, do not open existing, write, sync after write
buffer[6] = '0' + i/10;
buffer[7] = '0' + i%10;
if (! SD.exists(buffer)) {
break;
}
}
// Now open the file just created
logFile = SD.open(buffer, FILE_WRITE);
if( ! logFile ) {
if (DEBUG)
{
Serial.print("Couldnt create "); Serial.println(buffer);
}
error(3);
}
if (DEBUG)
{
Serial.print("Writing to "); Serial.println(buffer);
}
// Done opening log file
}
uint32_t parsedecimal(char *str)
{
uint32_t d = 0;
while (str[0] != 0)
{
if ((str[0] > '9') || (str[0] < '0'))
return d;
d *= 10;
d += str[0] - '0';
str++;
}
return d;
}
// Read line from GPS unit
void readline(void)
{
if (DEBUG)
Serial.print("Input from GPS: ");
char c;
buffidx = 0; // start at beginning of line
while (1)
{
c = mySerial.read();
if (c == -1)
continue;
// Output status to screen
if (DEBUG)
Serial.print(c);
if (c == '\n')
continue;
// if we're nearing the end of buffer, terminate
if ((buffidx == BUFFSIZE-1) || (c == '\r'))
{
buffer[buffidx] = 0;
return;
}
// Write each char into buffer
buffer[buffidx++] = c;
}
}
// Main program - keep doing this over and over
void loop()
{
uint32_t tmp;
if (DEBUG)
Serial.print("\n\rRead: ");
readline();
// Check if $GPRMC (global positioning fixed data)
if (strncmp(buffer, "$GPRMC",6) == 0)
{
// Set gotGPRMC
gotGPRMC = true;
//hhmmss time data
parseptr = buffer+7;
tmp = parsedecimal(parseptr);
hour = tmp / 10000;
minute = (tmp / 100) % 100;
second = tmp %100;
parseptr = strchr(parseptr, ',') + 1;
validity = parseptr[0];
parseptr +=2;
/*
// Break out if "validity" = "V"
if(validity = 'V')
{
if(DEBUG)
Serial.print("\nGPS navigation error. Trying again...");
return;
}
*/
// grab latitude & longitude data
// latitude
latitude = parsedecimal(parseptr);
if (latitude != 0)
{
latitude *= 10000;
parseptr = strchr(parseptr, '.') + 1;
latitude += parsedecimal(parseptr);
}
parseptr = strchr(parseptr, ',') + 1;
// read latitude N/S data
if (parseptr[0] != ',')
{
latdir = parseptr[0];
}
// longituide
parseptr = strchr(parseptr, ',')+1;
longitude = parsedecimal(parseptr);
if (longitude != 0)
{
longitude *= 10000;
parseptr = strchr(parseptr, '.') + 1;
longitude += parsedecimal(parseptr);
}
parseptr = strchr(parseptr, ',') + 1;
// read longitude E/W data
if (parseptr[0] != ',')
{
longdir = parseptr[0];
}
// groundspeed
parseptr = strchr(parseptr, ',') + 1;
groundspeed = parsedecimal(parseptr);
// trackangle, just 'cause
parseptr = strchr(parseptr, ',') + 1;
trackangle = parsedecimal (parseptr);
// date
parseptr = strchr(parseptr, ',') + 1;
tmp = parsedecimal(parseptr);
date = tmp / 10000;
month = (tmp / 100) % 100;
year = tmp % 100;
// OK - we've parsed the full string. Now let's print to serial if in debug mode
if (DEBUG)
{
Serial.print("\n\tTime: ");
Serial.print(hour, DEC); Serial.print(':');
Serial.print(minute, DEC); Serial.print(':');
Serial.println(second, DEC);
Serial.print("\tDate: ");
Serial.print(month, DEC); Serial.print('/');
Serial.print(date, DEC); Serial.print('/');
Serial.println(year, DEC);
Serial.print("\n\tStatus: "); Serial.print(validity);
Serial.print("\n\tLat: ");
if (latdir == 'N')
Serial.print('+');
else if (latdir == 'S')
Serial.print('-');
Serial.print(latitude/1000000, DEC); Serial.print("* ");
Serial.print((latitude/10000)%100, DEC); Serial.print('\''); Serial.print(' ');
Serial.print((latitude%10000)*6/1000, DEC); Serial.print('.');
Serial.print(((latitude%10000)*6/10)%100, DEC); Serial.println('"');
Serial.print("\tLong: ");
if (longdir == 'E')
Serial.print('+');
else if (longdir == 'W')
Serial.print('-');
Serial.print(longitude/1000000, DEC); Serial.print("* ");
Serial.print((longitude/10000)%100, DEC); Serial.print('\''); Serial.print(' ');
Serial.print((longitude%10000)*6/1000, DEC); Serial.print('.');
Serial.print(((longitude%10000)*6/10)%100, DEC); Serial.println('"');
Serial.print("\tGroundspeed: ");
Serial.println(groundspeed);
Serial.println("Now writing to SD card...\n\t");
Serial.println(buffer);
}
// Now log tab separated string
digitalWrite(led2Pin, HIGH); // First turn on LED2 to indicate writing to SD
logFile.write((uint8_t *) buffer, buffidx); // write the string to the SD card
logFile.println("");
logFile.flush();
digitalWrite(led2Pin, LOW); // turn off LED2 (write to SD is finished)
buffidx = 0; // reset buffer pointer
if(fix)
{
if ((TURNOFFGPS) && (SLEEPDELAY))
{
digitalWrite(powerpin, HIGH); // turn off GPS
delay(100); // wait for serial monitor write to finish
sleep_sec(SLEEPDELAY); // turn off CPU
digitalWrite(powerpin, LOW); // turn on GPS
} // if (TURNOFFGPS)
} // if (fix)
return;
} // if(gotGPRMC)
}
// Handling Errrs HERE
// blink out an error code
void error(uint8_t errno) {
if (DEBUG)
{
/* Need to investigate
if (SD.errorCode()) {
putstring("SD error: ");
Serial.print(card.errorCode(), HEX);
Serial.print(',');
Serial.println(card.errorData(), HEX);
}
*/
Serial.print("Error writing to SD card. ");
}
while(1) {
for (i=0; i<errno; i++) {
digitalWrite(led1Pin, HIGH);
digitalWrite(led2Pin, HIGH);
delay(1000);
digitalWrite(led1Pin, LOW);
digitalWrite(led2Pin, LOW);
delay(100);
}
for (; i<10; i++) {
delay(200);
}
}
}
void sleep_sec(uint16_t x) {
while (x--) {
// set the WDT to wake us up!
WDTCSR |= (1 << WDCE) | (1 << WDE); // enable watchdog & enable changing it
WDTCSR = (1<< WDE) | (1 <<WDP2) | (1 << WDP1);
WDTCSR |= (1<< WDIE);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// sleep_enable();
sleep_mode();
// sleep_disable();
}
}