ricezione stringa seriale aiuto per interpretazione dati?

ciao a tutti,

avrei bisogno di superare un punto morto e non ho trovato discussioni simili, qualcuno sa farmi superare questo scoglio?
la mia idea è far comunicare due arduino a distanza, io vorrei inviare dall'arduino master una stringa con variabili separate da virgole (tipo stringa NMEA), vorrei far ricevere dallo slave i dati e far riconoscere le variabili, ma non sono in grado di separare i diversi dati e farli riconoscere come variabili.
mi sono spiegato da cane, faccio un esempio, voglio mandare una stringa tipo:
$GSUB,(variabile1 da 0 a 255),(variabile2 da 0 a 255),(variabile3 da 0 a 255),(variabile4 da 0 a 255),#
con $ inizio stringa e # fine stringa.
c'è qualche libreria o codice che mi fa riconoscere la stringa in ingresso ad esempio come un array dove posso dire all'arduino slave che ad esempio array [1] è la variabile 1 e così via?
scusate se sono stato lungo, e grazie.

Paolo

ciao

non ho ben capito la domanda... in pratica vuoi far parlare due arduino via seriale con un protocollo tuo?
Hai già visto come inviare dati su seriale? In ricezione ricevi un byte alla volta quindi ti basta una semplice macchina a stati che faccia qualcosa tipo:

STATO 1: aspetto l'inizio $
STATO 2: sto ricevendo il pacchetto

ricevo un nuovo carattere
sono in stato 1? Sì, il carattere è $? Si passo in stato 2, No resto in stato 1
Sono in stato 2? Sì, il carattere è #? Sì passo in stato 1, No salvo il carattere nell'array di ricezione incrementando un contatore che mi dice a che punto sono arrivato

ciao luca,
intanto grazie per l'appoggio!
si vorrei far parlare i due arduino con una seriale inventata a distanza.
si credo di aver visto come inviare dati via seriale, e non ho problemi per l'invio (ho testato con porta com del pc tramite max 232).
volevo fare qualcosa di simile a quello che mi hai consigliato te, ma mi sono inchiodato pesantemente, in pratica se quello che ricevevo lo mettevo ad esempio in un Serial.print mi dava sul serial monitor la stringa da me inviata, ma non sono stato in grado di "infilare la stringa " in un array di ricezione.
c'è qualche codice che per esempio mi dica array[]={stringa ricevuta};
comunque hai capito il punto, mi puoi chiarire il concetto di macchina a stati (io sono un po' verde, in genere uso l'if).
comunque grazie di nuovo

paolo

ciao

vista la trasmissione seriale, dovrai essere tu a fare qualcosa tipo:

char rx_buffer[20];
int rx_position = 0;

if (Serial.available()) {
rx_buffer[rx_position++];
if(rx_position == 20) rx_position = 0;
}

in questo modo:

  • ogni volta che è disponibile un byte via seriale lo metti nel buffer, incrementando la posizione in cui "salvi" i dati
  • se vai oltre la dimensione del tuo buffer devi per forza ripartire da 0 sovrascrivendo...

La macchina a stati è solo un "modello", in pratica si riduce a mettere degli IF(...), tipo:

#define STATO1 1
#define STATO2 2
int stato_attuale;

stato_attuale = STATO1;
...
if(stato_attuale == STATO1) %% (carattere_ricevuto == '$')

ma così fa più figo quando lo dici :grin:

pensavo di capirci di più...

quindi il char rx_buffer[] con le posizioni da 0 a 20 sarebbe la mia stringa ?
avevo fatto una cosa simile con il Serial.read, ma il mio problema è che non riesco a infilare in un array ad esempio rx_buffer[da 0 a 20], e sono convinto che mi perdo veramente in un bicchiere d'acqua.

comunque proverò sia l'if che la macchina a stati
grazie poi ti faccio sapere se sono riuscito a pigiare il buffer nell'array XD
paolo

ciao non so cosa intendi per array di stringa ricevuta, forse intendi raccogliere tutto in una stringa

