本教程介绍如何将 NEO-6M GPS 模块与 Arduino 一起使用来获取 GPS 数据。GPS 代表全球定位系统,可用于确定旅行时的位置、时间和速度。
你将学习如何:
- 将 NEO-6M GPS 模块连接到 Arduino UNO
- 获取原始 GPS 数据
- 解析原始数据以获取选定且可读的 GPS 信息
- 获取位置
目录
介绍 NEO-6M GPS 模块
NEO-6M GPS模块如下图所示。它带有一个外部天线,并且没有带接头引脚。因此,您需要获得并焊接一些。
- 该模块具有外部天线和内置 EEPROM。
- 接口:RS232 TTL
- 电源:3V至5V
- 默认波特率:9600 bps
- 适用于标准 NMEA 句子
NEO-6M GPS模块还与其他微控制器板兼容。要了解如何将 NEO-6M GPS 模块与 Raspberry Pi 一起使用,您可以阅读:使用 Raspberry Pi 和 GPS 模块更改位置的电子邮件警报系统。
哪里可以买到?
您可以以 6 美元到 5 美元的价格购买 NEO-20M GPS 模块。我们建议您查看 Maker Advisor 上的 NEO-6M GPS 模块页面,比较不同商店的价格并找到最好的。
引脚接线
NEO-6M GPS 模块有四个引脚:VCC、RX、TX 和 GND。该模块使用 TX 和 RX 引脚通过串行通信与 Arduino 通信,因此接线再简单不过了:
NEO-6M GPS模块 | 连接到Arduino UNO |
VCC | 5V |
RX | 软件串行中定义的 TX 引脚 |
TX | 软件串行中定义的RX引脚 |
GND | GND |
获取 GPS 原始数据
要获取原始 GPS 数据,您只需使用软件串行开始与 GPS 模块进行串行通信。继续阅读以了解如何做到这一点。
所需零件
若要测试此示例,需要以下部件:
- Arduino
- NEO-6M GPS模块
- 跳线
连接图
按照下面的原理图将 NEO-6M GPS 模块连接到您的 Arduino。
- 模块GND引脚连接到Arduino GND引脚
- 模块RX引脚连接到Arduino引脚3
- 模块TX引脚连接到Arduino引脚4
- 模块VCC引脚连接到Arduino 5V引脚
使用方法
将以下代码复制到Arduino IDE并将其上传到Arduino开发板。
此程序假设您使用引脚 4 和引脚 3 作为 RX 和 TX 串行引脚,以建立与 GPS 模块的串行通信。如果您使用的是其他图钉,则应在以下行中对其进行编辑:
SoftwareSerial ss(4, 3);
此外,如果您的模块使用的默认波特率与 9600 bps 不同,则应修改以下行中的代码:
ss.begin(9600);
该程序监听GPS串口,当从模块接收到数据时,将其发送到串口监视器。
while (ss.available() > 0){
// get the byte data from the GPS
byte gpsData = ss.read();
Serial.write(gpsData);
}
以 9600 的波特率打开串行监视器。
您应该以 GPS 标准语言 NMEA 获得一堆信息。您在串行监视器中得到的每一行都是一个 NMEA 语句。
NMEA 代表美国国家海洋电子协会,在 GPS 世界中,它是 GPS 制造商支持的标准数据格式。
理解 NMEA 句子
NMEA 语句以 $ 字符开头,每个数据字段用逗号分隔。
$GPGGA,110617.00,41XX.XXXXX,N,00831.54761,W,1,05,2.68,129.0,M,50.1,M,,*42 $GPGSA,A,3,06,09,30,07,23,,,,,,,,4.43,2.68,3.53*02 $GPGSV,3,1,11,02,48,298,24,03,05,101,24,05,17,292,20,06,71,227,30*7C $GPGSV,3,2,11,07,47,138,33,09,64,044,28,17,01,199,,19,13,214,*7C $GPGSV,3,3,11,23,29,054,29,29,01,335,,30,29,167,33*4E $GPGLL,41XX.XXXXX,N,00831.54761,W,110617.00,A,A*70 $GPRMC,110618.00,A,41XX.XXXXX,N,00831.54753,W,0.078,,030118,,,A*6A $GPVTG,,T,,M,0.043,N,0.080,K,A*2C
NMEA 句子有多种类型。消息的类型由第一个逗号前的字符指示。
$ 后面的 GP 表示它是 GPS 位置。 $GPGGA是基本的 GPS NMEA 消息,提供 3D 位置和精度数据。在下面的句子中:
$GPGGA,110617.00,41XX.XXXXX,N,00831.54761,W,1,05,2.68,129.0,M,50.1,M,,*42
- 110617 – 表示获取修复位置的时间,11:06:17 UTC
- 41XX.XXXXX,N – 北纬 41 度 XX.XXXXX’
- 00831.54761,W – 经度 008 度 31.54761′ W
- 1 – 定位质量(0 = 无效;1 = GPS 定位;2 = DGPS 定位;3 = PPS 定位;4 = 实时运动学;5 = 浮动 RTK;6 = 估计(航位推算);7 = 手动输入模式;8 = 模拟模式)
- 05 – 被跟踪的卫星数量
- 2.68 – 水平稀释位置
- 129.0, M – 海拔高度,以海平面以上米为单位
- 50.1, M – WGS84 椭球体上方的大地水准面(平均海平面)高度
- 空字段 – 自上次 DGPS 更新以来的时间(以秒为单位)
- 空字段 – DGPS 站 ID 号
- *42 – 校验和数据,始终以 * 开头
其他 NMEA 句子提供了其他信息:
- $GPGSA – GPS DOP 和活动卫星
- $GPGSV – 详细的 GPS 卫星信息
- $GPGLL – 地理纬度和经度
- $GPRMC – 基本 GPS pvt(位置、速度、时间)数据
- $GPVTG – 速度很好
要了解每个数据字段在每句话中的含义,您可以在此处查阅 NMEA 数据。
使用 TinyGPS++ 库解析 NMEA 句子
您可以使用来自 GPS 的原始数据,也可以通过将字符序列保存到变量中来将这些 NMEA 消息转换为可读且有用的格式。为此,我们将使用 TinyGPS++ 库。
该库使以有用且易于理解的格式获取位置信息变得简单。您可以单击此处了解有关 TinyGPS++ 库的更多信息。
安装 TinyGPS++ 库
按照以下步骤在Arduino IDE中安装TinyGPS++库:
该库提供了几个关于如何使用它的示例。在Arduino IDE中,您只需要转到TinyGPS++>文件>示例,然后从提供的示例中进行选择。
注意:库中提供的示例假设 GPS 模块的波特率为 4800。如果您使用的是 NEO-9600M GPS 模块,则需要将其更改为 6。
使用 NEO-6M GPS 模块和 TinyGPS++ 库获取位置
您可以使用 TinyGPS++ 库以方便且有用的格式获取位置。下面,我们提供了一个代码来从 GPS 获取位置。这是其中一个库示例的简化版本。
/*
* https://www.qutaojiao.com
*/
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
void setup(){
Serial.begin(9600);
ss.begin(GPSBaud);
}
void loop(){
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0){
gps.encode(ss.read());
if (gps.location.isUpdated()){
Serial.print("Latitude= ");
Serial.print(gps.location.lat(), 6);
Serial.print(" Longitude= ");
Serial.println(gps.location.lng(), 6);
}
}
}
首先导入所需的库:TinyGPSPlus 和 SoftwareSerial
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
然后,定义软件串行 RX 和 TX 引脚,以及 GPS 波特率。如果您将其他引脚用于软件串行,则需要在此处进行更改。此外,如果您的 GPS 模块使用不同的默认波特率,您还应该对其进行修改。
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
然后,创建一个 TinyGPS++ 对象:
TinyGPSPlus gps;
并在您之前定义的引脚上启动串行连接
SoftwareSerial ss(RXPin, TXPin);
在 setup() 中,您可以初始化串行通信,既可以查看串行监视器上的读数,也可以与 GPS 模块进行通信。
void setup() {
Serial.begin(9600);
ss.begin(GPSBaud);
}
在循环中是您请求信息的地方。要使 TinyGPS++ 正常工作,您必须使用 encode() 方法从 GPS 模块重复将字符汇集到它。
while (ss.available() > 0){
gps.encode(ss.read());
然后,您可以查询 gps 对象以查看是否有任何数据字段已更新:
if (gps.location.isUpdated()){
Serial.print("Latitude="); Serial.print(gps.location.lat(), 6);
Serial.print("Longitude="); Serial.println(gps.location.lng(), 6);
}
获取纬度和经度很简单,分别使用 gps.location.lat() 和 gps.location.lng()。
将代码上传到Arduino,您应该会看到串行监视器上显示的位置。上传代码后,等待几分钟,模块调整位置以获得更准确的数据。
使用 TinyGPS++ 库获取更多 GPS 信息
TinyGPS++ 库允许您以简单的方式获得更多信息,而不仅仅是位置。除了位置,您还可以获得:
- 日期
- 时间
- 速度
- 课程
- 高度
- 卫星
- HDOP的
下面的代码举例说明了如何以简单的方式获取所有这些信息。
/*
* https://www.qutaojiao.com
*
* Based on the example TinyGPS++ from arduiniana.org
*
*/
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
void setup(){
Serial.begin(9600);
ss.begin(GPSBaud);
}
void loop(){
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0){
gps.encode(ss.read());
if (gps.location.isUpdated()){
// Latitude in degrees (double)
Serial.print("Latitude= ");
Serial.print(gps.location.lat(), 6);
// Longitude in degrees (double)
Serial.print(" Longitude= ");
Serial.println(gps.location.lng(), 6);
// Raw latitude in whole degrees
Serial.print("Raw latitude = ");
Serial.print(gps.location.rawLat().negative ? "-" : "+");
Serial.println(gps.location.rawLat().deg);
// ... and billionths (u16/u32)
Serial.println(gps.location.rawLat().billionths);
// Raw longitude in whole degrees
Serial.print("Raw longitude = ");
Serial.print(gps.location.rawLng().negative ? "-" : "+");
Serial.println(gps.location.rawLng().deg);
// ... and billionths (u16/u32)
Serial.println(gps.location.rawLng().billionths);
// Raw date in DDMMYY format (u32)
Serial.print("Raw date DDMMYY = ");
Serial.println(gps.date.value());
// Year (2000+) (u16)
Serial.print("Year = ");
Serial.println(gps.date.year());
// Month (1-12) (u8)
Serial.print("Month = ");
Serial.println(gps.date.month());
// Day (1-31) (u8)
Serial.print("Day = ");
Serial.println(gps.date.day());
// Raw time in HHMMSSCC format (u32)
Serial.print("Raw time in HHMMSSCC = ");
Serial.println(gps.time.value());
// Hour (0-23) (u8)
Serial.print("Hour = ");
Serial.println(gps.time.hour());
// Minute (0-59) (u8)
Serial.print("Minute = ");
Serial.println(gps.time.minute());
// Second (0-59) (u8)
Serial.print("Second = ");
Serial.println(gps.time.second());
// 100ths of a second (0-99) (u8)
Serial.print("Centisecond = ");
Serial.println(gps.time.centisecond());
// Raw speed in 100ths of a knot (i32)
Serial.print("Raw speed in 100ths/knot = ");
Serial.println(gps.speed.value());
// Speed in knots (double)
Serial.print("Speed in knots/h = ");
Serial.println(gps.speed.knots());
// Speed in miles per hour (double)
Serial.print("Speed in miles/h = ");
Serial.println(gps.speed.mph());
// Speed in meters per second (double)
Serial.print("Speed in m/s = ");
Serial.println(gps.speed.mps());
// Speed in kilometers per hour (double)
Serial.print("Speed in km/h = ");
Serial.println(gps.speed.kmph());
// Raw course in 100ths of a degree (i32)
Serial.print("Raw course in degrees = ");
Serial.println(gps.course.value());
// Course in degrees (double)
Serial.print("Course in degrees = ");
Serial.println(gps.course.deg());
// Raw altitude in centimeters (i32)
Serial.print("Raw altitude in centimeters = ");
Serial.println(gps.altitude.value());
// Altitude in meters (double)
Serial.print("Altitude in meters = ");
Serial.println(gps.altitude.meters());
// Altitude in miles (double)
Serial.print("Altitude in miles = ");
Serial.println(gps.altitude.miles());
// Altitude in kilometers (double)
Serial.print("Altitude in kilometers = ");
Serial.println(gps.altitude.kilometers());
// Altitude in feet (double)
Serial.print("Altitude in feet = ");
Serial.println(gps.altitude.feet());
// Number of satellites in use (u32)
Serial.print("Number os satellites in use = ");
Serial.println(gps.satellites.value());
// Horizontal Dim. of Precision (100ths-i32)
Serial.print("HDOP = ");
Serial.println(gps.hdop.value());
}
}
}
TinyGPS++ 库在如何使用其所有功能方面得到了很好的评论。
总结
希望本教程对您有所帮助。