使用带有 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