Arduino не записывает полное предложение NMEA в файл SD-карты

В настоящее время я создаю небольшой GPS-модуль, который должен отслеживать мое местоположение и записывать полное предложение NMEA на SD-карту.
(Я хочу потом разобрать его на своем компьютере)
Для получения данных я использую Arduino Nano и GPS-модуль NEO-6M. р>

Что работает: получение данных NMEA из модуля, запись на SD-карту.
Вывод данных на последовательный вывод через Serial.write работает нормально.

Теперь у меня проблема: похоже, что Arduino не может достаточно быстро записывать данные на SD-карту и рассинхронизируется с модулем GPS. Иногда это приводит к таким вещам: $G3,3,09,32,20,248,*4D

У меня есть несколько идей, как это исправить:
1. Записывайте данные быстрее
2. Всегда дожидайтесь полной записи данных перед получением следующего исправления
3. писать только каждую вторую поправку GPS

Я пытался реализовать их, но каждый раз терпел неудачу (извините, я новичок в этом).

Вот мой текущий код:

#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>

SoftwareSerial GPS_Serial(4, 3); // GPS Module’s TX to D4 & RX to D3
File GPS_File;
int NBR = 1;  //file number

void setup() {
  Serial.begin(9600);
  GPS_Serial.begin(9600);
  SD.begin(5);                  //SD Pin  

  //write data to a new file
  bool rn = false;
  while (rn == false) {
    if (SD.exists(String(NBR) + ".txt")) {
      NBR = NBR + 1;
    }
    else {
      GPS_File = SD.open(String(NBR) + ".txt", FILE_WRITE);
      GPS_File.write("START\n");
      GPS_File.close();
      rn = true;
    }
  }
}

int x = 0;
int temp = 0;
char gpsData;
char buff[300];

void loop() {

  //collect data and write to buffer
  while (GPS_Serial.available() > 0) {
    gpsData = GPS_Serial.read();
    x++;
    buff[x] = gpsData;
  }

  temp = x;
  x = 1;

  GPS_File = SD.open(String(NBR) + ".txt", FILE_WRITE);

  //copy from buffer to sd
  while (x <= temp) {
    GPS_File.print(buff[x]);
    x++;
  }

  GPS_File.close();

  x = 0;
  temp = 0;
}

, 👍0

Обсуждение

Вам нужно пересмотреть свое последовательное чтение. И не закрывайте и не открывайте файл (вместо этого используйте GPS_File.flush()). https://majenko.co.uk/blog/reading-serial-arduino, @Majenko

while (GPS_Serial.available() > 0) может прерваться посередине, потому что цикл быстрее, чем скорость передачи (байта). Возможно, вы захотите дождаться символа конца строки., @the busybee

@Majenko, реализующий File.flush(), немного доказал это и позволил получить полные наборы, когда у GPS нет сигнала. К сожалению, когда GPS получает сигнал, объем данных значительно увеличивается, и он больше не может поддерживать связь, что приводит к рассинхронизации., @DerEntinator

@Majenko, к сожалению, внедрив строку чтения по вашей ссылке, не улучшил ее и привел к большему количеству рассинхронизаций., @DerEntinator


1 ответ


Лучший ответ:

0

Попробовав разные подходы, я решил упростить его до самого базового уровня.
Без какого-либо причудливого кодирования или буферов я теперь просто записываю данные прямо на SD-карту и сбрасываю каждые 15 секунд, что рискует потерять до 15 секунд данных, т.е. 15 GPS-фиксов (1 в секунду) при резке. выключено питание.

Еще один случай потенциальной потери данных может наблюдаться, когда программа сбрасывает накопленные данные на SD. Однако это происходит не каждый раз.

Чтобы преобразовать предложения NMEA в пригодные для использования данные, я использую GPSBabel. Он автоматически игнорирует ломаные линии. После преобразования в .gpx я просматриваю его с помощью Google Планета Земля.

Это "законченный" код:

#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>

SoftwareSerial GPS_Serial(4, 3);  // TX модуля GPS на D4 & RX к D3
File GPS_File;
int NBR = 1;                      //номер дела

unsigned long TimerA;             //сохранить таймер
bool sw = false;                  // сохранить переключатель таймера

void setup() {
  Serial.begin(9600);
  GPS_Serial.begin(9600);
  SD.begin(5);                    //SD-пин

  //записываем данные в новый файл
  bool rn = false;
  while (rn == false) {
    if (SD.exists(String(NBR) + ".txt")) {
      NBR = NBR + 1;
    }
    else {
      GPS_File = SD.open(String(NBR) + ".txt", FILE_WRITE);
      GPS_File.write("START\n");
      rn = true;
    }
  }
}

void loop() {
  while (GPS_Serial.available() > 0) {
    GPS_File.write(GPS_Serial.read());
  }

  // устанавливаем таймер
  if ( sw == false) {
    TimerA = millis();
    sw = true;
  }

  //сохраняем каждые 15 секунд
  if (millis() - TimerA >= 15000UL) {
    GPS_File.flush();
    sw = false;
  }
}
,