我知道这已被多次询问,但我真的找不到我真正想要的东西。
我使用的是Arduino Uno和GPS Shield,可以通过串口显示GPS数据。
以下是我上传到我的Arduino以连接GPS Shield的代码:
void loop() // run over and over
{
while(!(mySerial.available())){}
Serial.write(mySerial.read());
}
这只是代码。然而,由于它连续循环,在串行监视器上,它还每秒输出GPS数据。
这是每秒的输出:
$GPGGA,013856.000,000.9090,N,9090.90,E,1,09,1.1,316.97,M,0.00,M,,*66 $GPGSA,A,3,07,08,11,1ÿ3,16,19,23,27,42,,,,2.8,1.1,2.5*3F $GPRMC,013856.000,A,000.9090,N,9090.90,E,0.0,038.1,310814,,,A*62 $GPGSV,ÿ3,1,12,16,26,059,33,27,33,025,44,08,30,330,32,07,31,326,34*7A $GPGSV,3,2,12,19,58,354,31,01,33,186,18,23,32,221,24,11,5ÿ9,198,31*70 $GPGSV,3,3,12,42,60,129,32,13,38,253,27,32,06,161,,31,01,140,*7E
当它每秒更新时,坐标变为最小,这意味着GPS盾正在工作。
这里的问题是,我想解析GPS数据,特别是在GPGGA线路上,并忽略其他线路。我想解析状态,纬度,N / S指标,经度和E / W指标。
我搜索了NMEA图书馆(http://nmea.sourceforge.net/),但我不知道如何使用它。
有人可以帮我吗?谢谢。
答案 0 :(得分:1)
我在互联网上搜索过,最好的答案是使用Arduino的“TinyGPS ++”库。几乎所有与GPS相关的代码都已包含在图书馆中。
答案 1 :(得分:1)
NMEA数据采用GPS风格(ddmm.ssss)格式,Google希望它采用十进制风格(dd.mmssss),此步骤的代码底部有一个转换函数。
我写这篇文章是因为我不喜欢大而复杂的图书馆来做简单的小事,特别是在我想弄清楚它是如何工作的时候。 这解析了GLL句子,但您可以更改它要查找的句子,并在需要时重新排列这些句子。
String ReadString;
void setup() {
Serial.begin(9600); //Arduino serial monitor thru USB cable
Serial1.begin(9600); // Serial1 port connected to GPS
}
void loop() {
ReadString=Serial1.readStringUntil(13); //NMEA data ends with 'return' character, which is ascii(13)
ReadString.trim(); // they say NMEA data starts with "$", but the Arduino doesn't think so.
// Serial.println(ReadString); //All the raw sentences will be sent to monitor, if you want them, maybe to see the labels and data order.
//Start Parsing by finding data, put it in a string of character array, then removing it, leaving the rest of thes sentence for the next 'find'
if (ReadString.startsWith("$GPGLL")) { //I picked this sentence, you can pick any of the other labels and rearrange/add sections as needed.
Serial.println(ReadString); // display raw GLL data in Serial Monitor
// mine looks like this: "$GPGLL,4053.16598,N,10458.93997,E,224431.00,A,D*7D"
//This section gets repeated for each delimeted bit of data by looking for the commas
//Find Lattitude is first in GLL sentence, other senetences have data in different order
int Pos=ReadString.indexOf(','); //look for comma delimetrer
ReadString.remove(0, Pos+1); // Remove Pos+1 characters starting at index=0, this one strips off "$GPGLL" in my sentence
Pos=ReadString.indexOf(','); //looks for next comma delimetrer, which is now the first comma because I removed the first segment
char Lat[Pos]; //declare character array Lat with a size of the dbit of data
for (int i=0; i <= Pos-1; i++){ // load charcters into array
Lat[i]=ReadString.charAt(i);
}
Serial.print(Lat); // display raw latitude data in Serial Monitor, I'll use Lat again in a few lines for converting
//repeating with a different char array variable
//Get Lattitude North or South
ReadString.remove(0, Pos+1);
Pos=ReadString.indexOf(',');
char LatSide[Pos]; //declare different variable name
for (int i=0; i <= Pos-1; i++){
LatSide[i]=ReadString.charAt(i); //fill the array
Serial.println(LatSide[i]); //display N or S
}
//convert the variable array Lat to degrees Google can use
float LatAsFloat = atof (Lat); //atof converts the char array to a float type
float LatInDeg;
if(LatSide[0]==char(78)) { //char(69) is decimal for the letter "N" in ascii chart
LatInDeg= ConvertData(LatAsFloat); //call the conversion funcion (see below)
}
if(LatSide[0]==char(83)) { //char(69) is decimal for the letter "S" in ascii chart
LatInDeg= -( ConvertData(LatAsFloat)); //call the conversion funcion (see below)
}
Serial.println(LatInDeg,15); //display value Google can use in Serial Monitor, set decimal point value high
//repeating with a different char array variable
//Get Longitude
ReadString.remove(0, Pos+1);
Pos=ReadString.indexOf(',');
char Longit[Pos]; //declare different variable name
for (int i=0; i <= Pos-1; i++){
Longit[i]=ReadString.charAt(i); //fill the array
}
Serial.print(Longit); //display raw longitude data in Serial Monitor
//repeating with a different char array variable
//Get Longitude East or West
ReadString.remove(0, Pos+1);
Pos=ReadString.indexOf(',');
char LongitSide[Pos]; //declare different variable name
for (int i=0; i <= Pos-1; i++){
LongitSide[i]=ReadString.charAt(i); //fill the array
Serial.println(LongitSide[i]); //display raw longitude data in Serial Monitor
}
//convert to degrees Google can use
float LongitAsFloat = atof (Longit); //atof converts the char array to a float type
float LongInDeg;
if(LongitSide[0]==char(69)) { //char(69) is decimal for the letter "E" in ascii chart
LongInDeg=ConvertData(LongitAsFloat); //call the conversion funcion (see below
}
if(LongitSide[0]==char(87)) { //char(87) is decimal for the letter "W" in ascii chart
LongInDeg=-(ConvertData(LongitAsFloat)); //call the conversion funcion (see below
}
Serial.println(LongInDeg,15); //display value Google can use in Serial Monitor, set decimal point value high
//repeating with a different char array variable
//Get TimeStamp - GMT
ReadString.remove(0, Pos+1);
Pos=ReadString.indexOf(',');
char TimeStamp[Pos]; //declare different variable name
for (int i=0; i <= Pos-1; i++){
TimeStamp[i]=ReadString.charAt(i); //fill the array
}
Serial.print(TimeStamp); //display raw longitude data in Serial Monitor, GMT
Serial.println("");
}
}
//Conversion function
float ConvertData(float RawDegrees)
{
float RawAsFloat = RawDegrees;
int firstdigits = ((int)RawAsFloat)/100; // Get the first digits by turning f into an integer, then doing an integer divide by 100;
float nexttwodigits = RawAsFloat - (float)(firstdigits*100);
float Converted = (float)(firstdigits + nexttwodigits/60.0);
return Converted;
}
答案 2 :(得分:1)
我写了这个体面的代码,它可以工作到小数点后两位。
代码:
String gpsData;
String LATval = "######";
String LNGval = "######";
char inChar;
String gpsData;
String latt;
String la;
String lonn;
String lo;
float lattt;
float lonnn;
int latDeg;
int lonDeg;
float latMin;
float lonMin;
float latttt;
float lonnnn;
String sGPRMC;
void setup() {
Serial.begin(9600);
}
void loop() {
while (Serial.available()) {
inChar = Serial.read();
gpsData += inChar;
if (inChar == '$') {
gpsData = Serial.readStringUntil('\n');
break;
}
}
Serial.println(gpsData);
sGPRMC = gpsData.substring(0, 5);
if (sGPRMC == "GPRMC") {
Serial.flush();
latt = gpsData.substring(18, 28);
la = gpsData.substring(29, 30);
lonn = gpsData.substring(31, 42);
lo = gpsData.substring(43, 44);
Serial.print("latt:");
Serial.println(latt);
Serial.print("la:");
Serial.println(la);
Serial.print("lonn:");
Serial.println(lonn);
Serial.print("lo:");
Serial.println(lo);
lattt = latt.toFloat();
lonnn = lonn.toFloat();
Serial.print("lattt:");
Serial.println(lattt);
Serial.print("lonnn:");
Serial.println(lonnn);
if (la == "N" and lo == "E") {
latDeg = float(int(lattt / 100));
latMin = float(lattt - (latDeg * 100));
latMin = latMin / 60;
lonDeg = float(int(lonnn / 100));
lonMin = float(lonnn - (lonDeg * 100));
lonMin = lonMin / 60;
latttt = latDeg + latMin;
lonnnn = lonDeg + lonMin;
LATval = String(latttt);
LNGval = String(lonnnn);
Serial.print("latDeg:");
Serial.println(latDeg);
Serial.print("latMin:");
Serial.println(latMin);
Serial.print("lonDeg:");
Serial.println(lonDeg);
Serial.print("lonMin:");
Serial.println(lonMin);
Serial.print("LATval:");
Serial.println(LATval);
Serial.print("LNGval:");
Serial.println(LNGval);
}
}
}
答案 3 :(得分:0)
您可以使用TinyGPS来解析NMEA字符串。如果您只对1个句子感兴趣。您只能为该句子编写如下自定义解析器。
int handle_byte(int byteGPS) {
buf[counter1] = byteGPS;
//Serial.print((char)byteGPS);
counter1++;
if (counter1 == 300) {
return 0;
}
if (byteGPS == ',') {
counter2++;
offsets[counter2] = counter1;
if (counter2 == 13) {
return 0;
} } if (byteGPS == '*') {
offsets[12] = counter1; }
// Check if we got a <LF>, which indicates the end of line if (byteGPS == 10) {
// Check that we got 12 pieces, and that the first piece is 6 characters
if (counter2 != 12 || (get_size(0) != 6)) {
return 0;
}
// Check that we received $GPRMC
// CMD buffer contains $GPRMC
for (int j=0; j<6; j++) {
if (buf[j] != cmd[j]) {
return 0;
}
}
// Check that time is well formed
if (get_size(1) != 10) {
return 0;
}
// Check that date is well formed
if (get_size(9) != 6) {
return 0;
}
SeeedOled.setTextXY(7,0);
for (int j=0; j<6; j++) {
SeeedOled.putChar(*(buf+offsets[1]+j));
}
SeeedOled.setTextXY(7,7);
for (int j=0; j<6; j++) {
SeeedOled.putChar(*(buf+offsets[9]+j));
}
// TODO: compute and validate checksum
// TODO: handle timezone offset
return 0; }
return 1; }
答案 4 :(得分:0)
尝试这可以帮助你
#include <SoftwareSerial.h>
#include <TinyGPS.h>
TinyGPS gps;
SoftwareSerial ss(3,4);
static void smartdelay(unsigned long ms);
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);
void setup()
{
Serial.begin(9600);
ss.begin(9600);
}
void loop()
{
float flat, flon;
unsigned short sentences = 0, failed = 0;
gps.f_get_position(&flat, &flon);
Serial.print("LATITUDE: ");
print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 10, 6);
Serial.println(" ");
Serial.print("LONGITUDE: ");
print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 11, 6);
Serial.println(" ");
Serial.print("altitude: ");
print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 7, 2);
Serial.println(" ");
Serial.print("COURSE:");
print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
Serial.println("");
Serial.print("DIRECTION: ");
int d;
print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
d=gps.f_course();
Serial.println();
Serial.println();
smartdelay(1000);
}
static void smartdelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
static void print_float(float val, float invalid, int len, int prec)
{
if (val == invalid)
{
while (len-- > 1)
Serial.print('*');
Serial.print(' ');
}
else
{
Serial.print(val, prec);
int vi = abs((int)val);
int flen = prec + (val < 0.0 ? 2 : 1); // . and -
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i=flen; i<len; ++i)
Serial.print(' ');
}
smartdelay(0);
}
static void print_int(unsigned long val, unsigned long invalid, int len)
{
char sz[32];
if (val == invalid)
strcpy(sz, "*******");
else
sprintf(sz, "%ld", val);
sz[len] = 0;
for (int i=strlen(sz); i<len; ++i)
sz[i] = ' ';
if (len > 0)
sz[len-1] = ' ';
Serial.print(sz);
smartdelay(0);
}
static void print_str(const char *str, int len)
{
int slen = strlen(str);
for (int i=0; i<len; ++i)
Serial.print(i<slen ? str[i] : ' ');
smartdelay(0);
}