Módulo GPS NEO-6M com Arduino: ligação, NMEA e TinyGPSPlus
Como usar o módulo GPS NEO-6M com Arduino: ligação TX/RX, tempo até a primeira posição, sentenças $GPGGA e $GPRMC, código com TinyGPSPlus, ESP32 com OLED e Pico com MicroPython.
O módulo GPS NEO-6M é um receptor GPS barato e muito popular que acrescenta ao seu projeto com Arduino, ESP32 ou Raspberry Pi Pico latitude, longitude, velocidade, altitude e uma hora UTC extremamente precisa vinda dos satélites. Para usá-lo com um Arduino você só precisa de quatro fios (VCC, GND, TX, RX): uma vez por segundo, o módulo envia linhas de texto chamadas sentenças NMEA a 9600 baud, e a biblioteca TinyGPSPlus transforma essas linhas em números que você pode usar na hora.
Neste guia você vai ver, passo a passo, como o módulo funciona, como ligá-lo a um Arduino Uno, a um ESP32 e a um Pico, por que a primeira posição às vezes demora minutos, o que significa cada campo das sentenças $GPGGA e $GPRMC, como transformar latitude e longitude em um link do Google Maps e como mostrar a posição em um display OLED. No final, você encontra uma tabela com as causas e soluções dos dois problemas mais comuns: “sem dados” e “sem posição”.

