GPS device with text LCD display and track logging to GPX file on SD Card
Dependencies: MODGPS SDFileSystem TextLCD mbed
- Haicom HI-203E Serial GPS Receiver
- Text LCD Display 2x40 (1x HD44780, 4x HD44100)
- RS-232 Level Shifter (MAX232)
- Adafruit Micro-SD breakout board+
mbed Pin # | mbed Pin Function | Peripheral Pin |
---|---|---|
p5 | SPI MOSI / SDFileSystem | SD Card Data In |
p6 | SPI MISO / SDFileSystem | SD Card Data Out |
p7 | SPI SCK / SDFileSystem | SD Card Clk |
p8 | SPI CS / SDFileSystem | SD Card Data CS |
p12 | GPIO / TextLCD | LCD RS |
p14 | GPIO / TextLCD | LCD EN |
p21 | GPIO / InterruptIn | Button switch to GND (start/stop logging) |
p22 | GPIO / TextLCD | LCD D4 |
p23 | GPIO / TextLCD | LCD D5 |
p24 | GPIO / TextLCD | LCD D6 |
p25 | GPIO / TextLCD | LCD D7 |
p27 | UART RX / GPS | GPS TX |
main.cpp
- Committer:
- mprinke
- Date:
- 2013-02-17
- Revision:
- 1:1b62ee4c7e05
- Parent:
- 0:e8ad47e9a9b4
File content as of revision 1:1b62ee4c7e05:
/* mbed GPS Logger using SD Card and Text LCD display * * Copyright (c) 2013 m.prinke, MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * @file main.cpp * @purpose GPS Logger using SD Card and Text LCD display * @version 0.1 * @date Feb 2013 * @author M. Prinke */ /** * Time and position data from GPS receiver is displayed on a text LCD. * GPS tracks can be written to a logfile (GPX format) on SD Card. * Logging is started/stopped using a toggle button. * Everytime logging is started, a new file with the filename pattern /sd/gpslog<nnnn>.gpx * is created, where <nnnn> is decimal number in the range 0000 to 9999 which is incremented. * Searching for a new unique filename is started from zero. * * LED1: GPS status (blinking: fix invalid; on: fix valid) * LED2: Logging status (off: stopped; on: logging) * * To Do: * - Adjustable logging cycle time (read from config file on SD Card?) * - Start new track segment after loss of GPS fix * - Add support for GSA message (2D/3D fix, dilution of precision) */ #include "mbed.h" #include "GPS.h" #include "TextLCD.h" #include "SDFileSystem.h" #define GPS_BAUDRATE 4800 #define LOGGING_CYCLE_SEC 5 DigitalOut led_fix(LED1); // GPS fix (blinking - no data/no fix; on: fix) DigitalOut led_log(LED2); // logging active InterruptIn button(p21); // button connects pin to GND Serial pc(USBTX, USBRX); // tx, rx GPS gps(NC, p27); // tx, rx TextLCD lcd(p12, p14, p22, p23, p24, p25, TextLCD::LCD40x2); // rs, e, d4-d7 SDFileSystem sd(p5, p6, p7, p8, "sd"); // mosi, miso, sclk, cs bool g_logging = false; bool g_changed = false; uint32_t g_trkpt_no = 0; /** * Function to create a unique filename * * @param fn pointer to a filename buffer * @param number part of filename (returned by reference) * @return 0 on success, -1 if no unused filename could be created. */ int get_filename(char *fn, uint16_t *number) { FILE *fp; for (int n=0; n < 9999; n++) { sprintf(fn, "/sd/gpslog%04d.gpx", n); if ((fp = fopen(fn, "r")) == NULL) { *number = n; // file does not exist yet return 0; } else { fclose(fp); } } // filename pattern exhausted return -1; } /** * Callback function for button interrupt * * Debounce button and set change flag. */ void change_logging(void) { wait_ms(50); // button debounce while (!button); // wait until button released g_changed = true; } /** * Write GPX file header (including start of track segment) * * @param fp file pointer * @param t time structure * @param fileno file number * @return result of last file write access */ int write_gpx_header(FILE *fp, GPS_Time t, uint16_t fileno) { g_trkpt_no = 0; //< reset trackpoint number fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); fprintf(fp, "<gpx\n"); fprintf(fp, " version=\"1.0\"\n"); fprintf(fp, " creator=\"mbed GPS Logger\"\n"); fprintf(fp, " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"); fprintf(fp, " xmlns=\"http://www.topografix.com/GPX/1/0\"\n"); fprintf(fp, " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n"); fprintf(fp, "<time>%04d-%02d-%02dT%02d:%02d:%02dZ</time>\n", t.year, t.month, t.day, t.hour, t.minute, t.second); fprintf(fp, "<trk>\n"); fprintf(fp, " <name>track%04d</name>\n", fileno); return fprintf(fp, "<trkseg>\n"); } /** * Write GPX trackpoint - add your geo-referenced data here * * @param fp file pointer * @param t time structure * @return result of last file write access */ int write_gpx_trkpt(FILE *fp, GPS_Time t) { fprintf(fp, " <trkpt lat=\"%.4f\" lon=\"%.4f\">\n", gps.latitude(), gps.longitude()); fprintf(fp, " <ele>%.1f</ele>\n", gps.altitude() * 1000.0); fprintf(fp, " <time>%04d-%02d-%02dT%02d:%02d:%02dZ</time>\n", t.year, t.month, t.day, t.hour, t.minute, t.second); fprintf(fp, " <name>TP%06d</name>\n", g_trkpt_no++); return fprintf(fp, " </trkpt>\n"); } /** * Write GPX file footer (including end of track segment) * * @param fp file pointer * @return result of last file write access */ int write_gpx_footer(FILE *fp) { fprintf(fp, "</trkseg>\n"); fprintf(fp, "</trk>\n"); return fprintf(fp, "</gpx>\n"); } int main() { GPS_Time t; char filename[30]; uint16_t fileno; FILE *fp = NULL; uint16_t log_wait = 0; button.mode(PullUp); button.fall(&change_logging); gps.baud(GPS_BAUDRATE); lcd.cls(); while (1) { // Wait for the GPS NMEA data to become valid. // (Status flag in RMC message) while (!gps.isTimeValid()) { led_fix = !led_fix; lcd.locate(21, 0); lcd.printf("[no fix]"); wait(1); } gps.timeNow(&t); #if defined(DEBUG) pc.printf("The time/date is %02d:%02d:%02d %02d/%02d/%04d\r\n", t.hour, t.minute, t.second, t.day, t.month, t.year); #endif lcd.locate(0, 0); lcd.printf("%02d:%02d:%02d %02d/%02d/%04d %9s %10s", t.hour, t.minute, t.second, t.day, t.month, t.year, (gps.getGPSquality() > 0 ? "[fix] " : "[no fix]"), (g_logging ? "[logging]" : "[stopped]")); // Check if at least four satellites produce a position fix and a valid quality. if (gps.numOfSats() < 4 && gps.getGPSquality() != 0) { // No fix or poor quality led_fix = !led_fix; } else { // Fix valid and good quality led_fix = 1; #if defined(DEBUG) pc.printf("Lat = %.4f Lon = %.4f Alt = %.1fkm\r\n", gps.latitude(), gps.longitude(), gps.altitude()); #endif lcd.locate(0, 1); lcd.printf("Lat: %07.4f Lon: %08.4f Alt: %.0fm ", gps.latitude(), gps.longitude(), gps.altitude() * 1000.0); if (g_logging) { if (log_wait-- == 0) { log_wait = LOGGING_CYCLE_SEC - 1; if (write_gpx_trkpt(fp, t) < 0) { // write error fclose(fp); g_logging = false; led_log = 0; } } } } wait(1); // Logging state changed if (g_changed) { if (!g_logging) { // Start logging if (get_filename(filename, &fileno) != 0) { error("Could not create file with unique name\n"); } else { // open file for writing fp = fopen(filename, "w"); if (fp == NULL) { error("Could not open file for write\n"); } else { if (write_gpx_header(fp, t, fileno)) { g_logging = true; led_log = 1; } } } } else { // Stop logging write_gpx_footer(fp); // close file fclose(fp); g_logging = false; led_log = 0; } g_changed = false; } // if (changed) } // while (1) }