The NEO-6M is the GPS module in most Indian vehicle trackers and student projects (about ₹350 with antenna). It sends standard NMEA text sentences once a second. The TinyGPSPlus library turns them into latitude, longitude, altitude, speed and UTC time.
The Uno’s only hardware serial port is busy with USB, so the GPS connects to SoftwareSerial on D4 (receive) and D3 (transmit). The module’s TX is a 3.3 V signal, which the Uno reads without help. Its RX pin is 3.3 V too, so the Uno’s 5 V transmit line goes through a 1 kΩ / 2 kΩ divider. You only need that wire if you later send configuration commands; reading position needs just TX.
The sketch prints the satellite count, position and Indian time every 2 seconds, and tells you clearly when no data is arriving at all.
Wiring
| Arduino Uno R3 | NEO-6M GPS module (GY-NEO6MV2) | Wire | Notes |
|---|---|---|---|
| 5V | VCC | red | The GY-NEO6MV2 board has a 3.3 V regulator; 5 V in is right. It draws up to about 50 mA while searching. |
| GND | GND | black | |
| D4 | TX | yellow | GPS TX (3.3 V) → Uno SoftwareSerial RX. Read fine as HIGH. |
| D3 | RX | green | Via 1 kΩ / 2 kΩ divider — Only needed if you send configuration commands; the GPS RX pin is 3.3 V. |
3.3–5 V (on-board 3.3 V regulator) part, 5 V board. The module’s TX is a 3.3 V signal, which every board reads fine. Its RX pin is 3.3 V logic: from a 5 V Arduino TX, add a 1 kΩ / 2 kΩ divider. You only need RX if your sketch sends configuration commands.
Board quirks
- GPS needs open sky. Indoors under a concrete roof it usually never gets a fix. Take the Uno to a balcony or terrace on a laptop or power bank for the first fix — a cold start takes 1–5 minutes.
- The module’s blue LED blinks once a second only after it has a fix. Solid or off means still searching.
- D0/D1 carry USB serial, so the GPS sits on SoftwareSerial. At the GPS’s 9600 baud this is reliable, but avoid other long interrupt-blocking code (NeoPixel strips, DHT reads) or characters get lost and sentences fail their checksum.
- GPS time is UTC. The sketch adds 5 h 30 min for IST (it doesn’t roll the date over at midnight — use a time library for that).
Code
// NEO-6M GPS module on an Arduino Uno R3, with TinyGPSPlus and SoftwareSerial.
// GPS TX → D4 (Uno RX), Uno D3 (TX) → 1 kΩ / 2 kΩ divider → GPS RX, VCC → 5V, GND → GND.
// First fix needs open sky: take it outdoors or to a window for 1–5 minutes.
#include <SoftwareSerial.h>
#include <TinyGPSPlus.h>
SoftwareSerial gpsSerial(4, 3); // RX, TX
TinyGPSPlus gps;
unsigned long lastPrint = 0;
void printTwo(uint8_t v) {
if (v < 10) Serial.print('0');
Serial.print(v);
}
void setup() {
Serial.begin(9600);
gpsSerial.begin(9600); // NEO-6M default
Serial.println(F("NEO-6M on D4/D3 - waiting for satellites..."));
}
void loop() {
while (gpsSerial.available()) gps.encode(gpsSerial.read());
if (millis() - lastPrint < 2000) return;
lastPrint = millis();
if (gps.charsProcessed() < 10) {
Serial.println(F("No data from GPS - check GPS TX -> D4 and power"));
return;
}
Serial.print(F("Sats "));
Serial.print(gps.satellites.isValid() ? gps.satellites.value() : 0);
if (gps.location.isValid()) {
Serial.print(F(" Lat "));
Serial.print(gps.location.lat(), 6);
Serial.print(F(" Lng "));
Serial.print(gps.location.lng(), 6);
Serial.print(F(" Alt "));
Serial.print(gps.altitude.meters(), 0);
Serial.print(F(" m"));
} else {
Serial.print(F(" no fix yet"));
}
if (gps.time.isValid()) {
// GPS time is UTC; India is UTC+5:30.
int mins = gps.time.hour() * 60 + gps.time.minute() + 330;
Serial.print(F(" IST "));
printTwo((mins / 60) % 24);
Serial.print(':');
printTwo(mins % 60);
Serial.print(':');
printTwo(gps.time.second());
}
Serial.println();
}// NEO-6M GPS module on an Arduino Uno R3, with TinyGPSPlus and SoftwareSerial.
// GPS TX → D4 (Uno RX), Uno D3 (TX) → 1 kΩ / 2 kΩ divider → GPS RX, VCC → 5V, GND → GND.
// First fix needs open sky: take it outdoors or to a window for 1–5 minutes.
#include <SoftwareSerial.h>
#include <TinyGPSPlus.h>
SoftwareSerial gpsSerial(4, 3); // RX, TX
TinyGPSPlus gps;
unsigned long lastPrint = 0;
void printTwo(uint8_t v) {
if (v < 10) Serial.print('0');
Serial.print(v);
}
void setup() {
Serial.begin(9600);
gpsSerial.begin(9600); // NEO-6M default
Serial.println(F("NEO-6M on D4/D3 - waiting for satellites..."));
}
void loop() {
while (gpsSerial.available()) gps.encode(gpsSerial.read());
if (millis() - lastPrint < 2000) return;
lastPrint = millis();
if (gps.charsProcessed() < 10) {
Serial.println(F("No data from GPS - check GPS TX -> D4 and power"));
return;
}
Serial.print(F("Sats "));
Serial.print(gps.satellites.isValid() ? gps.satellites.value() : 0);
if (gps.location.isValid()) {
Serial.print(F(" Lat "));
Serial.print(gps.location.lat(), 6);
Serial.print(F(" Lng "));
Serial.print(gps.location.lng(), 6);
Serial.print(F(" Alt "));
Serial.print(gps.altitude.meters(), 0);
Serial.print(F(" m"));
} else {
Serial.print(F(" no fix yet"));
}
if (gps.time.isValid()) {
// GPS time is UTC; India is UTC+5:30.
int mins = gps.time.hour() * 60 + gps.time.minute() + 330;
Serial.print(F(" IST "));
printTwo((mins / 60) % 24);
Serial.print(':');
printTwo(mins % 60);
Serial.print(':');
printTwo(gps.time.second());
}
Serial.println();
}Library: TinyGPSPlus (Mikal Hart) — compiled with TinyGPSPlus 1.0.3.
Expected serial output
NEO-6M on D4/D3 - waiting for satellites...
Sats 0 no fix yet
Sats 4 no fix yet IST 18:42:07
Sats 7 Lat 19.076012 Lng 72.877655 Alt 14 m IST 18:43:11NEO-6M on D4/D3 - waiting for satellites... Sats 0 no fix yet Sats 4 no fix yet IST 18:42:07 Sats 7 Lat 19.076012 Lng 72.877655 Alt 14 m IST 18:43:11
Common errors
“No data from GPS”
GPS TX is not on D4 (TX and RX are easy to swap), or the module has no power. Its red power LED should be on.
Satellites show but no fix for 10+ minutes
Weak sky view or the antenna is loose or upside down (ceramic side up). See NEO-6M no GPS fix.
Position jumps by tens of metres when still
Normal for a cheap single-band GPS, especially between tall buildings. Average a few readings, and wait until 6 or more satellites are used.