String readString;
void loop()
{
while (Serial.available())
{
delay(1);
if (Serial.available() >0)
{
char c = Serial.read();
readString += c;
}

if (readString.endsWith('#'))
{
Serial.println(readString);
readString="";
break;
}
}

readString="";
}

in questo caso readString verrà compilato solo se il carattere terminale è # if (readString.endsWith('#')) altrimenti verrà svuotata readString="";
inoltre char c = Serial.read(); ti permette di leggere e analizzare un carattere alla volta potresti vedere così in che punto si trova la virgola e registrarlo.
readString += c; fa la concatenazione

che puoi anche sostituire con
readString .concat(char(Serial.read()));

non so se è quello che chiedi

String readString;
//String InputBuffer = String();
int xx=0;

void setup() 
{
	Serial.begin(9600);
}

// esempio di stringa    $GSUB,255,255,255,255#
void loop() 
{
     xx=0;
     while (Serial.available()) 
     {
	  delay(1);
	    if (Serial.available() >0) 
            {
	      char c = Serial.read();
	      readString += c;
              xx++;
                  if (c ==',')
                 {
                   Serial.print(String(xx));
                   Serial.print(";");
                 } 
              
            }
                  if (readString.endsWith('#'))
                  {
                    Serial.println("");
                    Serial.println(readString);
	            readString="";
                    break;       
                  }
      }

      readString="";	
}

questo esempio ti da la posizione delle virgole che potresti usare
ad esempio con
1a_virgola= readString.substring(0,char_posiz_a);
2a_virgola= readString.substring(char_pos_a+1, char_posiz_b);
3a_virgola= readString.substring(char_pos_b+1, char_posiz_c);

ottieni i valori numerici tra una virgola e l'altra ovviamente questo è un esempio di uso del substring le tue posizioni che saranno valori interi le puoi registrare in un array e andarle a riprendere con un for.

una volta ottenuta la stringa per intero cerca un argomento sui separatori, split di stringhe, parsing di stringhe ecc


un altro esempio:

#include <string.h>

char sz[] = "Here, is some, sample, 100, data, 1.414, 1020";
void setup()
{
char *p = sz;
char *str;
Serial.begin(9600);
while ((str = strtok_r(p, ",", &p)) != NULL) // delimiter is the semicolon
Serial.println(str);
}

void loop(){}

Generando questa uscita

Here
is some
sample
100
data
1.414
1020

ciao

x iscrizione

buongiorno ragazzi,

@ pablos grazie,
ora ho un po' di materiale su cui studiare un po'...ero proprio bloccato e mi annodavo sui caratteri, virgole ecc.
ciao anche a te testato, anche se non ho capito cosa vuol dire x iscrizione

serve per seguire il post.
quando si risponde ad un topic automaticamente si ci iscrive a seguire il thread.
ma quando il post e' interessante e non si ha nulla da rispondere ? in quel caso mi iscrivo scrivendo "x iscrizione" :slight_smile:

signorbarro,

