2

我想同时使用 GPS 模块和指南针传感器并用 SD 卡记录信息。我完成了硬件部分,但我的代码不能正常工作。我可以在 SD 卡上记录 GPS 数据,但我无法使用 Compass 的航向数据以这种格式记录 GPS 数据 => 日期时间+经度+纬度+速度+航向..

我认为出于某种原因,循环正在中断,它在第一次运行后停止,但我不知道为什么。

#include <SoftwareSerial.h>
#include <TinyGPS.h>
#include <SD.h>
#include <Wire.h>
#include <HMC5883L.h>

HMC5883L compass;

TinyGPS gps;
static char dtostrfbuffer[20];
int CS = 10;
int LED = 13;
int SD_LED = A0;
int GPS_LED = A1;
int Blink_LED = 6;
SoftwareSerial mySerial(2 , 3); // RX, TX


String SD_date_time = "";
String SD_lat = "";
String SD_lon = "";
String SD_spd = "";
String SD_heading = "";
String dataString ="";

static void gpsdump(TinyGPS &gps);
static bool feedgps();


void setup()
{
  pinMode(CS, OUTPUT);  //Chip Select Pin for the SD Card
  pinMode(LED, OUTPUT);  //LED Indicator

  //Serial interfaces
  Serial.begin(9600);
  mySerial.begin(9600);
   Wire.begin();

  //Connect to the SD Card
  if(!SD.begin(CS))
  {
    Serial.println("card failure");
    return;
  }


 compass = HMC5883L(); //new instance of HMC5883L library
 setupHMC5883L(); //setup the HMC5883L

}


void loop()
{
  bool newdata = false;
  unsigned long start = millis();

  // Every 5 second we print an update
  while (millis() - start < 5000)
  {
    if (feedgps())
      newdata = true;
  }
  gpsdump(gps);
  int intHead = ReadCompass();
  SD_heading = String(intHead); 
  dataString = SD_date_time + "," + SD_lat + "," + SD_lon + "," + SD_spd + "," + SD_heading;

  //Open the Data CSV File
  File dataFile = SD.open("LOG.csv", FILE_WRITE);
  if (dataFile)
  {
    dataFile.println(dataString);
    Serial.print("SD card writing:");
    Serial.println(dataString);
    dataFile.close();
    digitalWrite(SD_LED, HIGH);      //if sd works led is on

  }
  else
  {
    Serial.println("\ncouldn't open LOG file!");
  }
}


int ReadCompass() 
{
  int intHead;
  // Retrive the raw values from the compass (not scaled).
  MagnetometerRaw raw = compass.ReadRawAxis();
  // Retrived the scaled values from the compass (scaled to the configured scale).
  MagnetometerScaled scaled = compass.ReadScaledAxis();

  // Values are accessed like so:
  int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)

  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(scaled.YAxis, scaled.XAxis);
  // Correct for when signs are reversed.
  if(heading < 0)
    heading += 2*PI;

  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading -= 2*PI;

  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI; 

  intHead= int (headingDegrees);
  return intHead;
  delay (200);
}

//GPS Reading Function  
static void gpsdump(TinyGPS &gps)
{
  float flat, flon;
  unsigned long age, date, time, chars = 0;
  unsigned short sentences = 0, failed = 0;

  int year;
  byte month, day, hour, minute, second, hundredths;


  gps.f_get_position(&flat, &flon, &age); 
  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
  gps.stats(&chars, &sentences, &failed);
  float fmps = gps.f_speed_mps(); // speed in m/sec

  if (age == TinyGPS::GPS_INVALID_AGE)
  {
    Serial.println("no GPS connection");

    SD_lat = "invalid";
    SD_lon = "invalid";
    SD_date_time = "invalid";

    Serial.print("Age:"); 
    Serial.println(age);
    Serial.print("char count:"); 
    Serial.println(chars);
    Serial.print("valid NMEA sentences"); 
    Serial.println(sentences);
    Serial.print("invalid NMEA sentences"); 
    Serial.println(failed);
    digitalWrite(GPS_LED, HIGH);                //if GPS doesn't get fix led is on
  }
  else
  {

    Serial.println("GPS connection is available ");

    digitalWrite(LED, HIGH);          //GPS fix exists

    SD_lat = dtostrf(flat,9,5,dtostrfbuffer);
    SD_lon = dtostrf(flon,10,5,dtostrfbuffer);
    SD_spd = dtostrf(fmps,5,2,dtostrfbuffer);

    char sz[32];
    sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d   ",
    day, month, year, hour+2, minute, second);
    Serial.print(sz);
    Serial.println(SD_lat);
    Serial.println(SD_lon);
    Serial.print("Hiz:"); 
    Serial.println(SD_spd);
    Serial.print("Age:"); 
    Serial.println(age);
    Serial.print("char count:"); 
    Serial.println(chars);
    Serial.print("valid NMEA sentences"); 
    Serial.println(sentences);
    Serial.print("invalid NMEA sentences:"); 
    Serial.println(failed);
    SD_date_time = sz;
  }
  Serial.println();
}

static bool feedgps()
{
  while (mySerial.available())
  {
    if (gps.encode(mySerial.read()))
      return true;
  }
  return false;
}


void setupHMC5883L(){
 //Setup the HMC5883L, and check for errors
 int error; 
 error = compass.SetScale(1.3); //Set the scale of the compass.
 if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so

 error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
 if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so
}
4

2 回答 2

0

我解决了这个问题。Arduino UNO (ATmega328) 的 RAM 对于上面的代码是不够的。我关闭了有关串行监视器的所有内容,所以我无法观察记录的数据,但 SD、指南针和 GPS 现在工作正常。谢谢。

于 2014-01-06T21:09:11.053 回答
0

有些事情要问..您是否继续打印调试消息?

当您说您可以记录 GPS 数据时,也许您的意思是当您添加代码以读取指南针时,事情就会停止工作,因为您没有记录任何可用的数据。真的吗?

我在尝试同时使用软件串行和普通串行端口的项目中遇到了麻烦。如果两个串口同时有流量,软件端口时序可能会受到干扰。也许这也让你着迷。

浮点精度对于纬度/经度值并不是很好,对您来说可能不是问题,但精度步长可能是 2 或 3 英尺。我会考虑将 Lat/Lon 的 NMEA 数据记录为未修改的字符串。让读取日志文件的应用程序解析可能要存储双精度的字符串。

请注意,在 arduino 上使用 double 与 float 相同,在那里使用 double 类型不会获得更高的精度,它实际上只是一个 4 字节的浮点数。

于 2014-01-06T02:37:27.127 回答