使用带有 Arduino uno 的 SIM900a 使用 GPRS 将 GPS 位置发送到服务器
Using a SIM900a with Arduino uno to send GPS location to a server using GPRS
我已经尝试这样做 2 天了。我可以将 GPS lat、lang 作为短信发送到接收号码。但是我现在想要的是使用 GPRS 发送它。我正在使用 SIM900A GSM/GPRS 模块。我是一名软件工程专业的学生,我对 Arduino 还很陌生。这是我使用 GSM 的代码。
#include <SoftwareSerial.h>
#include <TinyGPS.h>
TinyGPS gps;
SoftwareSerial ss(5, 6);
static void smartdelay(unsigned long ms);
void setup()
{
Serial.begin(115200);
ss.begin(9600);
}
void loop()
{
float flat, flon;
unsigned long age, date, time, chars = 0;
unsigned short sentences = 0, failed = 0;
gps.f_get_position(&flat, &flon, &age);
sendLatLang(flat, flon);
gps.stats(&chars, &sentences, &failed);
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 sendLatLang(float lat, float lang)
{
if (lat == TinyGPS::GPS_INVALID_F_ANGLE || lang == TinyGPS::GPS_INVALID_F_ANGLE) {
Serial.println("Searching for GPS fix...");
} else {
Serial.println("AT+CMGF=1");
delay(1000);
Serial.println("AT+CMGS=\"+94123445678\"");
delay(1000);
Serial.print("Latittude : ");
Serial.println(lat);
Serial.print("Longitude : ");
Serial.println(lang);
Serial.write(26);
delay(1000);
}
}
首先,SoftwareSerial 非常非常低效。它会长时间禁用中断,这会干扰草图的其他部分。
总结this answer:
- AltSoftSerial 是最好的,但它只适用于引脚 8 和 9(在 UNO 上)。
- NeoSWSerial 次之。它适用于任意两个引脚,但它只支持波特率 9600、19200 和 38400
其次,因为您的程序与两个设备通信,所以在程序的任何部分使用 delay
或 "blocking" 时必须小心。当程序 "stuck" 处于 delay
时,没有其他任何东西正在处理。 GPS 字符不断进入,它们最终会溢出输入缓冲区(64 个字符限制)。 smartDelay
函数试图解决这个问题。
您应该使用 Finite-state Machine 来处理发送,而不是调用 delay
。每次通过 loop
,FSM 都会检查是否到了执行下一步的时间。这很容易用一个 switch
语句和一个 case
为每个 "step" 的发送过程(即当前的 "state")实现。
这允许循环不断处理所有 GPS 字符,即使 FSM "waiting" 已经过去了一段时间。 FSM 未使用 delay
,它会不断检查 millis()
以查看时间是否已过。它每 loop
.
检查一次
我还建议使用我的 NeoGPS 库。它比所有其他库更小、更快、更准确,并且可以配置为仅解析您真正使用的字段和 NMEA 消息。如果您想尝试一下,可以从 Arduino IDE 菜单 Sketch -> Include Library -> Manage Libraries.
获得
这是草图的 NeoGPS 版本:
#include <NeoSWSerial.h>
#include <NMEAGPS.h>
NMEAGPS gps;
NeoSWSerial gps_port(5, 6);
enum state_t { WAITING_TO_SEND, SENDING_CMD1, SENDING_CMD2 }; // valid FSM states
state_t state; // current FSM state
uint32_t stateTime; // FSM timer for delays between states
bool newData = false; // true when a fix with a location is ready
gps_fix fixToSend;
const uint32_t SEND_INTERVAL = 60 * 1000UL; // once a minute
void setup()
{
Serial.begin(115200);
gps_port.begin(9600);
}
void loop()
{
// Always process GPS characters so the latest fix is ready to go
while (gps.available( gps_port )) {
gps_fix newFix = gps.read();
if (newFix.valid.location) {
newData = true;
fixToSend = newFix;
}
}
// FSM for sending fixes
switch (state) {
case WAITING_TO_SEND:
// Don't send new data too often.
if (newData && (millis() - stateTime >= SEND_INTERVAL)) {
Serial.println( F("AT+CMGF=1") );
stateTime = millis();
state = SENDING_CMD1;
}
break;
case SENDING_CMD1:
// Delay 1 second after the CMGF command
if (millis() - stateTime >= 1000) {
Serial.println( F("AT+CMGS=\"+94123445678\"") );
stateTime = millis();
state = SENDING_CMD2;
}
break;
case SENDING_CMD2:
// Delay 1 second after the CMGS command...
if (millis() - stateTime >= 1000) {
// ... then send the message
sendFix( fixToSend );
Serial.write(26); // no more data to send
newData = false;
stateTime = millis();
state = WAITING_TO_SEND;
}
break;
}
}
static void sendFix( const gps_fix &fix )
{
// Send only the fix pieces of interest
// (other pieces described on Data Model page)
Serial.print( F("Latitude : ") );
Serial.println( fix.latitude(), 6 );
Serial.print( F("Longitude : ") );
Serial.println( fix.longitude(), 6 );
}
您的原始程序使用了 8896 字节的程序 space 和 564 字节的 RAM。
NeoGPS 版本使用 8562 字节的程序 space 和 364 字节的 RAM。
即使您不使用 NeoGPS,也请务必阅读疑难解答页面。它描述了许多常见问题,这些问题通常与程序结构和时序有关。
P.S。请注意 F 宏用于 "double-quoted" 字符串常量...这通过强制从闪存中使用它们来节省 RAM。该草图还有一个 SENDING_INTERVAL 以避免每秒发送 lat/long 消息。 :P
我已经尝试这样做 2 天了。我可以将 GPS lat、lang 作为短信发送到接收号码。但是我现在想要的是使用 GPRS 发送它。我正在使用 SIM900A GSM/GPRS 模块。我是一名软件工程专业的学生,我对 Arduino 还很陌生。这是我使用 GSM 的代码。
#include <SoftwareSerial.h>
#include <TinyGPS.h>
TinyGPS gps;
SoftwareSerial ss(5, 6);
static void smartdelay(unsigned long ms);
void setup()
{
Serial.begin(115200);
ss.begin(9600);
}
void loop()
{
float flat, flon;
unsigned long age, date, time, chars = 0;
unsigned short sentences = 0, failed = 0;
gps.f_get_position(&flat, &flon, &age);
sendLatLang(flat, flon);
gps.stats(&chars, &sentences, &failed);
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 sendLatLang(float lat, float lang)
{
if (lat == TinyGPS::GPS_INVALID_F_ANGLE || lang == TinyGPS::GPS_INVALID_F_ANGLE) {
Serial.println("Searching for GPS fix...");
} else {
Serial.println("AT+CMGF=1");
delay(1000);
Serial.println("AT+CMGS=\"+94123445678\"");
delay(1000);
Serial.print("Latittude : ");
Serial.println(lat);
Serial.print("Longitude : ");
Serial.println(lang);
Serial.write(26);
delay(1000);
}
}
首先,SoftwareSerial 非常非常低效。它会长时间禁用中断,这会干扰草图的其他部分。
总结this answer:
- AltSoftSerial 是最好的,但它只适用于引脚 8 和 9(在 UNO 上)。
- NeoSWSerial 次之。它适用于任意两个引脚,但它只支持波特率 9600、19200 和 38400
其次,因为您的程序与两个设备通信,所以在程序的任何部分使用 delay
或 "blocking" 时必须小心。当程序 "stuck" 处于 delay
时,没有其他任何东西正在处理。 GPS 字符不断进入,它们最终会溢出输入缓冲区(64 个字符限制)。 smartDelay
函数试图解决这个问题。
您应该使用 Finite-state Machine 来处理发送,而不是调用 delay
。每次通过 loop
,FSM 都会检查是否到了执行下一步的时间。这很容易用一个 switch
语句和一个 case
为每个 "step" 的发送过程(即当前的 "state")实现。
这允许循环不断处理所有 GPS 字符,即使 FSM "waiting" 已经过去了一段时间。 FSM 未使用 delay
,它会不断检查 millis()
以查看时间是否已过。它每 loop
.
我还建议使用我的 NeoGPS 库。它比所有其他库更小、更快、更准确,并且可以配置为仅解析您真正使用的字段和 NMEA 消息。如果您想尝试一下,可以从 Arduino IDE 菜单 Sketch -> Include Library -> Manage Libraries.
获得这是草图的 NeoGPS 版本:
#include <NeoSWSerial.h>
#include <NMEAGPS.h>
NMEAGPS gps;
NeoSWSerial gps_port(5, 6);
enum state_t { WAITING_TO_SEND, SENDING_CMD1, SENDING_CMD2 }; // valid FSM states
state_t state; // current FSM state
uint32_t stateTime; // FSM timer for delays between states
bool newData = false; // true when a fix with a location is ready
gps_fix fixToSend;
const uint32_t SEND_INTERVAL = 60 * 1000UL; // once a minute
void setup()
{
Serial.begin(115200);
gps_port.begin(9600);
}
void loop()
{
// Always process GPS characters so the latest fix is ready to go
while (gps.available( gps_port )) {
gps_fix newFix = gps.read();
if (newFix.valid.location) {
newData = true;
fixToSend = newFix;
}
}
// FSM for sending fixes
switch (state) {
case WAITING_TO_SEND:
// Don't send new data too often.
if (newData && (millis() - stateTime >= SEND_INTERVAL)) {
Serial.println( F("AT+CMGF=1") );
stateTime = millis();
state = SENDING_CMD1;
}
break;
case SENDING_CMD1:
// Delay 1 second after the CMGF command
if (millis() - stateTime >= 1000) {
Serial.println( F("AT+CMGS=\"+94123445678\"") );
stateTime = millis();
state = SENDING_CMD2;
}
break;
case SENDING_CMD2:
// Delay 1 second after the CMGS command...
if (millis() - stateTime >= 1000) {
// ... then send the message
sendFix( fixToSend );
Serial.write(26); // no more data to send
newData = false;
stateTime = millis();
state = WAITING_TO_SEND;
}
break;
}
}
static void sendFix( const gps_fix &fix )
{
// Send only the fix pieces of interest
// (other pieces described on Data Model page)
Serial.print( F("Latitude : ") );
Serial.println( fix.latitude(), 6 );
Serial.print( F("Longitude : ") );
Serial.println( fix.longitude(), 6 );
}
您的原始程序使用了 8896 字节的程序 space 和 564 字节的 RAM。 NeoGPS 版本使用 8562 字节的程序 space 和 364 字节的 RAM。
即使您不使用 NeoGPS,也请务必阅读疑难解答页面。它描述了许多常见问题,这些问题通常与程序结构和时序有关。
P.S。请注意 F 宏用于 "double-quoted" 字符串常量...这通过强制从闪存中使用它们来节省 RAM。该草图还有一个 SENDING_INTERVAL 以避免每秒发送 lat/long 消息。 :P