O que é o módulo GPS NEO-6M e como ele funciona?
O GPS (Sistema de Posicionamento Global) é formado por mais de 30 satélites em órbita a uma altitude de cerca de 20.200 km. Cada satélite transmite o tempo todo a hora do seu relógio atômico de bordo e os dados da sua própria órbita. O NEO-6M mede a diferença entre o momento em que um sinal saiu do satélite e o momento em que chegou e, a partir disso, calcula a sua distância até cada satélite; quando enxerga pelo menos 4 satélites, ele consegue resolver latitude, longitude, altitude e o erro do seu próprio relógio. Com só 3 satélites, ele calcula uma posição bidimensional (2D), sem altitude. Os sinais dos satélites chegam ao chão extremamente fracos (cerca de -130 dBm), e concreto, telhados metálicos e até copas densas de árvores bloqueiam a maior parte deles. Por isso a regra de ouro do GPS é simples: a antena precisa ver o céu.
| Característica | Valor |
|---|---|
| Chip receptor | u-blox NEO-6M (motor de posicionamento u-blox 6) |
| Canais e sinal | 50 canais, GPS L1 C/A (1575,42 MHz), SBAS: EGNOS, WAAS, MSAS |
| Precisão horizontal | 2,5 m CEP (2,0 m com SBAS) |
| Precisão de velocidade e rumo | 0,1 m/s e 0,5 grau |
| Tempo até a primeira posição (TTFF) | A frio 27 s, morno 27 s, a quente 1 s |
| Sensibilidade | Rastreamento -161 dBm, partida a frio -147 dBm |
| Taxa de atualização | 1 Hz por padrão, até 5 Hz |
| Interface | UART, 9600 baud 8N1 por padrão, NMEA 0183 |
| Alimentação | Placa: 3,3–5 V (com regulador); chip: 2,7–3,6 V |
| Corrente | ~47 mA procurando, ~39 mA rastreando |
| Temperatura de operação | -40 a +85 °C |
A placa que você compra é mais que o chip NEO-6M de 16×12 mm. As placas GY-NEO6MV2 comuns acrescentam uma antena cerâmica tipo patch de 25×25 mm, um regulador que permite alimentar o módulo com 3,3–5 V, uma pequena EEPROM que guarda as configurações, uma bateria de reserva recarregável que mantém a hora e os dados dos satélites e um LED que pisca quando uma posição é encontrada. Algumas placas, como a da foto acima, também têm um conector SMA ou um minúsculo u.FL para antena externa e uma porta micro USB para ligar direto em um computador.
Ligação do NEO-6M: Arduino Uno, ESP32 e Raspberry Pi Pico
O NEO-6M se comunica por UART, que funciona como a porta serial de um computador e usa duas linhas de dados. A regra é simples: as linhas de dados são cruzadas. O pino TX (transmissão) do módulo vai ao pino RX (recepção) da placa, e o pino RX do módulo vai ao pino TX da placa. A única porta serial de hardware do Arduino Uno (pinos 0 e 1) é usada para o carregamento pelo USB e para o Monitor Serial, então ligamos o GPS aos pinos D4 e D3 com SoftwareSerial. Você encontra os detalhes da comunicação serial no artigo Comunicação serial UART.
| Pino do NEO-6M | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC | 5V | VIN (5V) ou 3V3 | VBUS (5V) ou 3V3(OUT) |
| GND | GND | GND | GND |
| TX | D4 (RX da SoftwareSerial) | GPIO 16 (RX2) | GP1 (RX da UART0) |
| RX | D3, através de um divisor de 1 kΩ / 2 kΩ | GPIO 17 (TX2) | GP0 (TX da UART0) |
| PPS (se houver) | Pode ficar desligado | Pode ficar desligado | Pode ficar desligado |
A primeira posição: partida a frio, morna e a quente
É totalmente normal que um módulo GPS não informe a posição no instante em que você o liga pela primeira vez. Para calcular a posição, o módulo precisa dos dados precisos de órbita (efemérides) dos satélites visíveis, e cada satélite os transmite mais ou menos a cada 30 segundos; baixar o almanaque completo, a lista aproximada das órbitas de todos os satélites, leva 12,5 minutos. Dependendo do quanto guardou de antes de ser desligado, o módulo parte de uma de três formas. Os tempos do datasheet foram medidos em condições de teste, com sinais fortes de todos os satélites; com a pequena antena cerâmica que vem com a placa, esperar alguns minutos é normal.
| Tipo de partida | Dados guardados no módulo | Datasheet | Na prática (ao ar livre) |
|---|---|---|---|
| Partida a frio | Sem hora, posição nem dados dos satélites (primeiro uso ou bateria de reserva descarregada) | 27 s | 1–5 minutos; pode passar de 10 minutos com sinais fracos |
| Partida morna | Almanaque, hora e posição aproximadas; efemérides desatualizadas (desligado por mais de cerca de 4 horas) | 27 s | 30 segundos – 1 minuto |
| Partida a quente | Efemérides e hora atuais (desligado há pouco tempo, bateria de reserva carregada) | 1 s | Alguns segundos |
- Vá para fora: em ambientes fechados, principalmente em prédios de concreto, o módulo muitas vezes não encontra posição nenhuma. Para testar, use uma varanda, um quintal ou pelo menos a frente de uma janela aberta.
- Aponte a antena do jeito certo: a face plana e clara da antena cerâmica precisa ficar virada para o céu; virá-la de cabeça para baixo ou cobri-la com a mão enfraquece muito o sinal.
- Mantenha a antena longe da eletrônica: a antena Wi-Fi do ESP32, os reguladores chaveados e cabos USB longos emitem ruído; coloque a antena a alguns centímetros das placas.
- Tenha paciência e mantenha parado: não corte a alimentação durante a primeira posição; cada reinício recomeça a busca do zero.
- Observe o LED: o LED da placa fica apagado até encontrar uma posição e depois começa a piscar uma vez por segundo.
- Carregue a bateria de reserva: se a bateria estiver descarregada, toda energização é uma partida a frio. Deixar o módulo ligado por algumas horas a carrega, e as partidas seguintes caem para segundos.
Sentenças NMEA: como ler $GPGGA e $GPRMC
O NEO-6M envia tudo o que encontra como linhas de texto simples, separadas por vírgulas, no padrão NMEA 0183. Com as configurações padrão, chegam seis tipos de sentença por segundo: GGA, GLL, GSA, GSV, RMC e VTG; as sentenças TXT normalmente só aparecem na energização e trazem mensagens informativas, como a versão do firmware. Cada sentença começa com $; o prefixo GP significa que os dados vêm do GPS, e as três letras seguintes dão o tipo da sentença. Os dois caracteres depois do * no fim da linha são o checksum, obtido fazendo XOR de todos os caracteres entre $ e *, e é com ele que as linhas corrompidas são filtradas. As duas sentenças mais importantes para a posição são: $GPGGA,092750.00,4100.82500,N,02858.74000,E,1,08,1.01,39.2,M,36.9,M,,*67 e $GPRMC,092750.00,A,4100.82500,N,02858.74000,E,0.512,,281026,,,A*7E
| Campo do $GPGGA | Exemplo | Significado |
|---|---|---|
| Hora (UTC) | 092750.00 | 09:27:50 UTC |
| Latitude | 4100.82500,N | 41 graus e 00,825 minuto Norte |
| Longitude | 02858.74000,E | 28 graus e 58,74 minutos Leste |
| Qualidade da posição | 1 | 0 = sem posição, 1 = GPS, 2 = com correção diferencial (SBAS) |
| Satélites | 08 | Satélites usados no cálculo da posição |
| HDOP | 1.01 | Diluição horizontal da precisão; abaixo de 2 é muito bom |
| Altitude | 39.2,M | 39,2 m acima do nível médio do mar |
| Separação do geoide | 36.9,M | Diferença entre o nível do mar e o elipsoide WGS84 |
| Campo do $GPRMC | Exemplo | Significado |
|---|---|---|
| Hora (UTC) | 092750.00 | Horas, minutos, segundos |
| Status | A | A = posição válida, V = sem posição |
| Latitude / longitude | 4100.82500,N / 02858.74000,E | Mesmo formato do GGA |
| Velocidade | 0.512 | Em nós (0,512 × 1,852 ≈ 0,95 km/h) |
| Rumo | (vazio) | Direção do movimento em graus; pode ficar vazio quando parado |
| Data | 281026 | Formato ddmmaa: 28 de outubro de 2026 |
| Modo | A | A = autônomo, D = diferencial, N = sem dados |
A latitude e a longitude no NMEA não estão em graus decimais, mas em graus e minutos (ddmm.mmmm), enquanto o Google Maps e a maioria dos programas querem graus decimais. Para converter, pegue os dois primeiros dígitos da latitude (os três primeiros da longitude) como graus, depois divida os minutos restantes por 60 e some: 4100.82500 → 41 + 0,825 / 60 = 41,013750; 02858.74000 → 28 + 58,74 / 60 = 28,979000. Valores ao Sul (S) e a Oeste (W) são escritos como números negativos. A sexta casa decimal corresponde a cerca de 11 cm e a quinta a 1,1 m; como o NEO-6M tem precisão de 2,5 m, seis casas decimais são mais que suficientes.
Passo a passo: vendo os dados brutos do GPS com um Arduino Uno
- Ligue o NEO-6M como na tabela: VCC → 5V, GND → GND, TX do GPS → D4, RX do GPS → D3 através do divisor.
- Carregue o código abaixo; não é preciso nenhuma biblioteca extra, a SoftwareSerial vem com a Arduino IDE.
- Abra o Monitor Serial e ajuste a velocidade para 115200 baud.
- Leve o módulo para fora ou para perto de uma janela e veja as linhas que começam com $GP passarem.
- Quando o segundo campo da linha $GPRMC mudar de V para A e o LED começar a piscar, o módulo encontrou a posição.
1#include <SoftwareSerial.h>
2
3SoftwareSerial gpsSerial(4, 3); // RX, TX → GPS TX D4'e, GPS RX D3'e / GPS TX to D4, GPS RX to D3
4
5void setup() {
6 Serial.begin(115200); // Seri Monitör hızı / Serial Monitor speed
7 gpsSerial.begin(9600); // NEO-6M varsayılan hızı / NEO-6M default baud rate
8 Serial.println(F("NEO-6M ham NMEA / raw NMEA"));
9}
10
11void loop() {
12 while (gpsSerial.available()) {
13 Serial.write(gpsSerial.read()); // gelen her baytı aynen aktar / pass every byte through
14 }
15}No Monitor Serial você vai ver um bloco de seis a nove linhas a cada segundo (quanto mais satélites à vista, em mais linhas a sentença GSV é dividida). Se o módulo ainda não encontrou nenhum satélite, as linhas ficam cheias de vírgulas vazias, como $GPRMC,,V,,,,,,,,,,N*53 e $GPGGA,,,,,,0,00,99.99,,,,,,*48; isso não é erro, mostra que o módulo está funcionando, mas ainda não consegue calcular a posição. Nas linhas $GPGSV você pode acompanhar o número de satélites visíveis e a intensidade do sinal (dB-Hz) de cada um; valores acima de 30 dB-Hz significam sinal bom. Se nenhuma linha chegar, confira a ligação; se aparecerem caracteres estranhos, confira o baud rate.
Lendo latitude, longitude, velocidade e hora com a TinyGPSPlus
Em vez de analisar as linhas NMEA na mão, é muito mais prático usar a biblioteca TinyGPSPlus, de Mikal Hart. Busque “TinyGPSPlus” no Gerenciador de Bibliotecas e instale; explicamos os passos no artigo como adicionar uma biblioteca no Arduino. Atenção: os exemplos da biblioteca usam 4800 baud, enquanto o NEO-6M usa 9600 baud. Se você rodar um exemplo sem mudar a velocidade, a localização sempre aparece como INVALID, porque a biblioteca não consegue decodificar nenhuma sentença a partir dos caracteres embaralhados. O código abaixo mostra a posição, a velocidade, a altitude, o número de satélites, a data e a hora uma vez por segundo e transforma a posição em um link do Google Maps que você pode abrir no navegador:
1#include <TinyGPSPlus.h>
2#include <SoftwareSerial.h>
3
4const int RX_PIN = 4; // GPS TX → D4
5const int TX_PIN = 3; // GPS RX ← D3 (bölücü üzerinden / through a divider)
6const uint32_t GPS_BAUD = 9600; // NEO-6M varsayılanı / NEO-6M default
7
8TinyGPSPlus gps;
9SoftwareSerial gpsSerial(RX_PIN, TX_PIN);
10unsigned long lastPrint = 0;
11
12void setup() {
13 Serial.begin(115200);
14 gpsSerial.begin(GPS_BAUD);
15 Serial.println(F("NEO-6M + TinyGPSPlus"));
16}
17
18void loop() {
19 while (gpsSerial.available()) {
20 gps.encode(gpsSerial.read()); // her baytı ayrıştırıcıya ver / feed every byte to the parser
21 }
22 if (millis() - lastPrint >= 1000) { // delay() yok, saniyede bir yaz / no delay(), print once per second
23 lastPrint = millis();
24 printInfo();
25 }
26}
27
28void printInfo() {
29 if (gps.charsProcessed() < 10) {
30 Serial.println(F("GPS verisi yok: kablolari ve baud hizini kontrol et / No GPS data: check wiring and baud"));
31 return;
32 }
33 Serial.print(F("Uydu / Sats: "));
34 Serial.println(gps.satellites.value());
35
36 if (gps.location.isValid()) {
37 Serial.print(F("Enlem / Lat: "));
38 Serial.println(gps.location.lat(), 6);
39 Serial.print(F("Boylam / Lng: "));
40 Serial.println(gps.location.lng(), 6);
41 Serial.print(F("Hiz / Speed: "));
42 Serial.print(gps.speed.kmph(), 1);
43 Serial.println(F(" km/h"));
44 Serial.print(F("Yukseklik / Alt: "));
45 Serial.print(gps.altitude.meters(), 1);
46 Serial.println(F(" m"));
47 // Google Haritalar bağlantısı / Google Maps link
48 Serial.print(F("https://www.google.com/maps/search/?api=1&query="));
49 Serial.print(gps.location.lat(), 6);
50 Serial.print(',');
51 Serial.println(gps.location.lng(), 6);
52 } else {
53 Serial.println(F("Konum yok, uydu araniyor / No fix yet, searching"));
54 }
55
56 if (gps.date.isValid() && gps.time.isValid()) {
57 char buf[32];
58 snprintf(buf, sizeof(buf), "%02d.%02d.%04d %02d:%02d:%02d UTC",
59 gps.date.day(), gps.date.month(), (int)gps.date.year(),
60 gps.time.hour(), gps.time.minute(), gps.time.second());
61 Serial.println(buf); // saat UTC'dir / time is UTC
62 }
63 Serial.println();
64}| Função | O que retorna |
|---|---|
| gps.encode(c) | Chamada a cada byte recebido; retorna true quando uma sentença válida está completa |
| gps.location.lat() / lng() (posição) | Latitude e longitude em graus decimais |
| gps.location.isValid() / age() (validade) | Se há uma posição válida / milissegundos desde a última atualização |
| gps.speed.kmph() (velocidade) | Velocidade em relação ao solo em km/h (também existem mps() e knots()) |
| gps.course.deg() (rumo) | Direção do movimento em graus (0 = norte, 90 = leste) |
| gps.altitude.meters() (altitude) | Altitude acima do nível do mar em metros |
| gps.satellites.value() (satélites) | Número de satélites usados para a posição |
| gps.hdop.hdop() (precisão) | Diluição horizontal da precisão (menor = melhor) |
| gps.date.day() / gps.time.hour() (data e hora) | Campos de data e hora em UTC |
| TinyGPSPlus::distanceBetween(...) | Distância entre duas coordenadas em metros |
| gps.failedChecksum() | Número de sentenças corrompidas; se não parar de subir, dados estão se perdendo |
A regra mais importante deste código é nunca usar delay() dentro do loop(). O GPS envia cerca de 500 bytes por segundo, mas o buffer de recepção da SoftwareSerial tem só 64 bytes; durante um delay() longo, o buffer transborda, as sentenças são cortadas e a TinyGPSPlus as descarta com erro de checksum. Por isso mostramos os dados uma vez por segundo usando millis(); veja o artigo millis() vs delay() para os detalhes. A hora do GPS é sempre UTC, então some a diferença do seu fuso horário (por exemplo, −3 horas para o horário de Brasília, +1 para a Europa Central no inverno ou +3 para a Turquia). No Arduino Uno, um double na verdade é um float de 32 bits, então o último dígito da latitude e da longitude é arredondado para cerca de meio metro; perto da precisão de 2,5 m do módulo, essa diferença não importa.
ESP32 com Serial2: mostrando a posição em um display OLED
No ESP32 você não precisa da SoftwareSerial: o chip tem três UARTs de hardware, e a Serial2 pode ser associada a qualquer par de pinos. No exemplo abaixo, o GPS está ligado ao GPIO 16 (RX2) e ao GPIO 17 (TX2); como o ESP32 trabalha em 3,3 V, também não é preciso divisor. A posição, a velocidade e a hora local aparecem em um display OLED de 0,96 polegada (SSD1306) ligado por I2C ao GPIO 21 (SDA) e ao GPIO 22 (SCL). Além da TinyGPSPlus, o código também precisa das bibliotecas Adafruit SSD1306 e Adafruit GFX.
1#include <TinyGPSPlus.h>
2#include <Wire.h>
3#include <Adafruit_GFX.h>
4#include <Adafruit_SSD1306.h>
5
6#define GPS_RX 16 // ESP32 RX2 ← GPS TX
7#define GPS_TX 17 // ESP32 TX2 → GPS RX
8const int UTC_OFFSET = 3; // Türkiye UTC+3, kendi saat dilimini yaz / set your own time zone
9
10TinyGPSPlus gps;
11Adafruit_SSD1306 display(128, 64, &Wire, -1); // OLED: SDA 21, SCL 22
12unsigned long lastDraw = 0;
13
14String mapsLink() {
15 // Google Haritalar bağlantısı üret / build a Google Maps link
16 return "https://www.google.com/maps/search/?api=1&query=" +
17 String(gps.location.lat(), 6) + "," + String(gps.location.lng(), 6);
18}
19
20void drawScreen() {
21 display.clearDisplay();
22 display.setTextSize(1);
23 display.setCursor(0, 0);
24 display.print(F("Uydu/Sat: "));
25 display.print(gps.satellites.value());
26
27 if (gps.time.isValid()) {
28 int h = (gps.time.hour() + UTC_OFFSET + 24) % 24; // yerel saat / local time
29 char t[12];
30 snprintf(t, sizeof(t), "%02d:%02d:%02d", h, gps.time.minute(), gps.time.second());
31 display.setCursor(80, 0);
32 display.print(t);
33 }
34
35 if (gps.location.isValid()) {
36 display.setCursor(0, 16);
37 display.print(F("Lat: "));
38 display.println(gps.location.lat(), 6);
39 display.print(F("Lng: "));
40 display.println(gps.location.lng(), 6);
41 display.setTextSize(2); // hız büyük yazılsın / speed in large digits
42 display.setCursor(0, 44);
43 display.print(gps.speed.kmph(), 1);
44 display.print(F(" km/h"));
45 } else {
46 display.setCursor(0, 24);
47 display.println(F("Uydu araniyor..."));
48 display.println(F("Searching for fix"));
49 }
50 display.display();
51}
52
53void setup() {
54 Serial.begin(115200);
55 Serial2.begin(9600, SERIAL_8N1, GPS_RX, GPS_TX); // donanım UART2 / hardware UART2
56 if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
57 Serial.println(F("OLED bulunamadi / OLED not found"));
58 while (true) delay(10);
59 }
60 display.setTextColor(SSD1306_WHITE);
61}
62
63void loop() {
64 while (Serial2.available()) {
65 gps.encode(Serial2.read()); // NMEA baytlarını çöz / decode NMEA bytes
66 }
67 if (millis() - lastDraw >= 1000) { // saniyede bir güncelle / refresh once per second
68 lastDraw = millis();
69 drawScreen();
70 if (gps.location.isValid()) {
71 Serial.println(mapsLink()); // Telegram ya da SMS ile gönderilebilir / can be sent via Telegram or SMS
72 }
73 }
74}A variável UTC_OFFSET converte a hora do GPS em hora local; ela vale 3 para a Turquia, 1 para o horário de inverno da Europa Central e -3 para o horário de Brasília. A função mapsLink() transforma a posição em um endereço do Google Maps com o parâmetro query=latitude,longitude. Você pode copiar esse link do Monitor Serial e abri-lo em um navegador, enviá-lo ao celular com um bot do Telegram ou mandá-lo por SMS com um módulo GSM SIM800L. Em placas ESP32-WROVER com PSRAM, os GPIO 16 e 17 são usados pela memória, então ligue o GPS, por exemplo, aos GPIO 26 e 27; no ESP32-C3, que tem só duas UARTs, use a Serial1 em vez da Serial2.
Lendo o GPS com o Raspberry Pi Pico e MicroPython
No Raspberry Pi Pico, ligamos o GPS à UART0: o TX do módulo vai ao GP1 e o RX ao GP0. No MicroPython, podemos analisar as linhas NMEA nós mesmos, sem instalar nenhuma biblioteca, o que também é um ótimo exercício para entender como as sentenças são montadas. O código confere o checksum de cada linha, tira o número de satélites do GGA e a posição, a velocidade e a hora do RMC e converte graus e minutos em graus decimais. A configuração timeout=200 faz o readline() esperar até 200 ms pelo fim de uma linha; se mesmo assim uma meia linha passar na inicialização, a verificação do checksum a descarta. Como o tipo de sentença é obtido com f[0][3:], o código também reconhece as linhas $GNRMC e $GNGGA enviadas por módulos que usam vários sistemas de satélites. Se você ainda não sabe rodar código com o Thonny, dê uma olhada antes no artigo Fundamentos de MicroPython.
1from machine import UART, Pin
2
3# GP0 (TX) → GPS RX, GP1 (RX) ← GPS TX
4gps = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1), timeout=200, rxbuf=1024)
5
6def checksum_ok(line):
7 # $ ile * arasındaki karakterlerin XOR'u / XOR of the characters between $ and *
8 try:
9 body, cs = line[1:].split('*')
10 x = 0
11 for ch in body:
12 x ^= ord(ch)
13 return x == int(cs[:2], 16)
14 except ValueError:
15 return False
16
17def to_deg(value, hemi):
18 # ddmm.mmmm → ondalık derece / decimal degrees
19 dot = value.index('.')
20 deg = int(value[:dot - 2]) + float(value[dot - 2:]) / 60
21 return -deg if hemi in ('S', 'W') else deg
22
23sats = '0'
24while True:
25 raw = gps.readline() # bir NMEA satırı / one NMEA line
26 if not raw:
27 continue
28 try:
29 line = raw.decode().strip()
30 except UnicodeError:
31 continue # bozuk bayt / corrupted byte
32 if not line.startswith('$') or not checksum_ok(line):
33 continue
34 f = line.split('*')[0].split(',')
35 kind = f[0][3:] # GPRMC ya da GNRMC → RMC / GPRMC or GNRMC → RMC
36 if kind == 'GGA':
37 sats = f[7] # kullanılan uydu sayısı / satellites in use
38 elif kind == 'RMC':
39 if f[2] != 'A':
40 print('Uydu araniyor / searching, uydu/sats:', sats)
41 continue
42 lat = to_deg(f[3], f[4])
43 lon = to_deg(f[5], f[6])
44 kmh = float(f[7] or 0) * 1.852 # knot → km/sa / knots → km/h
45 t = f[1]
46 print('UTC {}:{}:{} uydu/sats: {}'.format(t[0:2], t[2:4], t[4:6], sats))
47 print('Konum / position: {:.6f}, {:.6f} {:.1f} km/h'.format(lat, lon, kmh))
48 print('https://www.google.com/maps/search/?api=1&query={:.6f},{:.6f}'.format(lat, lon))Ideias de projetos com o NEO-6M
- Rastreador que manda a posição por SMS: com um NEO-6M e um SIM800L, monte um rastreador de carro ou bicicleta que responde a um SMS com “LOCATION” enviando um link do Google Maps.
- Registrador de dados GPS: salve a sua rota a cada segundo em CSV em um módulo de cartão SD e depois desenhe-a em um mapa no computador.
- Velocímetro de bicicleta: mostre a velocidade atual, a máxima e a distância total em um display OLED; some a distância entre pontos consecutivos com TinyGPSPlus::distanceBetween().
- Relógio sincronizado com satélites: pegue a hora do GPS e acerte um módulo de relógio RTC no segundo, sem internet.
- Alarme de cerca virtual: um sistema que toca um buzzer ou manda uma notificação quando algo se afasta mais de 100 metros de um ponto que você escolher.
- Rastreamento de longo alcance: envie a posição a um receptor a quilômetros de distância com um módulo LoRa e economize energia na bateria com o deep sleep do ESP32.
Sem dados ou sem posição: problemas comuns e como resolver
| Sintoma | Causa provável | Solução |
|---|---|---|
| Monitor Serial completamente vazio | TX e RX trocados, sem GND comum ou módulo sem alimentação | Ligue o TX do GPS ao pino RX da placa (D4 no Uno), una os GNDs, meça o VCC |
| “No GPS detected: check wiring.” (nenhum GPS detectado) | Nem 10 caracteres chegaram à biblioteca em 5 segundos | Confira a ligação e os números dos pinos no código; experimente trocar TX e RX |
| Caracteres estranhos | Baud rate diferente | Use 9600 para o GPS e a velocidade do código no Monitor Serial; se não der certo, experimente 4800 e 38400 |
| As linhas chegam, mas os campos estão vazios (,V,) | O módulo funciona, mas não encontrou satélites | Vá para fora, aponte a antena para o céu, espere 5–15 minutos |
| Número de satélites parado em 0–3 | Sinal fraco, antena de cabeça para baixo, conector u.FL frouxo ou uma fonte de ruído por perto | Confira a antena, encaixe bem o conector, afaste a antena do ESP32 e dos reguladores |
| Os dados brutos mostram uma posição, a TinyGPSPlus diz INVALID | Um delay() no loop() faz o buffer transbordar; failedChecksum() não para de subir | Tire o delay(), use millis(), chame encode() continuamente |
| A hora está algumas horas errada | A hora do GPS é UTC | Some a diferença do seu fuso horário |
| A posição oscila alguns metros e a velocidade não é 0 parado | Ruído normal do GPS e sinais refletidos em prédios | Considere 0 as velocidades abaixo de 2 km/h, ignore leituras com HDOP alto, tire médias |
| Espera vários minutos de novo a cada energização | Bateria de reserva descarregada ou ausente | Deixe o módulo ligado por algumas horas para carregar a bateria |
O NEO-6M acrescenta aos seus projetos, a um custo muito baixo, as respostas para “onde estou, com que velocidade estou indo e que horas são”; o segredo é mostrar o céu à antena e ter a paciência de que a primeira posição precisa. Para entender melhor a comunicação serial, dê uma olhada no artigo sobre UART. No app BlueGrays você encontra projetos que também ajudam em montagens com GPS, como comunicação serial entre dois Arduinos, displays OLED, registro de dados em microSD, deep sleep do ESP32 e um alarme com notificações no Telegram, cada um com esquemas do circuito e código passo a passo.
Perguntas frequentes
O módulo GPS NEO-6M funciona em ambientes fechados?
Normalmente não. Os sinais dos satélites chegam ao chão muito fracos, e telhados de concreto ou de metal bloqueiam a maior parte deles. Na frente de uma janela aberta ele pode captar alguns satélites, mas, para uma posição confiável, a antena precisa ver o céu diretamente; se você precisa de posição em ambiente fechado, use uma antena ativa externa colocada no telhado ou em uma janela.
Quanto tempo o NEO-6M leva para obter a primeira posição?
Segundo o datasheet, uma partida a frio leva 27 segundos e uma partida a quente, 1 segundo. Na prática, com a pequena antena cerâmica ao ar livre, a primeira posição costuma levar 1–5 minutos e, no primeiro uso ou com a bateria de reserva descarregada, pode levar 10–15 minutos. Se o módulo foi desligado há pouco tempo, ele volta a travar em alguns segundos.
Qual é a precisão do módulo GPS NEO-6M?
O fabricante especifica uma precisão horizontal de 2,5 m CEP com céu aberto, ou 2,0 m com correção SBAS; isso significa que metade das leituras fica a menos de 2,5 m do ponto real. Nas cidades, sinais refletidos em prédios podem elevar o erro para 5–10 metros. A altitude é menos precisa que a posição horizontal.
O NEO-6M funciona com 5V? Posso ligá-lo direto em um Arduino?
As placas GY-NEO6MV2 comuns têm regulador, então o VCC pode ser alimentado com 5 V. Porém, o pino RX do chip aguenta no máximo 3,6 V, então baixe o sinal TX de 5 V do Arduino Uno com um divisor de tensão de 1 kΩ e 2 kΩ. A saída TX do módulo é de 3,3 V, que o Uno lê sem problema.
Um módulo GPS precisa de internet ou chip de celular?
Não. O NEO-6M calcula a posição diretamente pelos sinais dos satélites, de graça e sem internet. Você só precisa de internet ou de um chip quando quer enviar a posição para outro lugar, usando o Wi-Fi do ESP32 ou um módulo GSM como o SIM800L.
Qual é a diferença entre o NEO-6M e o NEO-M8N?
O NEO-6M só usa satélites GPS. O NEO-M8N, mais novo, pode usar satélites GLONASS, Galileo ou BeiDou ao mesmo tempo que o GPS; como enxerga mais satélites, ele obtém uma posição mais rápida e estável nas cidades. As sentenças do M8N costumam começar com $GN, mas a TinyGPSPlus lê as duas com o mesmo código.
Projetos para montar depois desta leitura
Ver todos os projetos
Comunicação unidirecional entre 2 Arduinos
Faça dois Arduinos conversarem por um único fio: ao pressionar o botão de um, o LED do outro acende; ao pressionar de novo, ele apaga. A placa transmissora informa que o botão foi pressionado com uma

