🛰️ ESP32 GPS NEO-6M 卫星定位:DIY 你的第一个 GPS 定位器
📅 2026-05-26 · 📂 硬件编程 · ⏱ 阅读约 10 分钟
📺 B站推荐视频:GPS NEO-6M 卫星定位模块的经纬度读取实验 · 零基础手把手教学
📡 概述
GPS(全球定位系统)是物联网和嵌入式项目中最常用的定位技术之一。NEO-6M 是 u-blox 公司出品的经典 GPS 模块,凭借价格便宜(¥15~30)、接口简单(串口通信)、精度够用(2.5m)三大优势,成为 Arduino/ESP32 社区最受欢迎的定位方案。
NEO-6M 模块自带陶瓷天线和信号放大器,上电后自动搜索卫星。一旦锁定 3 颗以上卫星,就开始通过串口持续输出 NMEA-0183 标准格式的定位数据——包括经纬度、海拔、速度、UTC 时间等信息。我们的 ESP32 只需要用软串口(SoftwareSerial)或硬件串口读取这些文本,用 TinyGPS++ 库解析即可。
💡 适用场景:户外 GPS 轨迹记录仪、共享单车定位、无人机导航、宠物追踪器、车载定位、地理围栏报警。在室内或高楼密集区信号会衰减,建议户外开阔地带测试。
📦 物料清单
| 物料 | 型号/参数 | 数量 | 参考价格 |
| ESP32 开发板 | ESP32-WROOM-32 / ESP32-S3 | 1 | ¥15~25 |
| GPS 模块 | NEO-6M(带陶瓷天线+信号放大器) | 1 | ¥15~30 |
| OLED 显示屏 | SSD1306 128×64 I2C(可选) | 1 | ¥8~15 |
| MicroSD 模块 | SPI 接口 TF 卡读写模块(可选,轨迹记录用) | 1 | ¥3~8 |
| TF 卡 | 4GB+ Class10 | 1 | ¥10~15 |
| 锂电池 | 3.7V 18650 ×1 + TP4056 充电模块 | 1 套 | ¥12~20 |
| 面包板 + 杜邦线 | 400 孔面包板 + 公母杜邦线 | 1 套 | ¥5~10 |
💰 总计:约 ¥68~123(不含运费)。核心 GPS 模块不到 20 块,性价比极高。
🔌 接线图
NEO-6M 模块通过 UART 串口 与 ESP32 通信。模块上的 PPS 引脚是秒脉冲输出,本项目不用,悬空即可。
┌─────────────────────────────────────────────────────────┐
│ NEO-6M GPS 接线图 │
├─────────────────────────────────────────────────────────┤
│ │
│ 【NEO-6M 模块引脚】 【ESP32 引脚】 │
│ │
│ VCC (红线) ──────── 3.3V │
│ GND (黑线) ──────── GND │
│ TX (蓝线) ──────── GPIO 16 (RX2 / 软串口RX) │
│ RX (绿线) ──────── GPIO 17 (TX2 / 软串口TX) │
│ PPS (黄线) ──────── (悬空,不用) │
│ │
│ ⚠️ 模块工作电压 3.3V~5V,建议接 3.3V │
│ ⚠️ GND 必须共地! │
│ │
├─────────────────────────────────────────────────────────┤
│ 【OLED SSD1306(可选显示)】 │
│ OLED VCC ──── 3.3V │
│ OLED GND ──── GND │
│ OLED SDA ──── GPIO 21 │
│ OLED SCL ──── GPIO 22 │
│ │
├─────────────────────────────────────────────────────────┤
│ 【MicroSD 模块(可选记录)】 │
│ SD CS ──── GPIO 5 │
│ SD SCK ──── GPIO 18 │
│ SD MOSI ──── GPIO 23 │
│ SD MISO ──── GPIO 19 │
│ SD VCC ──── 3.3V / 5V(视模块) │
│ SD GND ──── GND │
└─────────────────────────────────────────────────────────┘
💡 为什么用 GPIO 16/17?ESP32 有三个硬件串口:Serial0(USB调试)、Serial1(GPIO 9/10,部分板子被Flash占用)、Serial2(GPIO 16/17,最好用)。我们使用 Serial2,波特率设为 9600(NEO-6M 默认),稳定可靠。
💻 基础代码:读取经纬度并打印到串口监视器
首先安装 TinyGPS++ 库:Arduino IDE → 工具 → 管理库 → 搜索 "TinyGPSPlus" → 安装(作者:Mikal Hart)。
// ESP32 + NEO-6M GPS 基础定位程序
// 使用 Serial2 硬件串口 + TinyGPS++ 库
#include <TinyGPS++.h>
#include <HardwareSerial.h>
// 使用 Serial2:RX=GPIO16, TX=GPIO17
#define GPS_RX 16
#define GPS_TX 17
#define GPS_BAUD 9600
TinyGPSPlus gps;
HardwareSerial gpsSerial(2); // 使用 UART2
void setup() {
Serial.begin(115200);
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, GPS_RX, GPS_TX);
Serial.println("🛰️ GPS NEO-6M 定位启动中...");
Serial.println("请将模块放在窗边或户外开阔处");
}
void loop() {
// 持续喂数据给 TinyGPS++
while (gpsSerial.available() > 0) {
char c = gpsSerial.read();
gps.encode(c);
}
// 每秒输出一次定位信息
static unsigned long lastPrint = 0;
if (millis() - lastPrint > 1000) {
lastPrint = millis();
displayGPSInfo();
}
}
void displayGPSInfo() {
Serial.print("📍 卫星数: ");
Serial.println(gps.satellites.value());
if (gps.location.isValid()) {
Serial.print("🌍 纬度: ");
Serial.println(gps.location.lat(), 6);
Serial.print("🌍 经度: ");
Serial.println(gps.location.lng(), 6);
Serial.print("⛰️ 海拔: ");
Serial.print(gps.altitude.meters());
Serial.println(" m");
Serial.print("🚀 速度: ");
Serial.print(gps.speed.kmph());
Serial.println(" km/h");
} else {
Serial.println("⏳ 等待定位中... (请确保在户外开阔处)");
}
if (gps.time.isValid()) {
Serial.printf("🕐 UTC时间: %02d:%02d:%02d\n",
gps.time.hour(),
gps.time.minute(),
gps.time.second());
}
Serial.println("───────────────────");
}
📟 进阶应用:OLED 屏幕实时显示定位
光在串口监视器上看数据不够酷。我们把 OLED 屏接上,做一个手持 GPS 定位器——屏幕实时显示经纬度、海拔和卫星数。
// ESP32 + NEO-6M + SSD1306 OLED 手持定位器
#include <TinyGPS++.h>
#include <HardwareSerial.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
TinyGPSPlus gps;
HardwareSerial gpsSerial(2);
void setup() {
Serial.begin(115200);
gpsSerial.begin(9600, SERIAL_8N1, 16, 17);
Wire.begin(21, 22);
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println("OLED 初始化失败!");
while (1);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
}
void loop() {
while (gpsSerial.available() > 0) {
gps.encode(gpsSerial.read());
}
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.print("🛰️ Sat:");
display.println(gps.satellites.value());
if (gps.location.isValid()) {
display.setCursor(0, 14);
display.print("Lat:");
display.println(gps.location.lat(), 5);
display.setCursor(0, 26);
display.print("Lng:");
display.println(gps.location.lng(), 5);
display.setCursor(0, 40);
display.print("Alt:");
display.print(gps.altitude.meters(), 1);
display.println("m");
display.setCursor(0, 53);
display.print("Spd:");
display.print(gps.speed.kmph(), 1);
display.println("km/h");
} else {
display.setCursor(10, 30);
display.println("Searching GPS...");
}
display.display();
delay(200);
}
💡 需要安装的库:Adafruit SSD1306 + Adafruit GFX Library。Arduino IDE → 管理库 → 分别搜索安装。OLED 地址通常是 0x3C,不显示的话用 I2C Scanner 扫描确认。
🔧 实战场景一:GPS 轨迹记录仪
场景:骑车/徒步时记录行进路线,生成 GPX 文件导入地图软件查看。
物料组合:ESP32 + NEO-6M + MicroSD 模块 + 18650 电池
思路:每秒采集一次 GPS 坐标,写入 MicroSD 卡上的 CSV 文件(lat,lng,alt,speed,time)。回到家拔卡插电脑,用 Google Earth 或 GPX Editor 打开,完整轨迹一目了然。
联动之前学的:
- DHT22(5/16):同时记录温湿度,了解骑行环境
- 低功耗模式(5/17):用深度睡眠+定时唤醒,延长电池续航到 10+ 小时
- MQTT(5/22):有 WiFi 时实时上传位置到云平台(如 ThingsBoard 地图组件)
- L298N 电机(5/25):装在智能小车上,实现 GPS 自动导航
🏠 实战场景二:地理围栏报警器
场景:设定一个安全区域(如家周围 500 米),当设备离开该范围时触发蜂鸣器报警——适合宠物项圈或老人防走失。
物料组合:ESP32 + NEO-6M + 有源蜂鸣器 + LED
核心逻辑:计算当前位置与预设中心点的距离(Haversine公式),超过半径阈值就触发 GPIO 输出。配合 WiFi 还可以发 HTTP 报警到手机。
// Haversine 公式 — 计算两点间距离(米)
double haversine(double lat1, double lng1,
double lat2, double lng2) {
const double R = 6371000; // 地球半径(米)
double dLat = (lat2 - lat1) * PI / 180.0;
double dLng = (lng2 - lng1) * PI / 180.0;
double a = sin(dLat/2) * sin(dLat/2) +
cos(lat1 * PI/180.0) * cos(lat2 * PI/180.0) *
sin(dLng/2) * sin(dLng/2);
return R * 2 * atan2(sqrt(a), sqrt(1 - a));
}
// 使用示例:判断是否超出500米围栏
double homeLat = 22.5431; // 你的家经纬度
double homeLng = 113.9526;
double distance = haversine(
gps.location.lat(), gps.location.lng(),
homeLat, homeLng
);
if (distance > 500) {
digitalWrite(BUZZER_PIN, HIGH); // 蜂鸣报警!
}
⚠️ 常见问题
❌ 问题1:模块一直显示 "等待定位中",搜不到卫星
原因:GPS 信号无法穿透墙壁和金属。NEO-6M 冷启动首次定位需要 30秒~2分钟,且必须在户外开阔处。
解决:① 将模块放到窗边或阳台;② 模块陶瓷天线朝上(有字一面朝天);③ 耐心等待 2 分钟以上。如果模块上的蓝色 LED 开始闪烁(1秒1闪),说明已锁定卫星。
❌ 问题2:串口收到乱码或 TinyGPS++ 解析不出来
原因:波特率不匹配。部分 NEO-6M 模块出厂波特率不是 9600。
解决:① 先用 USB-TTL 模块直接连接 NEO-6M(TX→RX, RX→TX),在串口助手 9600 波特率下看是否有 $GPGGA 开头的数据;② 如果没有,切换到 4800 / 38400 / 115200 逐个尝试;③ 用 u-center 软件(u-blox 官方工具)重新配置模块波特率。
❌ 问题3:经纬度偏差很大,漂移几百米
原因:① 模块附近有强电磁干扰(电机、大电流走线);② 卫星数少于 4 颗时精度下降;③ HDOP(水平精度因子)过高。
解决:① GPS 模块远离电机和电源走线,至少 5cm;② 检查 gps.hdop.value(),值越小越精确(<1.0 为优秀,>5.0 不可用);③ 在代码中加入滤波——连续取 10 次坐标取中位数。
❌ 问题4:GPS 模块带电拔插后损坏或异常
原因:NEO-6M 模块对电压敏感,热拔插可能导致闩锁效应或损坏 RF 前端。
解决:① 永远断电后再拔插模块;② 在 VCC 引脚并联一个 100μF 电解电容做电源滤波;③ 如果模块异常(灯不亮/不输出),断电放置 30 秒后再上电,通常能复位。