Registrare più variabili da seriale

scusate l'imprecisione sia nel titolo che in quello che sto scrivendo ma è davvero poco che mi sono avvicinato al mondo di arduino e sto cercando di imparare quindi anche qualsiasi consiglio/link/critica ecc sono ben accetti =)
vi spiego il mio quesito, mi serve che dal serial monitor del pc devo scrivere all'arduino una serie di 6 caratteri singoli (primo carattere, invio, secondo carattere, invio, ecc) così da creare sistema per poter lavorare anche matematicamente con ogni singolo valore inviato. Ho provato cosi ma non funziona:

int a;
int b;
Serial.read(a);
Serial.read(b);
if eccc...

ma non funziona perchè legge solo il primo poi il secondo non "lo aspetta". provando con parseInt va "meglio" ma devi rispettare le sue tempistiche perchè se scrivi troppo in fretta legge come un valore solo e se scrivi troppo lento resistuisce il secondo valore come 0... come posso fare? vi rigngrazio

chiedo scusa se per errore ho aperto un topic gia trattato ma onestamente ho cercato (credo abbastanza bene) ma non ho trovato nulla, se ho sbagliato a cercare chiedo scusa

while (Serial.available() < 1){
   //aspetta prossimo carattere
}
a = Serial.read();

vi espongo un altro problema legato allo stesso argomento, nella spiegazione di Serial non ho trovato risposta, se ho letto male chiedo scusa. quando chiedo di registrare una variabile da seriale arduino si aspetta di ricevere un solo int quindi una sola cifra, se scrivo ad esempio "125" lui giustamente registra tutte e tre le cifre in variabili diverse. il problema è che io devo operare con 2 variabili e se nella prima si scrive "12345" lui non solo fa quello che deve fare con "1","2","3" ma ricomincia il loop e occupa gia i primi due valori... come posso fare a far leggere solo 3 variabili alla volta scartando tutte le altre? scusate se tocco argomenti gia trattati o forse stupidi ma non ho trovato altro =)

devi usare un carattere "terminatore", opvvero un carattere (a tua scelta, di solito si unsa il newline \n) che indica quando finisce il tuo input.
quindi tu da arduino leggereai

125\n
12345\n

quindi dopo illoop che legge 3 cifre, farai un loop che butta via le cifre finchè non vede arrivare \n

Ho scritto un articolo, tempo fa, che spiega come gestire l'invio di dati su seriale. Spero possa aiutarti

scusate se insisto ancora su un argomento cosi "banale" ma io ci sto sbattendo la testa e non me ne faccio capace... il codice qui sotto è stra super banale... finchè non ci sono 3 valori nel buffer non fa niente, quando invece ci sono almeno 3 valori registra i primi 3 in altrettanti variabili. Tutti i caratteri che rimangono fuori vengono inseriti in una variabile temporanea che si cancella alla fine del ciclo... perchè non funziona secondo voi? se inserisco 6 valori li stampa tutti e 6 quando dovrebbe stamparne 3 e cancellare gli altri... altra domanda, perchè per catturare 3 valori nel primo ciclo while ho dovuto mettere <= 2 e non <=3? e poi scusate ma non mi è affatto chiaro il discorso del carattere di stop... per leggerlo devo usare readbyteuntil?

void setup(){
Serial.begin(9600);
delay(300);

}

void loop(){
while (Serial.available() <= 2){}
byte a = Serial.read();
byte b = Serial.read();
byte c = Serial.read();


Serial.println(a);
Serial.println(b);
Serial.println(c);
while (Serial.available()){
byte t = Serial.read();
}
}

Li invii tutti insieme oppure ad uno ad uno?
Se li invii ad uno ad uno, lo sketch riesce a prendere il 4° come il 1° della seconda tripletta e ripete lo sketch.

anche se li invio tutti insieme... se scrivo "123456" lui mi da 495051525354. Io mi aspettavo che i primi 3 entrassero nelle prime 3 variabili che venivano stampate, le altre 3 entravano nel secondo ciclo e quindi cancellate e invece le stampa tutte e 6

dadduni:
anche se li invio tutti insieme... se scrivo "123456" lui mi da 495051525354.

Attento ...
... stai ricevendo il valore ASCII (carattere e NON binario quindi) dei tuoi numeri :

49 = 0x31 = '1'
50 = 0x32 = '2'
51 = 0x33 = '3'
52 = 0x34 = '4'
53 = 0x35 = '5'
54 = 0x36 = '6'