Comunicação bidirecional entre 2 Arduinos
Dois Arduinos se conectam por fios e conversam entre si: ao pressionar o botão de um, a luz do outro acende; ao pressionar novamente, ela apaga. As duas placas executam o mesmo programa, então ambas e

Registrador de temperatura com ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
Monte um registrador de temperatura com data e hora usando ESP32! Leia a temperatura e a umidade do DHT22 a cada minuto, obtenha a hora real do DS1307 RTC e grave os dados em CSV no cartão microSD. O OLED exibe a temperatura atual em letras grandes, a porcentagem de umidade, a data e a hora e o contador de registros. O arquivo /temp_log.csv no cartão SD pode ser aberto no Excel, Google Sheets ou pandas do Python para análise — ideal para monitorar estufas, acompanhar a temperatura de casa ou…

ESP32 HTTPClient + API de clima (com display OLED SSD1306)
Neste projeto, usamos o ESP32 para fazer uma chamada REST à API de clima wttr.in pela internet com HTTPClient.h. Diferentemente da versão anterior com LCD I2C, aqui usamos um display OLED SSD1306 (128×64), que permite usar fontes grandes, ícones vetoriais e uma apresentação visual rica em uma única tela. Sete ícones vetoriais de condições do tempo (ensolarado, parcialmente nublado, nublado, chuvoso, com neve, com tempestade e com neblina) são desenhados durante a execução, sem arquivos bitmap.

