Проблема с разделением строк
Я получаю несколько сообщений от устройства GPS на разных частотах. После получения строк я должен сохранить эти данные на SD-карте. Это хорошо работает, когда у нас есть сообщения с одинаковыми частотами, но если частоты не совпадают, в сохраненных данных появляются пробелы. Я использую метод разделения строк.
CR1A = String1.indexOf(13); // находит местоположение первого
String1A = String1.substring(0, CR1A + 2 ); // захватывает первую строку данных
CR1B = String1.indexOf(13, CR1A + 2 ); // находит местоположение секунды,
String1B = String1.substring(CR1A , CR1B + 2 ); // захватывает вторую строку данных
CR1C = String1.indexOf(13, CR1B + 2 );
String1C = String1.substring(CR1B , CR1C + 2 );
CR1D = String1.indexOf(13, CR1C + 2 );
String1D = String1.substring(CR1C , CR1D + 2 );
CR1E = String1.indexOf(13, CR1D + 2 );
String1E = String1.substring(CR1D , CR1E + 2 );
CR1F = String1.indexOf(13, CR1E + 2 );
String1F = String1.substring(CR1E , CR1F + 2 );
strID = (String1A.substring(0, 2));
if (strID == "$G") {
File dataFile = SD.open("GPS1.txt", FILE_WRITE);
// если файл доступен, пишем в него:
strID = (String1A.substring(0, 5));
if (strID == "$GPGG") {
dataFile.print(dt);
dataFile.print(" ");
dataFile.print(tm);
dataFile.print(msec);
dataFile.print(",");
dataFile.print(String1A);
String1A = "";
}
strID = (String1D.substring(4, 6));
if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
dataFile.print(String1B);
String1B = "";
}
strID = (String1C.substring(4, 6));
if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
dataFile.print(String1C);
String1C = "";
}
strID = (String1D.substring(4, 6));
if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
dataFile.print(String1D);
String1D = "";
}
strID = (String1E.substring(4, 6));
if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
dataFile.print(String1E);
String1E = "";
}
strID = (String1F.substring(4, 6));
if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
dataFile.print(String1F);
String1F = "";
}
dataFile.close();
}
ИЗМЕНИТЬ:
Это код, который я сейчас использую. Я отключил все команды, которые извлекают строки из моих доступных данных, полученных через последовательный порт. Я просто использую для этого таймер прерывания... и он работает отлично. Но мне не понравился этот простой метод, и я не знаю, хороший это способ получить такие строки или нет, потому что я не очень хороший программист.
#include <TimerOne.h>
#define RxTimeOut 5
/*
** MEGA MINI **
** MOSI - pin 51
** MISO - pin 50
** CLK - pin 52
** CS - pin 53 (for MKRZero SD: SDCARD_SS_PIN)
** SDA - pin 20
** SCL - pin 21
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include "math.h"
#include <SPI.h>
#include <SD.h>
#include "RTClib.h"
#define DS1307_CTRL_ID 0x68
unsigned long int ticks = 0;
RTC_DS1307 rtc;
bool flag = false;
String GPSmessage = "";
const int chipSelect = 53;
String dataString = "";
//Строка dataString1 = "";
//Строка dataString2 = "";
//Строка dataString3 = "";
bool stringComplete = false;
bool string1Complete = false;
bool string2Complete = false;
bool string3Complete = false;
String strID = "";
unsigned long msec;
const long interval = 500;
#define SCREEN_WIDTH 128 // Ширина OLED-дисплея в пикселях
#define SCREEN_HEIGHT 64 // Высота OLED-дисплея в пикселях
#define OLED_RESET 4 // Номер вывода сброса (или -1, если используется общий вывод сброса Arduino)
#define SCREEN_ADDRESS 0x3C ///< См. спецификацию для адреса; 0x3D для 128x64, 0x3C для 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
unsigned long CurrentBaudRate = 9600;
unsigned long x = 0;
int Up = 3;
int Dn = 4;
int Mnu = 5;
String String1;
String inputString1 = ""; // строка для хранения входящих данных
boolean NewDataFlag1 = 0;
unsigned int Serial1TimeOut = 0;
String String2;
String inputString2 = ""; // строка для хранения входящих данных
boolean NewDataFlag2 = 0;
unsigned int Serial2TimeOut = 0;
String String3;
String inputString3 = ""; // строка для хранения входящих данных
boolean NewDataFlag3 = 0;
unsigned int Serial3TimeOut = 0;
void timerIsr()
{
serial1Event();
serial2Event();
serial3Event();
if (Serial1TimeOut > 0)Serial1TimeOut--;
if (Serial1TimeOut == 0 && NewDataFlag1 == 1)
{
String1 = inputString1;
inputString1 = "";
NewDataFlag1 = 0;
}
if (Serial2TimeOut > 0)Serial2TimeOut--;
if (Serial2TimeOut == 0 && NewDataFlag2 == 1)
{
String2 = inputString2;
inputString2 = "";
NewDataFlag2 = 0;
}
if (Serial3TimeOut > 0)Serial3TimeOut--;
if (Serial3TimeOut == 0 && NewDataFlag3 == 1)
{
String3 = inputString3;
inputString3 = "";
NewDataFlag3 = 0;
}
}
void setup() {
Timer1.initialize(5000); // Время события таймера
Timer1.attachInterrupt( timerIsr );
Serial.println("Sonay di nathli");
//======================================== SD-карта ===== ================================================== //
// Serial.println("Инициализация SD-карты...");
// смотрим, нет ли карты:
if (!SD.begin(chipSelect)) {
// Serial.println("Сбой карты или ее отсутствие");
// больше ничего не делаем:
return;
}
// Serial.println("SD-карта готова");
//=============================================== ====== RTC ========================================== ==//
if (!rtc.begin())
{
// Serial.println("Не удалось найти RTC");
Serial.flush();
abort();
}
if (!rtc.isrunning()) {
// Serial.println("RTC НЕ запущен, установим время!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
//=============================================== Выбор скорости OLED ============================================== =====//
pinMode(Up, INPUT_PULLUP);
pinMode(Dn, INPUT_PULLUP);
pinMode(Mnu, INPUT_PULLUP);
unsigned char bdindx = EEPROM.read(0);
if (bdindx > 3) bdindx = 0;
if (bdindx == 0) CurrentBaudRate = 4800;
if (bdindx == 1) CurrentBaudRate = 9600;
if (bdindx == 2) CurrentBaudRate = 19200;
if (bdindx == 3) CurrentBaudRate = 115200;
delay (500);
while (!Serial) { }// ждем подключения последовательного порта
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(CurrentBaudRate);
Serial1.begin(CurrentBaudRate);
Serial2.begin(CurrentBaudRate);
Serial3.begin(CurrentBaudRate);
Serial.println(CurrentBaudRate);
delay (1000);
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
display.clearDisplay();
display.setTextSize(1); // Обычный масштаб пикселя 1:1
display.setTextColor(SSD1306_WHITE); // Рисуем белый текст
display.display();
}
String String1A, String1B, String1C, String1D, String1E, String1F;
String String2A, String2B, String2C, String2D, String2E, String2F;
String String3A, String3B, String3C, String3D, String3E, String3F;
int CR1A, CR1B, CR1C, CR1D, CR1E, CR1F;
int CR2A, CR2B, CR2C, CR2D, CR2E, CR2F;
int CR3A, CR3B, CR3C, CR3D, CR3E, CR3F;
// =========================================== Отображение скорости передачи данных экран (позиция) ===========================================//
void DrawBaudRate(unsigned long BdRt)
{
unsigned char Xoffset = 0;
if (BdRt >= 0 && BdRt < 10000) Xoffset = 37;
if (BdRt >= 10000 && BdRt < 100000) Xoffset = 30;
if (BdRt >= 100000 ) Xoffset = 25;
// display.drawRect(0,0,128,64,SSD1306_WHITE);
// display.setTextSize(2);
// display.setCursor(15,10);
// display.println("Скорость передачи");
// display.setTextSize(2);
// display.setCursor(15,10);
// display.println(tm);
// display.setCursor(Xoffset,37);// 6 цифр
// display.println(BdRt);
// дисплей.дисплей();
// delay(10);
}
// =============================================== == Выбор скорости передачи данных ========================================== =============//
unsigned long SelectBaudRate(unsigned long BdRt)
{
unsigned char BdRtIndx = 0;
unsigned int FlashCnt = 0;
if (BdRt == 4800) BdRtIndx = 0;
if (BdRt == 9600) BdRtIndx = 1;
if (BdRt == 19200) BdRtIndx = 2;
if (BdRt == 115200) BdRtIndx = 3;
unsigned char Xoffset = 0;
if (BdRt >= 0 && BdRt < 10000) Xoffset = 37;
if (BdRt >= 10000 && BdRt < 100000) Xoffset = 30;
if (BdRt >= 100000 ) Xoffset = 25;
display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(15, 10); display.println("Select Baudrate");
display.setCursor(15, 20); display.println("by Up/Dn Buttons");
display.setTextSize(2);
display.setCursor(Xoffset, 37); // 6 цифр
display.println(BdRt);
display.display();
delay(10);
while (digitalRead(Mnu) == 0) delay(10);
delay(100);
while (digitalRead(Mnu) == 1)
{
delay(10);
FlashCnt++;
if (digitalRead(Up) == 0)
{
if (BdRtIndx < 3) BdRtIndx++;
}
if (digitalRead(Dn) == 0)
{
if (BdRtIndx > 0) BdRtIndx--;
}
if (BdRtIndx == 0) BdRt = 4800;
if (BdRtIndx == 1) BdRt = 9600;
if (BdRtIndx == 2) BdRt = 19200;
if (BdRtIndx == 3) BdRt = 115200;
if (BdRt >= 0 && BdRt < 10000) Xoffset = 37;
if (BdRt >= 10000 && BdRt < 100000) Xoffset = 30;
if (BdRt >= 100000 ) Xoffset = 25;
display.clearDisplay();
display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(15, 10); display.println("Select Baudrate");
display.setCursor(15, 20); display.println("by Up/Dn Buttons");
display.setTextSize(2);
display.setCursor(Xoffset, 37); // 6 цифр
if (FlashCnt > 1) display.println(BdRt);
if (FlashCnt > 2) FlashCnt = 0;
display.display();
delay(250);
//пока(digitalRead(Up)==0 || digitalRead(Dn)==0) delay(10);
}
while (digitalRead(Mnu) == 0) delay(10);
display.clearDisplay();
display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(20, 10); display.println("Saving");
display.setCursor(20, 35); display.println("Changes");
display.display();
delay(2000);
EEPROM.write(0, BdRtIndx);
return (BdRt);
}
//=============================================== === OLED, показывающий время =========================================== ===//
char Time[] = " : : ";
byte i, second, minute, hour;
void DS3231_display() {
// Преобразование BCD в десятичное число
second = (second >> 4) * 10 + (second & 0x0F);
minute = (minute >> 4) * 10 + (minute & 0x0F);
hour = (hour >> 4) * 10 + (hour & 0x0F);
// Конец преобразования
Time[7] = second % 10 + 48;
Time[6] = second / 10 + 48;
Time[4] = minute % 10 + 48;
Time[3] = minute / 10 + 48;
Time[1] = hour % 10 + 48;
Time[0] = hour / 10 + 48;
display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
draw_text(16, 25, Time, 2); // Отображение времени
}
void blink_parameter() {
byte j = 1;
while (j < 10 && digitalRead(Up) && digitalRead(Dn)) {
j++;
delay(25);
}
}
byte edit(byte x_pos, byte y_pos, byte parameter) {
char text[3];
sprintf(text, "%02u", parameter);
while (!digitalRead(Up)); // Ждем, пока кнопка B1 не будет отпущена
while (true) {
while (!digitalRead(Dn)) { // Если нажата кнопка B2
display.clearDisplay();
parameter++;
if (i == 0 && parameter > 23) // Если часы > 23 ==> часы = 0
parameter = 0;
if (i == 1 && parameter > 59) // Если минуты > 59 ==> минуты = 0
parameter = 0;
sprintf(text, "%02u", parameter);
draw_text(x_pos, y_pos, text, 2);
delay(200); // Подождать 200 мс
}
display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
draw_text(x_pos, y_pos, " ", 2);
blink_parameter();
draw_text(x_pos, y_pos, text, 2);
blink_parameter();
if (!digitalRead(Up)) { // Если нажата кнопка B1
i++; // Увеличение 'i' для следующего параметра
// display.clearDisplay();
return parameter; // Возвращаем значение параметра и выходим
}
}
}
void draw_text(byte x_pos, byte y_pos, char *text, byte text_size) {
display.setCursor(x_pos, y_pos);
display.setTextSize(text_size);
display.print(text);
display.display();
}
//---------------------------------------------
void loop() {
// ======================================== Время редактирования и отображение на OLED = ==========================================//
if (!digitalRead(Up)) { // Если нажата кнопка B1
i = 0;
while (!digitalRead(Up)); // Дождаться отпускания кнопки B1
hour = edit(16, 25, hour); // Редактировать часы
minute = edit(52, 25, minute); // Редактировать минуты
// Преобразование десятичного числа в двоично-десятичное
minute = ((minute / 10) << 4) + (minute % 10);
hour = ((hour / 10) << 4) + (hour % 10);
// Конец преобразования
// Запись данных в DS3231 RTC
Wire.beginTransmission(0x68); // Запустить протокол I2C с адресом DS3231
Wire.write(0); // Отправляем регистрационный адрес
Wire.write(0); // Сбросить секунды и запустить осциллятор
Wire.write(minute); // Запись минуты
Wire.write(hour); // Запись часа
Wire.endTransmission(); // Остановить передачу и освободить шину I2C
delay(200); // Подождать 200 мс
}
Wire.beginTransmission(0x68); // Запустить протокол I2C с адресом DS3231
Wire.write(0); // Отправляем регистрационный адрес
Wire.endTransmission(false); // перезапуск I2C
Wire.requestFrom(0x68, 7); // Запрос 7 байт от DS3231 и освобождение шины I2C в конце чтения
second = Wire.read(); // Чтение секунд из регистра 0
minute = Wire.read(); // Чтение минут из регистра 1
hour = Wire.read(); // Чтение часа из регистра 2
Wire.beginTransmission(0x68); // Запустить протокол I2C с адресом DS3231
Wire.write(0x11); // Отправляем регистрационный адрес
Wire.endTransmission(false); // перезапуск I2C
Wire.requestFrom(0x68, 2); // Запросить 2 байта у DS3231 и освободить шину I2C в конце чтения
DS3231_display(); // Время показа & календарь
delay(50); // Подождем 50 мс
{ display.clearDisplay();
if (digitalRead(Mnu) == 0) CurrentBaudRate = SelectBaudRate(CurrentBaudRate);
// DrawBaudRate(CurrentBaudRate);
delay(10);
x++;
if (x > 123456) x = 0;
}
// ======================================= Чтение даты и времени из RTC === =========================================//
DateTime now = rtc.now();
char dt[16];
char tm[16];
char buffer [16];
uint8_t thisSec, thisMin, thisHour;
thisSec = now.second();
thisMin = now.minute();
thisHour = now.hour();
sprintf(dt, "%02d-%02d-%02d", now.year(), now.month(), now.day());
sprintf(tm, "%02d%02d%02d", now.hour(), now.minute(), now.second());
sprintf (buffer, "%02d:%02d:%02d", thisHour, thisMin, thisSec);
msec = millis() % 1000; // ИСПОЛЬЗОВАТЬ ПОСЛЕДНИЕ 3 ЦИФРЫ МИЛЛИСА ARDUINO
//SERIAL_PORT_1
// если (string1Complete)
{ Serial.print (String1);
// CR1A = String1.indexOf(13); // находит местоположение первого
// String1A = String1.substring(0, CR1A + 2); // захватывает первую строку данных
// CR1B = String1.indexOf(13, CR1A + 2); // находит местоположение секунды,
// String1B = String1.substring(CR1A, CR1B + 2); // захватывает вторую строку данных
// CR1C = String1.indexOf(13, CR1B + 2);
// String1C = String1.substring(CR1B, CR1C + 2);
// CR1D = String1.indexOf(13, CR1C + 2);
// String1D = String1.substring(CR1C, CR1D + 2);
// CR1E = String1.indexOf(13, CR1D + 2);
// String1E = String1.substring(CR1D, CR1E + 2);
// CR1F = String1.indexOf(13, CR1E + 2);
// String1F = String1.substring(CR1E, CR1F + 2);
//
// strID = (String1A.substring(0, 5));
// если (strID == "$GPGG") {
// Serial.println(String1);
// }
// strID = (String1B.substring(0, 5));
// если (strID == "$GPVT") {
// Serial.println(String1B);
// }
// strID = (String1C.substring(0, 5));
// если (strID == "$GPZD") {
// Serial.println(String1C);
// }
// strID = (String1D.substring(0, 5));
// если (strID == "$GPGL") {
// Serial.println(String1D);
// }
// strID = (String1E.substring(0, 5));
// если (strID == "$GPGN") {
// Serial.println(String1E);
// }
// strID = (String1F.substring(0, 5));
// если (strID == "$GPGR") {
// Serial.println(String1F);
// }
// strID = (String1.substring(0, 2));
// если (strID == "$") {
File dataFile = SD.open("GPS1.txt", FILE_WRITE);
// если файл доступен, пишем в него:
strID = (String1A.substring(0, 5));
if (strID == "$GPGG") {
dataFile.print(dt);
dataFile.print(" ");
dataFile.print(tm);
dataFile.print(msec);
dataFile.print(",");
dataFile.print(String1);
Serial.print (String1);
String1 = "";
Serial.print (String1);
dataFile.close();
}
// }
// strID = (String1D.substring(4, 6));
// if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
// dataFile.print(String1B);
// String1B = "";
// }
// strID = (String1C.substring(4, 6));
// if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
// dataFile.print(String1C);
// String1C = "";
// }
// strID = (String1D.substring(4, 6));
// if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
// dataFile.print(String1D);
// String1D = "";
// }
// strID = (String1E.substring(4, 6));
// if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
// файл данных.print(String1E);
// String1E = "";
// }
// strID = (String1F.substring(4, 6));
// if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
// dataFile.print(String1F);
// String1F = "";
// }
// }
else {
File dataFile = SD.open("ES2.txt", FILE_WRITE);
if (dataFile) {
dataFile.print(dt);
dataFile.print(" ");
dataFile.print(tm);
dataFile.print(msec);
dataFile.print(",");
dataFile.println(String1);
Serial.print (String1);
// dataFile.println(String1B);
String1A = "";
String1B = "";
dataFile.close();
}
}
// }
string1Complete = false;
}
}
//------------------------------------------------ -------------------------------------------------- ---------------
void serial1Event() {
while (Serial1.available()) {
char inChar1 = (char)Serial1.read();
inputString1 += inChar1;
Serial1TimeOut = RxTimeOut;
NewDataFlag1 = 1;
if (NewDataFlag1 == 1) {
string1Complete = true;
}
}
}
@Omar Rai, 👍0
Обсуждение1 ответ
Я не знаю, какое отношение “частоты” имеют к вашей проблеме, но я бы поспорил, что вы получите более надежные результаты, если справитесь с одной из них NMEA предложение за раз, вместо того, чтобы пытаться справиться с шестью из них сразу и надеяться получить правильные.
Ниже приведена функция, которая обрабатывает по одному полному предложению за раз. Он записывает предложение в SD-файл, если его тип относится к списку “интересных” типов, которые вы хотите отслеживать:
// Типы предложений, которые должны быть записаны.
const char monitoredTypes[6][4] = {
"GGA", "VTG", "ZDA", "GLL", "GNS", "GRS"
};
// Обработайте полное, завершенное CRLF предложение NMEA.
void processSentence(String &sentence) {
// Sanity check.
if (sentence.substring(0, 3) != "$GP") {
Serial.print("WARNING: invalid sentence: ");
Serial.print(sentence);
return;
}
// Record the sentence if it has an interesting type.
String type = sentence.substring(3, 6);
for (int i = 0; i < 6; i++) {
if (type == monitoredTypes[i]) {
File dataFile = SD.open("GPS1.txt", FILE_WRITE);
if (type == "GGA") { // этот тип кажется особенным
dataFile.print(dt);
dataFile.print(" ");
dataFile.print(tm);
dataFile.print(msec);
dataFile.print(",");
}
dataFile.print(sentence);
dataFile.close();
}
}
}
Способ его использования состоит в том, чтобы буферизировать входящие символы до тех пор, пока вы не получите полное предложение (обозначенное окончательным LF), а затем отправьте этот буфер в эту функцию:
String buffer;
void loop() {
while (Serial.available() > 0) {
char c = Serial.read();
buffer += c;
// В конце предложения обработайте и очистите буфер.
if (c == '\n') {
processSentence(buffer);
buffer = "";
}
}
}
Обратите внимание, что для того, чтобы избавиться от строки, не потребуется слишком много работы
класс и вместо этого используйте простые строки C. Простые строки гораздо более
удобны для памяти.
- Как разделить входящую строку?
- Как вывести несколько переменных в строке?
- форматирование строк в Arduino для вывода
- Очень простая операция Arduino Uno Serial.readString()
- DateTime в строку
- Как преобразовать строку в массив байтов
- Как отправить строку на мастер с помощью i2c
- Создание форматированной строки (включая числа с плавающей запятой) в Arduino-совместимом C++
Вы никогда не проверяете, что
indexOf()
находит'\r'
. Почему вы пытаетесь обрабатывать пять сообщений одновременно, а не одно за другим?, @Edgar BonetПредоставьте более подробное описание того, какие данные сообщения у вас есть в этой строке, какой ошибочный вывод вы получаете и где в коде это происходит., @chrisl
Если (strID == "TG" || "DA" || "LL" || "NS" ... то это бред, @SBF
Я предоставлю вам свою полную программу. На самом деле между предложениями нет задержки, поэтому, когда процессор записывает одно предложение на SD-карту, приходит 2-е сообщение, и большую часть времени он сохраняет глюк на SD-карте., @Omar Rai
Если вам интересно,
"DA"
,"LL"
и"NS"
все [правдивы](https://en.wikipedia.org/wiki/Truth_value#Computing) в C++. Итак, упомянутая выше ерунда функционально эквивалентнаif (true)
., @timemage@OmarRai, просто чтобы прояснить, вы хотите использовать ссылку «редактировать» под своим вопросом, чтобы добавить дополнительные детали к вопросу. Если вы хотите, чтобы люди задавали вам вопросы, вы хотите «Добавить комментарий». Единственный раз, когда вы собираетесь «Опубликовать свой ответ», это если вам удалось решить нашу собственную проблему., @timemage