想给小车或者机器狗加一套定位,GPS 模块几乎是最顺手的选择。但不少人接上模块、打开串口,看到一屏以 $GP 开头的“天书”就卡住了——那其实是 NMEA 语句,定位数据全都藏在里面。这篇把接线、NMEA 语句长什么样、怎么用库把经纬度读出来一次讲清。示例图取自 Adafruit 官方教程里的 Ultimate GPS 模块;u-blox NEO-6 系列的型号参数逐项对照官方产品页,官方页没给的项直接写“官方未公布”。

先看官方页:NEO-6 系列给了哪些参数
u-blox 官方产品页对 NEO-6 系列的定位写得很直白:多用途的 u-blox 6 代 GPS 模块。有一个选型前必须知道的事实:官方页已把 NEO-6G、NEO-6Q、NEO-6M 三个型号全部标注 EOL(寿命终止),并注明新设计建议改用 NEO-M9N。市面上的 NEO-6M 模块大多是库存件,功能正常,但选型心里要有数。
参数表上能确认的:接口有 UART、USB、DDC(兼容 I2C)和 SPI;分 Crystal 和 TCXO 两种振荡器版本;板载 RTC 晶振,可以更快完成 warm start 和 hot start;供电上限 3.6V,最小供电标了 1.75V 与 2.7V 两组;工作温度零下 40 到 85 摄氏度;尺寸 16×12.2×2.4 毫米;支持秒脉冲(time pulse)输出。
更新率、灵敏度、通道数、定位精度这四项,官方产品页没有列——按规矩写“官方未公布”。网上不少教程给 NEO-6M 标更新率或某个 dBm 灵敏度值,这些不在官方页上,最终口径应以 datasheet 为准,别直接安到头上。
四根线接起来,串口交叉是唯一要点
GPS 模块本质上就是一个串口设备,接线只有四根。官方接线页的做法:VIN 接 +5V,GND 接地,模块 RX 接数字 7 脚,模块 TX 接数字 8 脚;示例代码里的构造函数是 SoftwareSerial(8, 7),也就是板子上 RX=8、TX=7。唯一容易搞错的是交叉关系:Arduino 的 TX 接模块的 RX,Arduino 的 RX 接模块的 TX。
| GPS 模块引脚 | Arduino UNO | 说明 |
|---|---|---|
| VIN | 5V | 供电,3.3 到 5VDC 均可 |
| GND | GND | 共地 |
| RX | D7 | 接 Arduino 的 TX(SoftwareSerial 的 TX=7) |
| TX | D8 | 接 Arduino 的 RX(SoftwareSerial 的 RX=8) |
供电和电平官方页也给了底:板载低压差 3.3V 稳压器,3.3 到 5VDC 供电都行,输入脚 5V 安全,导航时电流只有 20mA 左右。板上还有定位指示灯:搜星时大约 1 秒闪一次,定位成功后改为每 15 秒闪一次,盯灯比盯屏幕更快判断状态。没有多余硬件串口的板子就用 SoftwareSerial,按 9600 波特率收发。

NMEA 语句长什么样:先看原始输出
上电后模块就开始往外吐 NMEA 语句,每句以 $GP 开头、回车换行结尾。下面这张串口监视器截图取自官方教程,$GPGGA、$GPGLL、$GPRMC、$GPVTG、$GPGSA、$GPGSV 全都在往外蹦——每句负责一种信息,有的报定位、有的报卫星、有的报航向速度。