... se vuoi dei numeri dovrai convertire da carattere a numero ... '1' (0x31) NON è uguale a 1 (0x01) !

Guglielmo

Tu hai detto che vuoi da tastiera inviare i numeri SEPARATAMENTE ... 1 cifra, invio, 1 cifra, invio, ... 1 cifra, invio e questo per 6 volte giusto ?

Allora, ti conviene prima di tutto programmare il monitor seriale in modo che, quando premi invio, esso venga trasmesso come CR (0x0D). In questo modo avrai una divisione esatta dopo ogni carattere, difatti riceverai 0xNN, 0x0D, 0xNN, 0x0D .... per 6 volte, dove 0xNN è il codice ASCII del carattere che avrai trasmesso.

Su Arduino ti basterà fare un ciclo che legge il carattere, se è diverso da 0x0D è il carattere del numero che stavi aspettando, se è 0x0D passi a ricevere il numero successivo.

In modo piuttosto semplice .. potresti gestire un array di 6 elementi dove li memorizzi ... :wink:

Ricorda che li stai ricevendo come CARATTERI e, se devi fare poi delle operazioni, dovrai trasformali nel corrispondente NUMERO. Inoltre, se usi per memorizzarli un array, ricorda che i 6 elementi sono numerati da 0 a 5.

Guglielmo

leo72:
Li invii tutti insieme oppure ad uno ad uno?

queto NON ha senso. anche se li invvi "tutti insieme" in realtà li stai inviando uno a uno alla massima velocità conentita dalla seriale, che, come dico sempre, è leeeeeenta!!! (sopratutto a 9600 baud, aka 960 byte/s, mentre la Serial.read() è in grado di fare almeno 100.000Hz, visto che l'ho provata con successo a 1,000,000 baud)

e questo per 6 volte giusto ?

no, ha fatto l'esempio con 126 e 123456, quindi il numero di cifre è sconosciuto ma >= 3

il vero problema è semplice: se invii 6 caratteri, essi impegano X ad arrivare ad arduino. Ma arduino è talmente veloce che quando i 3 caratteri sono arrivati ed entra nel ciclo, mancano ancora il 4, 5 e 6(dipende eh), poi mentre tu fai altro codice, arriva un numero inprecisato di caratteri, ma NON è detto che ci siano tutti. metti che impieghi 1/680 di secondo per fare i vari conti (che è tantissimo, quasi 2 ms, mi stupirei se quelle operazioni impiegano più di qualche centinaio di MICROsecondi, visto che sta scrivendo in un array buffer), quindi quando arrivi al ciclo while che svuota il buffer, in realtà ci sei arrivao così in fretta che esso non si è ancora riempito!!!

quindi ci sono 2 soluzioni; metti un delay prima del while per dare tempo ai caratteri di arrivare; questo deve essere superiore al tempo di ricezione di una lettera, ed eventualmente ripetuto per ogni carattere letto; oppure usi un carattere NON cifra (di solito si usa il carattere speciale '\n', newline, l'invio nei sistemi unix)

con il carattere '\0' il while finale diventa:

while ( Serial.read() != '\n' ){
   ; //just wait for the next byte
}

poi ricordati di aggungere il caratte di newline anche quando mandi i valiri all'arduino, se usi il serial monitor cì+ una piccola lista in cui puoi selezionare il valore da accodare, di default è su "nessuno", sceli newline (ln)
in pratica lato pc è come se usassi println() invece che print()

lesto:

leo72:
Li invii tutti insieme oppure ad uno ad uno?

queto NON ha senso.

Ha senso per il fatto che se spedisci una stringa, questa viene inviata tutta insieme ed essa resta nel buffer, per cui i 3 numeri extra saranno senz'altro svuotati dal while(serial.available). Mentre se li spedisce singolarmente, dopo il 3° carattere il codice ha tutto il tempo di infilarsi nel while, vedere che non c'è nulla (perché come hai detto tu la seriale è lenta rispetto alla CPU), uscire e poi ritrovarsi gli altri 3 caratteri e stampare anche quelli. :stuck_out_tongue:

lesto:

e questo per 6 volte giusto ?

no, ha fatto l'esempio con 126 e 123456, quindi il numero di cifre è sconosciuto ma >= 3

Lesto ... è chiaramente scritto nel suo primo post :

dadduni:
vi spiego il mio quesito, mi serve che dal serial monitor del pc devo scrivere all'arduino una serie di 6 caratteri singoli (primo carattere, invio, secondo carattere, invio, ecc)

... ovvero, come ho detto io ! ]:smiley:

Se poi durante le prove ha fatto qualche altra cosa, non cambia che le sue specifiche iniziali erano quelle ...

Guglielmo

questa viene inviata tutta insieme

non è vero, viene inviata esattamente come a caratteri singoli, ma a velocità massima (960Hz con baudrate a 9600), certo più veclocemente di quanto tu possa digitare su tastiera, ma abbastanza lento per passare dal while indisturbato. Ricorda che la seriale "pensa" a singlo carattere, non ha un sistema di "pacchetto" come il TCP o simili.

@gpb01: mea culpa, quindi banalemente basta unire la soluzione di aspettare tutta la stringa (di 6 caratteri) invece che solo i primi 3;

quindi il primo while diventa

while (Serial.available() < 6){}

e il secondo while si toglie e sostituisce con 3 Serial.read() che semplicemente sviotano il buffer (giusto x evitare che mentre si svolge il codice arrivi un 7° carattere, che sarebbe il 1° della seconda stringa, e venga erronamente cancellato dal while)

Lesto, vuoi fare gli occhi alle pulci? :wink:
Lo so che viaggia byte per byte, ma dal lato dell'interfaccia Arduino è come se arrivasse tutta insieme. C'è una periferica che riceve il byte e lo schiaffa nel buffer, se non lo leggi subito a quel byte si somma il successivo eccc..

ma scusa, non è fare le pulci. Nel momento in cui il suo while di attesa caratteri finiscek, ci sono 3 byte nel buffer.
Nel momento in cui arriva al while di attesa non fa in tempo ad arrivare NEANCHE UN SOLO carattere (il 4°), non viene quindi scartato nulla, a prescidere se invi la stringa tutta insieme oppure no lato arduino IDE. quindi quando il loop() termina e ritorni al primo while di attesa ti vedi arrivare i caratteri che vanno a "sporcare" la prossima lettura, ovvero esattamente il problema che accusa:

dadduni:
anche se li invio tutti insieme... se scrivo "123456" lui mi da 495051525354. Io mi aspettavo che i primi 3 entrassero nelle prime 3 variabili che venivano stampate, le altre 3 entravano nel secondo ciclo e quindi cancellate e invece le stampa tutte e 6

Perdonatemi, l errore è stato il mio che sono stato forse poco chiaro... mi spiego meglio :slight_smile: l idea do funzionamento è che l utente deve inserire "un numero, invio, secondo numero, invio, terzo numero, invio"... questo a livello teorico ma a quanto ho capito può anche scrivete "primo secondo e terzo, invio" e jon mi da problemi... se incontro un "utente burlone" che scrive "17394739292839ahgin^^/" i primi 3 numeri vengono registrati in variabili ma gli altri non mi devono disturbare il loop successivo:) perdonatemi per la poca chiarezza forse non ho le idee chiarissime e ho fatto um po di confusione