mi sembra di capire che tu voglia inviare singoli caratteri e valori da 0 a 255. Forse esiste un modo semplice per gestirli: usare i caratteri ASCII. In questo modo, invece di mandare ad esempio 123, mandi il carattere {
Quindi non ti devi preoccupare di separare i caratteri con ; ma mandi una stringa completa.
Tale stringa viene messa in un array e gestisci poi i singoli caratteri.

Questo il codice:

#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3);
char myar[5];
int indice = 0;
void setup()
{
mySerial.begin(19200);
}
void loop()
{
indice = 0;
if (mySerial.available()>0){
while (mySerial.available()){
int serialIn = mySerial.read();
delay(5);
myar[indice] = serialIn;
indice++;
}
delay(1500);}
}

Qui trovi informazioni su come usare SoftwareSerial bidirezionale:

Ciao

signorbarro,
naturalmente i caratteri ASCII vanno da 0 a 127, quindi per avere valori da 0 a 255 devi usarne 2 e poi sommarli.

Scusa per l'errore

Aldo:

quando tu trasmetti (vedi ad esempio la funzione Serial.write() di Arduino) invii un BYTE, quindi un valore 0-255... che poi tu interpreti tale byte come carattere ASCII è solo una tua convenzione, comunque trasmetti UN BYTE, non hai alcun motivo per "sommare" due caratteri o altro se vuoi inviare un valore 0-255.

State perdendo il filo, veramente il suo problema era separare i dati...... da una stringa fatta così
es: $GSUB,255,255,255,255# lui vuole trovare i dati tra una virgola e l'altra :slight_smile: sapendo che $ è l'inizio stringa e # è il termine

Ciao

se il protocollo è "inventato", è inutile trasmettere un separatore tra byte e byte: in ricezione come indicavo prima ti basta salvare il "pacchetto" in un array per potervi accedere via indice e quindi estrarre il byte nella posizione che vuoi.
bye

true :slight_smile:
bye

rigrazie a tutti per la partecipazione,

@testato, grazie per ritenere il topic interessante

@ aldo, no non era un problema di trasmissione o caratteri ascii (come ha precisato pablos)

@luca, ho messo le virgole come separatore perche ho supposto che il dato trasmesso potesse avere 1, 2 o tre cifre (valore da 0 a 255), quindi non mi volevo legare a cercare i byte nel buffer con la posizione
detto terra terra volevo prendere la stringa inviata e sbatterla ad esempio in:
array []={stringa ricevuta con le variabili separate da virgole};
array[1]= prima variabile inviata
array[2]=seconda variabile inviata
ecc.
ma mi sembra di capire che non è immediato come pensavo
(devo essere sincero che per casini col lavoro non ho ancora ne provato ne ragionato sulla tua soluzione, ma lo farò presto ..la macchina a stati mi intriga anche come cultura)

@pablos penso che tu abbia "decifrato" la mia domanda probabilmente era posta in termini poco tecnici, ma sono comunque contento che abbia incuriosito tanta gente (anche il tuo suggerimento sarà seguito presto, quando avrò il tempo di agganciare l'arduino sul pc).

ciao di nuovo a tutti

Ciao

per fare lo split di una stringa o ti scrivi tu la funzione utilizzando i metodi che l'oggetto String ti mette a disposizione (indexOf, subString...) oppure puoi usare la funzione strtok_r che non è delle librerie Arduino ma è nativa del compilatore ed è sicuramente più complessa da usare:

http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html#gac0dbc25e8b202114031a4aa2a7c5177b

non esistono risposte sbagliate,ma domande fatte male!

allora ieri sera mi sono un po' sbizzarrito con i consigli di pablos, ed era perfetta per ottenere la stringa che inviavo io.
la mia idea era di ottenere però i valori numerici come int quindi non funzica in quanto sono parte di stringa.
io ho pensato:

  • soluzione tipo luca, butto nel buffer di rx e estrapolo dalla "," in poi i byte come variabile int provvedendo a catalogarli come unità, decine e centinaia, in modo da riottenere una variabile int da 0 a 255.
  • soluzione da valutare ho visto l'esistenza della funzione atoi per convertire stringa in int... sapete dove posso trovare la libreria "stdlib.h"?
    in pratica io con i valori che "spedisco con la stinga vorrei comandare 4 motori

non voglio logorare nessuno, e non voglio codici già fatti, ma un aiuto mi farebbe guadagnare ore di sonno XD

ciao a tutti

ciao

la funzione atoi() è già disponibile in Arduino senza necessità di aggiungere librerie.
Se ti serve trasmettere un valore 0-255 ti basta un byte, non serve convertirlo o dividere unità-decine... quando ricevi il singolo byte, ecco quello è già il valore!
bye

sei un mago!
allora se io mi prendo ciò che viene letto dopo le virgole mi da già i valori che voglio!
e posso dare il fine stringa per dare lo stop
giusto per finire di approfittarmi di voi..allora le virgole sono inutili e incasinanti?

lo sapevo che mi stavo complicando la vita ma era tutta una cavolata risolverlo

stanotte ritento!
grazie di nuovo

Paolo