ESP32 em sono profundo — Economia de bateria (OLED + contador na RAM RTC)
O modo de sono profundo do ESP32 reduz o consumo de corrente para ~10 µA ao desligar a CPU e a maioria dos periféricos, sendo essencial para dispositivos IoT alimentados por bateria. Neste projeto, usamos três fontes de despertar: um temporizador (15 segundos), um pino externo (EXT0 — botão no GPIO 33) e toque (T0/GPIO 4). As variáveis marcadas com RTC_DATA_ATTR são preservadas durante o sono profundo, mantendo os contadores de inicializações e de despertares por temporizador e botão.

Hora exata pela internet com ESP32 e NTP
O ESP32 se conecta ao Wi-Fi e obtém a hora exata com precisão de milissegundos de servidores NTP (Network Time Protocol). Com a função configTzTime(), o fuso horário configurado (TRT, UTC+3 neste exemplo) é aplicado automaticamente, e as mudanças nos países que adotam horário de verão são gerenciadas automaticamente por uma string POSIX TZ. A hora é exibida tanto no Monitor Serial quanto em um LCD I2C opcional.

Alarme de movimento com ESP32 (PIR + buzzer + LED + Telegram)
Um sistema de alarme de segurança inteligente que aciona o buzzer e o LED quando o sensor PIR detecta movimento e, ao mesmo tempo, envia uma notificação instantânea ao proprietário pelo Telegram. Inclui um intervalo de espera de 30 segundos para limitar a frequência dos alarmes repetidos; esse mecanismo não valida as detecções do PIR nem elimina disparos falsos. Pode ser usado na segurança de casas, no monitoramento de garagens, depósitos ou salas de trabalho.