allora semplicementefarei così: conteggi quanto tempo ci mette un carattere ad arrivare via seriale, prima dell'ultimo while attendi il tempo perchè arrivi un carattere, e questo tempo lo aspetti anche ogni volta che il while si ripere (un do{}while(); in effetti è l'ideale)

in questo modo eviti il burlone che screive il "dsafsdafhukvhxclkvh"invio in un colpo solo, ma non uno che fa lettera per lettera o gruppi di lettere.

Sinceramente IMHO il metodo ideale diventa è dire "se passano X secondi e nessun dato è inserito, svuoto il buffer in ingresso e mi preparo alla prossima lettura"

questo anche se hai letto 1 o 2 cifre valide: così evita che il burlone prema una cifra sola, (mettiamo 5) poi si metta ad osservarela vittima che arriva e digita "123" e si vede una risposta che corrisponde a "512" senza capire perchè.

infatti se il tempo di attesa è di 1 o 2 secondi senza caratteri in input (magari metti una lucina che si accende quando sei in attesa di input), per quanto il burlone possa impegnarsi:

  1. non potrà inserire più di un valore sbagliato ogni tot tempo, evitando un DDOS che non influenza arduino, ma eventuali macchine pilotate da esso potrebbero impallarsi;
  2. non può lasciare mezzo input al prossimo operatore, che aspetterebbela lucina di via libera;
  3. se un utente sbagli ad inserire un numero, basta semplicemente attendere qualche istante;
  4. un eventuale tasto/lettera di reset input non fa altro che azzerare il tempo di attesa