Decodificare Nmea 0183 ecoscandaglio

Ciao a tutti.
Ho un problema nel decodificare correttamente una stringa seriale proveniente da un ecoscandaglio CruzPro Atu120B, il protocollo è un NMEA 0183 cosi' composto:

Data Ouput:
NMEA 0183 serial 4800 BAUD, $SDDPT, $SDDBT, $SDMTW

Data:
$SDDPT,xxx.x,CS (Depth in Meters)
$SDDBT,xxx.x,f,xxx.x,M,xxx.x,F
CS (Depth in Fathoms, Meters & Feet)
$SDMTW,xxx.x,C*CS (Water Temperature in Deg C)

Ho connesso l'ecoscandaglio ad un convertitore 232-TTL e da Arduino ricevo correttamente le stringhe.

A me interessa solo la profondità in metri, ed eventualmente la temperatura anche se non fondamentale. Cercando in rete ho trovato solo librerie inerenti a stringhe GPS ma non sono riuscito a modificarle con successo per decodificare questa stringa.

Qualche esperto potrebbe buttarmi giu' due righe di codice per estrapolare i dati o indicarmi come modificare una libreria GPS ?

Grazie !

Flavio

La libreria GPS, come la TinyGPS, è molto complessa.
Dovresti avere un approccio più semplice.
Prova a vedere questo --> http://snipplr.com/view.php?codeview&id=23214
Con poche modifiche dovresti riuscire a leggere i dati che vuoi.

Ciao e grazie della risposta,
Scopiazzando da esempi in rete ho scritto questo codice che decodifica la stringa e mi restituisce le due variabili che mi servono, funzionare funziona , il problema è la lentezza , teoricamente dovrei ricevere due dati al secondo ma in realtà ne decodifico uno ogni due secondi circa :frowning:

Secondo voi si puo' ottimizzare ?

#include <string.h>
#include <stdio.h>
#include <avr\io.h>
#include <avr\interrupt.h>
#include <Wire.h>
#define DIM 20
#define DIM2 80
#define DIM3 15

struct tokens {
 byte char_index;
 char array[DIM2];
 char *token[DIM3];
}  Sonar_tokens;

float Depth, Temp;

void setup()
{
Serial.begin(4800);

}

void loop() {

 read_Sonar();
  
 }
 
void read_Sonar() {
  
 while (Serial.available()>0) {
   
  if (read_tokens(Serial.read(), &Sonar_tokens)) {
    
   if (!strcmp(Sonar_tokens.token[1],"$SDDPT")) Depth = atof(Sonar_tokens.token[2]); Serial.println((int)(Depth*100));
   
   if (!strcmp(Sonar_tokens.token[1],"$SDMTW")) Temp = atof(Sonar_tokens.token[2]); Serial.println((int)(Temp*100));
 
  }
 }
}

int read_tokens (char character, struct tokens *buffer) {
 char i, *p, *token;
 if (character == '\r') {
  buffer->array[buffer->char_index] = 0;
  buffer->char_index = 0;
  if (!checksum(buffer->array)) return 0;
  p = buffer->array;
  i = 0;
  while (token = strtok_r(p, ",", &p)) buffer->token[++i] = token;
  return i;
 }
 if (character == '\n') {
  buffer->char_index = 0;
  return 0;
 }
 buffer->array[buffer->char_index] = character;
 if (buffer->char_index < DIM2) (buffer->char_index)++;
 return 0;
}

int checksum(char *str) {
 int j, len, xor1, xor2;
 len = strlen(str);
 if (str[0] != '

) return 0;
if (str[len-3] != '') return 0;
xor1 = 16
hex2int(str[len-2]) + hex2int(str[len-1]);
xor2 = 0;
for (j=1;j<len-3;j++) xor2 = xor2 ^ str[j];
if (xor1 != xor2) return 0;
return 1;
}
int hex2int(char a) {
if (a>='A' && a<='F') return 10+(a-'A');
if (a>='a' && a<='f') return 10+(a-'a');
if (a>='0' && a<='9') return a-'0';
return 0;
}

Ma leggi e scrivi sulla stessa seriale?
Dovresti aggiungerne un'altra con SoftwareSerial.
Nel caso tu abbia l'Arduino Mega, ti ricordo che ha 4 seriali hardware.

Prova così.

#include <SoftwareSerial.h>
#include <string.h>
#include <stdio.h>
#include <avr\io.h>
#include <avr\interrupt.h>
#include <Wire.h>

#define DIM 20
#define DIM2 80
#define DIM3 15
#define ECOTX 7
#define ECORX 8

SoftwareSerial EcoSerial(ECORX, ECOTX); // RX, TX

struct tokens {
  byte char_index;
  char array[DIM2];
  char *token[DIM3];
}  
Sonar_tokens;

float Depth, Temp;

void setup()
{
  delay(2000);
  Serial.begin(9600); // Serial Monitor
  Serial.println("Arduino Start!");
  EcoSerial.begin(4800);
}

void loop() {
  read_Sonar();
}

void read_Sonar() {
  while (EcoSerial.available()>0) {
    if (read_tokens(EcoSerial.read(), &Sonar_tokens)) {
      if (!strcmp(Sonar_tokens.token[1],"$SDDPT")) Depth = atof(Sonar_tokens.token[2]); 
      Serial.println((int)(Depth*100));
      if (!strcmp(Sonar_tokens.token[1],"$SDMTW")) Temp = atof(Sonar_tokens.token[2]); 
      Serial.println((int)(Temp*100));
    }
  }
}

int read_tokens (char character, struct tokens *buffer) {
  char i, *p, *token;
  if (character == '\r') {
    buffer->array[buffer->char_index] = 0;
    buffer->char_index = 0;
    if (!checksum(buffer->array)) return 0;
    p = buffer->array;
    i = 0;
    while (token = strtok_r(p, ",", &p)) buffer->token[++i] = token;
    return i;
  }
  if (character == '\n') {
    buffer->char_index = 0;
    return 0;
  }
  buffer->array[buffer->char_index] = character;
  if (buffer->char_index < DIM2) (buffer->char_index)++;
  return 0;
}

int checksum(char *str) {
  int j, len, xor1, xor2;
  len = strlen(str);
  if (str[0] != '

Collega l'ECO ai PIN 7 e 8, oppure ridefiniscili nel #define.) return 0;
  if (str[len-3] != '') return 0;
  xor1 = 16
hex2int(str[len-2]) + hex2int(str[len-1]);
  xor2 = 0;
  for (j=1;j<len-3;j++) xor2 = xor2 ^ str[j];
  if (xor1 != xor2) return 0;
  return 1;
}

int hex2int(char a) {
  if (a>='A' && a<='F') return 10+(a-'A');
  if (a>='a' && a<='f') return 10+(a-'a');
  if (a>='0' && a<='9') return a-'0';
  return 0;
}


Collega l'ECO ai PIN 7 e 8, oppure ridefiniscili nel #define.

Aggiunto codice.

l'ecoscandaglio ti da la misura di un punto o di una linea o di un tot di punto che formano una linea?
funziona anche fuori dall'acqua?

Da la misura di un punto sulla sua verticale e funziona solo in acqua.

se googli cruzpro atu 120 bt trovi tutte le info.

Ciao Matrix.

Ce l'hai fatta alla fine?

Salut.