Relógio digital com ESP32 e RTC DS1307 (I2C + LCD)
Neste projeto, exibimos a hora e a data em um display LCD I2C 16x2 usando o módulo de relógio de tempo real (RTC) DS1307. O DS1307 é um RTC com bateria de reserva que mantém a hora mesmo quando o ESP32 é desligado. Os dois módulos compartilham o mesmo barramento I2C (SDA/SCL), permitindo aprender a controlar vários dispositivos com apenas dois fios de sinal. Você aprenderá na prática o protocolo de comunicação I2C, o funcionamento dos módulos RTC e a exibição de dados dinâmicos em um LCD.
Mais artigos
- O que é UART? Guia de ligação TX/RX, baud rate e comunicação serial com Arduino
- Como usar um display OLED (SSD1306): texto, formas e gráficos com Arduino
- SIM800L com Arduino: envie SMS, controle um relé e faça ligações
- O que é ESP32? Características, configuração na Arduino IDE e seu primeiro projeto com Wi-Fi
App BlueGrays
Monte este circuito passo a passo pelo celular
Esquema do circuito, código e lista de componentes em uma só tela. Mais de 200 projetos com Arduino, ESP32 e Pico prontos para montar.
Escaneie com seu celular
Aponte a câmera para o código para abrir a loja de aplicativos do seu celular.
ou abrir a loja

