想要使用 arduino 每 5 秒获取一次 GPS 数据
Want to get GPS data at every 5 sec using arduino
我用头文件TinyGPSPlus在Arduino uno中编写了以下代码,并使用了GPS SKG 13BL(GPS模块)。
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This program sketch obtain and print the lati,logi,speed,date and time
It requires the use of SoftwareSerial, and assumes that you have a
9600-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
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);
Serial.println(F("GPS LOADING....."));
Serial.println(F("Obtain and print lati,logi,speed,date and time"));
Serial.println(F("Testing by : "));
Serial.println(F("Billa"));
Serial.println();
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read()))
displayInfo();
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
Serial.print(gps.location.lat(), 6);
Serial.print(F(","));
Serial.print(gps.location.lng(), 6);
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Speed: "));
if (gps.speed.isValid())
{
Serial.print(gps.speed.kmph());
Serial.print(F(" KMPH "));
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Date : "));
if (gps.date.isValid())
{
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Time : "));
if (gps.time.isValid())
{
int hour= gps.time.hour() + 5;
if (hour < 10) Serial.print(F("0"));
if(hour > 12) hour-=11;
Serial.print(hour);
Serial.print(F(":"));
int minute = gps.time.minute() + 30;
if(minute >= 60) minute-=60;
if (minute < 10) Serial.print(F("0"));
Serial.print(minute);
Serial.print(F(":"));
if (gps.time.second() < 10) Serial.print(F("0"));
Serial.print(gps.time.second());
}
else
{
Serial.print(F("INVALID"));
}
Serial.println();
}
在串口监视器上连续获取了需要的output.Displays行数据。
但是现在我需要每 5 秒准确获取这些数据(即 每 5 秒上面的代码应该根据那个瞬间生成输出) .我尝试使用延迟来做到这一点,并重写了循环代码如下
void loop()
{
delay(5000);
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read()))
displayInfo();
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
}
但是这并没有得到想要的输出。谁能帮我解决一下this.Where我应该编辑什么吗?
使用此库时应避免使用正常的延迟功能,因为它需要定期进行新修复。在示例代码中,您会发现一个名为 smartDelay()
的函数,将此函数复制到您的代码中并改用它。看起来像这样。
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
将此代码放在调用 smartDelay(5000);
时代码的底部,而不是 void loop()
底部的 delay(5000);
您还应该像这样在 smartDelay()
下方调用 displayInfo();
。
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
if (millis() > 5000 && gps.charsProcessed() < 10) {
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
smartDelay(5000);
displayInfo();
}
编辑:更好的方法
更好的方法是使用 millis()
,特别是如果您喜欢在显示数据时做其他事情。这也将每 5 秒调用一次更精确。
您必须在顶部声明一个变量才能使其工作。它看起来像这样。
long timeToDisplay = 0; // Declare this at the top
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
if (millis() > 5000 && gps.charsProcessed() < 10) {
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
if(timeToDisplay <= millis()) {
timeToDisplay = millis() + 5000;
displayInfo();
}
}
这正是我写 NeoGPS 的原因。所有其他库的示例程序结构不正确。我在看着你,smartDelay()
...
NeoGPS 的结构是从 GPS 设备接收完整的 fix
。这通常需要接收几个句子。其他 GPS 库仅在收到一句话时告诉您。此外,很难判断两个句子是来自相同的 1 秒更新间隔,还是两个连续的间隔。
您想每 5 秒显示一次信息,但那可能是每 20 个句子显示一次。根据 Arduino millis()
时钟,它将是 大约 5000 毫秒, 但不完全是 。 millis()
将根据您的 crystal 的准确度与 GPS 间隔发生漂移。 GPS间隔非常准确,受限于原子钟、串口波特率、GPS设备计算时间。
这是您的草图,已修改为使用 NeoGPS:
#include <NMEAGPS.h>
/*
This program sketch obtain and print the lati,logi,speed,date and time
It requires the use of SoftwareSerial, and assumes that you have a
9600-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
#include <NeoSWSerial.h>
static const int RXPin = 4, TXPin = 3;
NeoSWSerial gpsPort(RXPin, TXPin);
static const uint32_t GPSBaud = 9600;
NMEAGPS gps;
gps_fix fix;
uint8_t fixCount = 0;
void setup()
{
Serial.begin(9600);
gpsPort.begin(GPSBaud);
Serial.println(F("GPS LOADING....."));
Serial.println(F("Obtain and print lati,logi,speed,date and time"));
Serial.println(F("Testing by : "));
Serial.println(F("Billa"));
Serial.println();
}
void loop()
{
while (gps.available( gpsPort )) {
fix = gps.read();
// Once every 5 seconds...
if (++fixCount >= 5) {
displayInfo();
fixCount = 0;
}
}
if ((gps.statistics.chars < 10) && (millis() > 5000)) {
Serial.println( F("No GPS detected: check wiring.") );
while(true);
}
}
void displayInfo()
{
Serial.print(F("Location: "));
if (fix.valid.location) {
Serial.print( fix.latitude(), 5 );
Serial.print( ',' );
Serial.print( fix.longitude(), 5 );
} else {
Serial.print(F("INVALID"));
}
Serial.print(F(" Speed: "));
if (fix.valid.speed) {
Serial.print(fix.speed_kph());
Serial.print(F(" KMPH "));
} else {
Serial.print(F("INVALID"));
}
// Shift the date/time to local time
NeoGPS::clock_t localSeconds;
NeoGPS::time_t localTime;
if (fix.valid.date && fix.valid.time) {
using namespace NeoGPS; // save a little typing below...
localSeconds = (clock_t) fix.dateTime; // convert structure to a second count
localSeconds += 5 * SECONDS_PER_HOUR + 30 * SECONDS_PER_MINUTE; // shift timezone
localTime = localSeconds; // convert back to a structure
}
Serial.print(F(" Date : "));
if (fix.valid.date) {
Serial.print(localTime.month);
Serial.print('/');
Serial.print(localTime.date);
Serial.print('/');
Serial.print(localTime.year);
} else {
Serial.print(F("INVALID"));
}
Serial.print(F(" Time : "));
if (fix.valid.time) {
Serial.print(localTime.hours);
Serial.print(':');
if (localTime.minutes < 10) Serial.print('0');
Serial.print(localTime.minutes);
Serial.print(':');
if (localTime.seconds < 10) Serial.print(F("0"));
Serial.print(localTime.seconds);
} else {
Serial.print(F("INVALID"));
}
Serial.println();
}
此草图显示每五分之一 fix
,没有使用不准确的 millis()
或令人讨厌的 delay()
。没有人有时间做那个!
并且每个修复都是从每个 1 秒间隔的 所有 个句子中累积的,无论是一个句子(RMC?),还是 8 个句子(GGA,GLL,RMC, GSV*3、GSA 和 VTG)。在 NeoGPS 中,计算修复等同于计算秒数。
注意:如果您需要超精确的 5 秒间隔,请考虑使用 PPS 引脚(如果可用)。
本地时间在此草图中计算正确,即使时区转换进入新的小时、日期、月份或年份。您的草图没有正确跨越日期边界。 5.5 小时轮班,如果我没看错的话。
我应该说 NeoGPS 比所有其他库更小、更快和更准确吗? :) 它可以从 Arduino IDE 库管理器中获得,在菜单 Sketch -> Include Library -> Manage Libraries.
下
您还应该考虑使用 SoftwareSerial
以外的东西。这是非常低效的,因为它会长时间禁用中断。这可能会干扰草图的其他部分或其他库。
最好的软件串口库是AltSoftSerial。如果您可以切换到引脚 8 和 9,我强烈建议您这样做。
如果你不能切换引脚(你真的确定吗?),你应该使用我的NeoSWSerial。它适用于任何两个引脚,而且效率几乎一样。支持您使用的9600波特率
slash-dev 给我一个关于如何在 5 秒间隔内获取数据的答案 GPS.He 还提供了一些改进的方法,当我遵循时获得完美 output.It 解决了代码中的一些错误我提供了 too.Link 的答案:
结果:
https://i.stack.imgur.com/pzvsu.png
我用头文件TinyGPSPlus在Arduino uno中编写了以下代码,并使用了GPS SKG 13BL(GPS模块)。
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This program sketch obtain and print the lati,logi,speed,date and time
It requires the use of SoftwareSerial, and assumes that you have a
9600-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
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);
Serial.println(F("GPS LOADING....."));
Serial.println(F("Obtain and print lati,logi,speed,date and time"));
Serial.println(F("Testing by : "));
Serial.println(F("Billa"));
Serial.println();
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read()))
displayInfo();
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
Serial.print(gps.location.lat(), 6);
Serial.print(F(","));
Serial.print(gps.location.lng(), 6);
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Speed: "));
if (gps.speed.isValid())
{
Serial.print(gps.speed.kmph());
Serial.print(F(" KMPH "));
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Date : "));
if (gps.date.isValid())
{
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Time : "));
if (gps.time.isValid())
{
int hour= gps.time.hour() + 5;
if (hour < 10) Serial.print(F("0"));
if(hour > 12) hour-=11;
Serial.print(hour);
Serial.print(F(":"));
int minute = gps.time.minute() + 30;
if(minute >= 60) minute-=60;
if (minute < 10) Serial.print(F("0"));
Serial.print(minute);
Serial.print(F(":"));
if (gps.time.second() < 10) Serial.print(F("0"));
Serial.print(gps.time.second());
}
else
{
Serial.print(F("INVALID"));
}
Serial.println();
}
在串口监视器上连续获取了需要的output.Displays行数据。 但是现在我需要每 5 秒准确获取这些数据(即 每 5 秒上面的代码应该根据那个瞬间生成输出) .我尝试使用延迟来做到这一点,并重写了循环代码如下
void loop()
{
delay(5000);
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read()))
displayInfo();
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
}
但是这并没有得到想要的输出。谁能帮我解决一下this.Where我应该编辑什么吗?
使用此库时应避免使用正常的延迟功能,因为它需要定期进行新修复。在示例代码中,您会发现一个名为 smartDelay()
的函数,将此函数复制到您的代码中并改用它。看起来像这样。
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
将此代码放在调用 smartDelay(5000);
时代码的底部,而不是 void loop()
底部的 delay(5000);
您还应该像这样在 smartDelay()
下方调用 displayInfo();
。
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
if (millis() > 5000 && gps.charsProcessed() < 10) {
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
smartDelay(5000);
displayInfo();
}
编辑:更好的方法
更好的方法是使用 millis()
,特别是如果您喜欢在显示数据时做其他事情。这也将每 5 秒调用一次更精确。
您必须在顶部声明一个变量才能使其工作。它看起来像这样。
long timeToDisplay = 0; // Declare this at the top
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
if (millis() > 5000 && gps.charsProcessed() < 10) {
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
if(timeToDisplay <= millis()) {
timeToDisplay = millis() + 5000;
displayInfo();
}
}
这正是我写 NeoGPS 的原因。所有其他库的示例程序结构不正确。我在看着你,smartDelay()
...
NeoGPS 的结构是从 GPS 设备接收完整的 fix
。这通常需要接收几个句子。其他 GPS 库仅在收到一句话时告诉您。此外,很难判断两个句子是来自相同的 1 秒更新间隔,还是两个连续的间隔。
您想每 5 秒显示一次信息,但那可能是每 20 个句子显示一次。根据 Arduino millis()
时钟,它将是 大约 5000 毫秒, 但不完全是 。 millis()
将根据您的 crystal 的准确度与 GPS 间隔发生漂移。 GPS间隔非常准确,受限于原子钟、串口波特率、GPS设备计算时间。
这是您的草图,已修改为使用 NeoGPS:
#include <NMEAGPS.h>
/*
This program sketch obtain and print the lati,logi,speed,date and time
It requires the use of SoftwareSerial, and assumes that you have a
9600-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
#include <NeoSWSerial.h>
static const int RXPin = 4, TXPin = 3;
NeoSWSerial gpsPort(RXPin, TXPin);
static const uint32_t GPSBaud = 9600;
NMEAGPS gps;
gps_fix fix;
uint8_t fixCount = 0;
void setup()
{
Serial.begin(9600);
gpsPort.begin(GPSBaud);
Serial.println(F("GPS LOADING....."));
Serial.println(F("Obtain and print lati,logi,speed,date and time"));
Serial.println(F("Testing by : "));
Serial.println(F("Billa"));
Serial.println();
}
void loop()
{
while (gps.available( gpsPort )) {
fix = gps.read();
// Once every 5 seconds...
if (++fixCount >= 5) {
displayInfo();
fixCount = 0;
}
}
if ((gps.statistics.chars < 10) && (millis() > 5000)) {
Serial.println( F("No GPS detected: check wiring.") );
while(true);
}
}
void displayInfo()
{
Serial.print(F("Location: "));
if (fix.valid.location) {
Serial.print( fix.latitude(), 5 );
Serial.print( ',' );
Serial.print( fix.longitude(), 5 );
} else {
Serial.print(F("INVALID"));
}
Serial.print(F(" Speed: "));
if (fix.valid.speed) {
Serial.print(fix.speed_kph());
Serial.print(F(" KMPH "));
} else {
Serial.print(F("INVALID"));
}
// Shift the date/time to local time
NeoGPS::clock_t localSeconds;
NeoGPS::time_t localTime;
if (fix.valid.date && fix.valid.time) {
using namespace NeoGPS; // save a little typing below...
localSeconds = (clock_t) fix.dateTime; // convert structure to a second count
localSeconds += 5 * SECONDS_PER_HOUR + 30 * SECONDS_PER_MINUTE; // shift timezone
localTime = localSeconds; // convert back to a structure
}
Serial.print(F(" Date : "));
if (fix.valid.date) {
Serial.print(localTime.month);
Serial.print('/');
Serial.print(localTime.date);
Serial.print('/');
Serial.print(localTime.year);
} else {
Serial.print(F("INVALID"));
}
Serial.print(F(" Time : "));
if (fix.valid.time) {
Serial.print(localTime.hours);
Serial.print(':');
if (localTime.minutes < 10) Serial.print('0');
Serial.print(localTime.minutes);
Serial.print(':');
if (localTime.seconds < 10) Serial.print(F("0"));
Serial.print(localTime.seconds);
} else {
Serial.print(F("INVALID"));
}
Serial.println();
}
此草图显示每五分之一 fix
,没有使用不准确的 millis()
或令人讨厌的 delay()
。没有人有时间做那个!
并且每个修复都是从每个 1 秒间隔的 所有 个句子中累积的,无论是一个句子(RMC?),还是 8 个句子(GGA,GLL,RMC, GSV*3、GSA 和 VTG)。在 NeoGPS 中,计算修复等同于计算秒数。
注意:如果您需要超精确的 5 秒间隔,请考虑使用 PPS 引脚(如果可用)。
本地时间在此草图中计算正确,即使时区转换进入新的小时、日期、月份或年份。您的草图没有正确跨越日期边界。 5.5 小时轮班,如果我没看错的话。
我应该说 NeoGPS 比所有其他库更小、更快和更准确吗? :) 它可以从 Arduino IDE 库管理器中获得,在菜单 Sketch -> Include Library -> Manage Libraries.
下您还应该考虑使用 SoftwareSerial
以外的东西。这是非常低效的,因为它会长时间禁用中断。这可能会干扰草图的其他部分或其他库。
最好的软件串口库是AltSoftSerial。如果您可以切换到引脚 8 和 9,我强烈建议您这样做。
如果你不能切换引脚(你真的确定吗?),你应该使用我的NeoSWSerial。它适用于任何两个引脚,而且效率几乎一样。支持您使用的9600波特率
slash-dev 给我一个关于如何在 5 秒间隔内获取数据的答案 GPS.He 还提供了一些改进的方法,当我遵循时获得完美 output.It 解决了代码中的一些错误我提供了 too.Link 的答案:
结果: https://i.stack.imgur.com/pzvsu.png