Here is the kasGPS V3.0 source code:
// GPS Logger kasGPS V3.0 Kas 2013
// SD wiring:
// MOSI: D11, MISO: D12, CLK: D13, CS: D10 (D53 for Mega)
// V30: Use sdfat (http://arduino.cc/forum/index.php/topic,149504.0.html)
// .....
// V1.0 Initial release
#include <SdFat.h>
#include <avr/sleep.h>
#include <TinyGPS.h>
#define PMTK_SET_NMEA_OUTPUT_RMCONLY "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" // only RMC data
TinyGPS gps; // TinyGPS object
SdFat sd; // SD file system.
SdFile file; // Log file.
int CS = 10; // SPI chip select
int logLED = 8;
int bipPin = 9;
int minDist = 30; // Minimum distance in meters between logs
long logRate = 3000; // Minimun time in ms between logs
int voltMin = 300; // Minimum battery voltage
static char dtostrfbuffer[20];
float flat, flon;
float flat_ant=0, flon_ant=0;
unsigned long age;
long distance;
long startLog = 0;
String SD_lat = "invalid";
String SD_lon = "invalid";
String dataString ="";
int maxSkip = 5; // do not log initial inaccurate values
int skip = 1;
static bool feedgps();
void setup() {
pinMode(CS, OUTPUT); // Chip Select Pin for SD Card
pinMode(bipPin, OUTPUT); // Buzzer
pinMode(logLED, OUTPUT); // LED Indicator
Serial.begin(9600);
Serial.println(PMTK_SET_NMEA_OUTPUT_RMCONLY); // turn on only RMC
if (!sd.begin(CS) || !getConfig()) { // Initialize SD card and get configuration
bip(bipPin, 250, 3); // error
blinkLED(logLED, 10, 3);
while(1);
}
if (!file.open("LOG.CSV", O_CREAT | O_WRITE | O_APPEND)) {// Initialize the SD and create or open the CVS data file for append.
bip(bipPin, 250, 4); // error
blinkLED(logLED, 10, 4);
while(1);
}
blinkLED(logLED, 10, 2);
bip(bipPin, 10, 2); // ready
}
void loop() {
bool newdata = false;
if(getBatVolt() < voltMin) { // battery monitoring
bip(bipPin, 200, 5);
GoToSleep(); // ATMega low hibernation mode
}
unsigned long start = millis();
while (millis() - start < 1500) { // data acquisition from GPS module
if (feedgps()) newdata = true;
}
if(newdata) {
gps.f_get_position(&flat, &flon, &age);
if(flat == TinyGPS::GPS_INVALID_F_ANGLE) {
SD_lat = "***";
SD_lon = "***";
} else {
SD_lat = dtostrf(flat,8,5,dtostrfbuffer);
SD_lon = dtostrf(flon,8,5,dtostrfbuffer);
}
dataString = SD_lat + "," + SD_lon;
feedgps();
if(dataString != "***,***") {
if(skip > maxSkip) { // discard first values
if((millis() - startLog > logRate)) { // time log conditions
startLog = millis();
distance = TinyGPS::distance_between(flat, flon, flat_ant, flon_ant);
if(distance > minDist) { // distance log conditions
if(abs(distance > 1000)) distance = 0; // max speed 1200Km/h
file.println(dataString); // write to file
file.sync(); // Use sync instead of close.
flat_ant = flat;
flon_ant = flon;
bip(bipPin, 3, 1);
blinkLED(logLED, 10, 1);
}
}
} else {
skip++;
blinkLED(logLED, 10, 1);
}
} else { blinkLED(logLED, 200, 1); blinkLED(logLED, 10, 1); }
} else digitalWrite(logLED, HIGH);
}
static bool feedgps() {
while(Serial.available()) {
if(gps.encode(Serial.read())) return true;
}
return false;
}
void bip(int pin, int duration, int n) { // Bip piezo: duree en ms et repetition
for(int i=0; i<n; i++) {
digitalWrite(bipPin, HIGH);
delay(duration);
digitalWrite(bipPin, LOW);
delay(75);
}
}
void blinkLED(int pin, int duration, int n) {
for(int i=0; i<n; i++) {
digitalWrite(pin, HIGH);
delay(duration);
digitalWrite(pin, LOW);
if(n > 1) delay(200); // ex500
}
}
int getBatVolt() {
int results;
const long InternalReferenceVoltage = 1098L; //1050L; // Adjust value to your boards specific internal BG voltage x1000
// REFS1 REFS0 --> 0 1, AVcc internal ref. // MUX3 MUX2 MUX1 MUX0 --> 1110 1.1V (VBG)
for (int i=0; i <= 3; i++) { //4 readings required for best stable value?
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
ADCSRA |= _BV( ADSC ); // Start a conversion
while( ( (ADCSRA & (1<<ADSC)) != 0 ) ); // Wait for it to complete
results = (((InternalReferenceVoltage * 1023L) / ADC) + 5L) / 10L; // Scale the value
}
return results;
}
void GoToSleep() {
Serial.end();
ADCSRA = 0; // disable ADC
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();
MCUCR = _BV (BODS) | _BV (BODSE); // turn on brown-out enable select
MCUCR = _BV (BODS); // this must be done within 4 clock cycles of above
sleep_cpu (); // sleep within 3 clock cycles of above
}
boolean getConfig() { // Read the Configuration information (Config.txt)
boolean result = true; // file content: X;Y
if (file.open("Config.txt", O_READ) ) { // X=seconds Y=metersX10 (between 2 records)
if(file.available() >= 3) {
logRate = (file.read() - '0') * 1000;
file.read(); // drops ";"
minDist = (file.read() - '0') * 10;
} else result = false;
file.close();
} else result = false;
return result;
}
I use two nice libraries for this project
Both libraries come with sample code I happily reused
Kudos to these two gentlemen for their hard works