句子不是越多越好。官方接线页的示例代码用 sendCommand 控制模块输出哪些句子、以什么频率更新,原样贴在下面:
// You can adjust which sentences to have the module emit, below
// uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
// uncomment this line to turn on only the "minimum recommended" data for high update rates!
//GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
// uncomment this line to turn on all the available data - for 9600 baud you'll want 1 Hz rate
//GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_ALLDATA);
// Set the update rate
// 1 Hz update rate
//GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
// 5 Hz update rate- for 9600 baud you'll have to set the output to RMC or RMCGGA only (see above)
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ);
// 10 Hz update rate - for 9600 baud you'll have to set the output to RMC only (see above)
//GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ); 代码注释已经把关系讲明:RMC 是 recommended minimum(推荐最小语句集),GGA 是定位数据、含海拔高度;9600 波特率下要开全量语句就只能跑 1Hz,想上 5Hz 或 10Hz 就得只开 RMC 或 RMCGGA。换句话说,输出句子和更新率是一对要一起权衡的旋钮,带宽就那么点,全开必然互相拖累。
把经纬度读出来:解析交给库
手写 NMEA 解析没必要。官方解析页的思路是:库在后台中断里完成读取、存储和解析,主循环只管查询最新结果,一行字符串处理都不用碰。
流程三步:主循环里不停调 GPS.read();GPS.newNMEAreceived() 返回 true 时,用 GPS.parse(GPS.lastNMEA()) 解析这一句;解析完就能直接读字段。解析必须放在主循环里持续做,官方明确说不能挪进中断,否则会丢数据。
能读的字段:GPS.day、GPS.month、GPS.year 是日期;GPS.fix 为 1 表示有定位;有定位时 GPS.latitude、GPS.longitude 就是经纬度,GPS.speed 是速度、GPS.angle 是航向、GPS.altitude 是海拔、GPS.satellites 是卫星数。两个单位坑官方原文特意标了:速度单位是节(knots),不是 mph 也不是 km/h;海拔单位是厘米。想把节换算成 km/h,乘 1.852 再打印就行。
完整示例不用自己拼:装好 Adafruit_GPS 库后,从 IDE 菜单打开 File→Examples→Adafruit_GPS→GPS_HardwareSerial_Parsing 或 GPS_SoftwareSerial_Parsing,接线沿用上一节。想自己定输出句子和更新率,就在 setup 里加上一节的 sendCommand 配置。
官方解析页给的建议很具体:更新率保持 1Hz,只让模块输出 RMC 和 GGA 两种句子——解析器本身不跟踪其他句子的数据,多开是白占串口带宽。
定位之前:天线和几个真容易踩的坑
没有 fix 之前,时间和位置都拿不准。官方提醒:模块要贴着窗户朝上,或者干脆放到户外,才能拿到数据;通常先收到时间信息,再收到位置——因为两者需要的卫星数不一样多。
室内搜不到星,第一反应是换天线。Adafruit 这块板内置贴片天线,同时留了 u.FL 座接外置有源天线,官方商店就有 3 到 5V、28dB、5 米 SMA 头的有源天线配件,配一根 SMA 转 u.FL 转接线就能用。NEO-6 系列裸模组同理,天线朝向和头顶遮挡对搜星速度的影响,比大多数参数都大。

后备电池也值得装:板上有 CR1220 纽扣电池座,装上后 RTC 断电继续走,支持 warm start,重新上电能更快拿到定位。
最后回到选型:NEO-6M 已经是官方标注 EOL 的型号,买库存件练手没问题,做新项目建议按官方页的指引看 NEO-M9N。参数口径回归官方页和 datasheet,官方没写的就写“官方未公布”,别让二手教程替官方发言。











看完才知道 $GP 开头那一屏乱码叫 NMEA,原来每句都有分工,长知识了。
补充一个我踩过的点:NEO-6M 这种串口模块如果用 SoftwareSerial,读写别开太高波特率,9600 就很稳,句子丢字段多半是软串口跟不上。另外 GPS.speed 出来是节,换 km/h 记得乘 1.852,直接打印出来你会以为模块坏了。海拔是厘米这个也容易忘,建议拿到手先打印一条原始语句对着看。
搜星一定要放窗边或者户外,我第一次测试把板子埋在桌面的线堆里,半小时一个星都搜不到,挪到窗台上两分钟就有 fix 了,血泪教训。
速度单位是节不是 km/h,这个坑官方文档都特意标注了,还是每年有人栽进去。
NEO-6M 官方都标 EOL 了,二手市场还一堆库存件在卖。练手没问题,真要做项目建议直接上新一代,别省那十几块钱。