inviare da monitor seriale un intero 3 cifre

Salve. Ciò che sto per chiedere sarà già stato argomento di discussione, ma mi sono perso tra Google e i titoli. Per cui chiedo di facilitarmi il compito.

Il primo metodo che ho copiato e inserito nello sketch che sto portando avanti usa millis e atoi. Funziona bene ma mi blocca il mio Mega: altre sezioni dello sketch, parte loop, non vanno avanti, sia ciò che è programmato prima di questa sezione, che dopo.
Questo sistema era stato descritto in una risposta del moderatore in un vecchio post:

int incomingByte;   
char Data[8];
int i;
unsigned long Tempo;

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

void loop(){

   do {
     if (Serial.available()) {       
       Data[i] = Serial.read();
       i++;
       }     
     if(i<1)Tempo = millis();
     } while (i<5&&(millis()-Tempo) < 500);
 
   Data[i] = 0;   
   incomingByte = atoi(Data); 
   i=0;
   Serial.println(incomingByte);
}

Come scritto prima tra le varie cose che questo mio sketch dovrebbe gestire, c’è un display LCD, il quale prima dell’inserimento mi faceva apparire 2 parole sulla riga in alto, poi alla riga sotto il numero dei secondi ricavato sempre da millis ([millis/ 1000). Ora tutto resta fermo a 0 come se ci fosse un reset continuo. Non sono esperto, ma forse millis tirato in ballo in un ciclo do…loop potrebbe interferire? Ma le immissioni dei numeri dal monitor e le uscite dal Mega al monitor vanno avanti tranquillamente…
Ho controllato che non fossero tirate nuovamente in ballo variabili dello stesso nome in varie parti del listato: non ne ho trovato. Per cui non comprendo il blocco.

La seconda possibilità invece gira senza “infastidire” il resto del programma.

Ho trovato uno sketch in cui si ricevono caratteri alfanumerici da monitor, e dalla stringa che viene a formarsi si estrae il numero. Ma questo è fisso: deve contenere obbligatoriamente 9 cifre, per cui, se volessi il numero 13 dovrei scrivere “000000013”. Quanto mai scocciante dato che ho bisogno solo di 3 cifre. Ho provato ad accorciare la cifra intervenendo sullo sketch, ma non sono riuscito… manca il manico.

Se c’è qualche topic che fa al caso mio, pregherei qualcuno di segnalarlo.
Grazie

Ciao

Ti rispondo dall'auto quindi telegrafico

Stai facendo la lettura bloccante e quindi tutto il resto aspetta

Si può mettere a posto, ma non è questione di cambiare due righe

È storia di ripensare tutto il programma

Stasera ti cerco post di esempio

Ti ringrazio per la disponibilità.

Il problema è qui:

if(i<1)Tempo = millis();

perché per uscire dal tuo ciclo

while (i<5&&(millis()-Tempo) < 500);

devono arrivare almeno 4 caratteri o essere trascorso aun tempo maggiore di mezzo secondo.
Prova a controllare il flusso del ciclo loop e prova a capire cosa succede se non c’è nulla nella seriale.

Ciao! Ti serve leggere una stringa da seriale e convertila in numero con atoi().

Io ti scriverei volentieri le 4 righe, ma la filosofia del forum è insegnare e non dare tutto pronto. :)

Modificando un po il tuo codice, speriamo che nessuno si offenda se fornisco codice. Nel serial monitor, dovrai selezionare in basso a destra, aggiungi newline

int incomingByte; 
char Data[8];
int i;


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

   if(Serial.available()){// Se ci sono caratteri sulla seriale inizio la lettura
       do {
          if (Serial.available()) {  // Solo se c'è un carattere leggo    
              Data[i] = Serial.read();
              i++;
           } // End if    
     
        } while (Data[i-1]!='\n'); // Fino a quando trovo il carattere nuova riga, da impostare nel serial monitor
   } // End if
   Data[--i] = 0;   
   incomingByte = atoi(Data);
   i=0;
   Serial.println(incomingByte);
}

Il tuo codice non prevede di smettere di attendere se non arrivano tutti i caratteri, da quel che si capisce a lui serve che in caso di parziale trasmissione il codice non resti bloccato nell'attesa dei caratteri

@fabpolli non avevo capito che avesse questa necessità! :) Comunque è strano che ci sia questa necessità da monitor seriale, se trasmettesse con un programma potrebbe succedere che non trasmetta 3 cifre, ma dal monitor seriale sei tu che scrivi tre cifre e poi le trasmetti ??

Credo che il monitor seriale sia a solo scopo di debug/test momentaneo, poi la direzione verrà inviata da qualche dispositivo

noi avevamo provato a cercare qualche esempio, come promesso

ma non abbiamo trovato molto, e quindi ho fatto prima a scrivere uno scheletro di programma che gestisce la comunicazione seriale E altri eventi asincroni (con la millis )

si tratta solo di uno scheletro, che mostra come si potrebbe impostare il tutto

ovvio che senza sapere con esattezza cosa deve fare e come comunica non possiamo esporci troppo ne andare troppo in la con le ipotesi

comunque lo scheletro è qui:

/*
   Una nuova idea DDD
   Del Dinamico Duo

   Sentitevi liberi di copiare
   Sentitevi liberi di trarre ispirazione
   Sentitevi liberi di dare un cenno di ringraziamento



   Creato con IDE 1.8.10
*/

unsigned long int azione = millis();
#define PASSO 1500

#define PULSANTE 2
bool statoled;
#define LED 3
#define LAMPEGGIATORE 4
bool statolampeggio;
void setup(void)
{
   Serial.begin(9600);
}

void loop(void)
{
   /*
      qui faccio delle cose
      ad esempio un lampeggio senza delay
   */
   if ((millis() - azione) > PASSO)
   {
      azione = millis();
      statolampeggio = !statolampeggio;
      digitalWrite(LAMPEGGIATORE, statolampeggio);
   }

   /*
      oppure controllo lo stato di un pulsante
      e se serve lo uso per accendere/spegnere un led
   */
   if (digitalRead(PULSANTE))
   {
      // primo aspetto che venga rilasciato
      while (digitalRead(PULSANTE)) {}

      // attenzione che tenere premuto è bloccante, pressioni brevi
      // il debounce deve essere hardware
      // inverto lo stato della luce
      statoled = !statoled;
      // aggiorno la luce
      digitalWrite(LED, statoled);
   }

   // in asincrono guardo se c'è roba dalla seriale

   if (Serial.available())
   {
      /* se c'é roba la leggo un carattere per volta
          così non è bloccante
      */
      char cx = Serial.read();

      /* però serve di avere un riconoscimento di start, stop, cifre e possibili errori

          quindi per il momento mi limito a rispedire al mittente solo alcun dei caratteri ricevuti
          per dimostrare che posso riconoscere i singoli caratteri e gestirli caso per caso
      */
      if (cx == 'a')
      {
         Serial.println("Hai schiacciato una a minuscola");
         return;
      }

      if (cx == 's')
      {
         Serial.println("Hai schiacciato una s minuscola");
         return;
      }

      if (cx == 'z')
      {
         Serial.println("Bravo, hai cambiato la luce");
         // inverto lo stato della luce
         statoled = !statoled;
         // aggiorno la luce
         digitalWrite(LED, statoled);
         Serial.println("Però potevi farlo anche col bottone");
         return;
      }

      if (cx > 'a' and cx < 'g')
      {
         Serial.println("Hai premuto b, c, d, e oppure f minuscola");
         return;
      }

      if (cx > 'a' and cx < 'g')
      {
         Serial.println("Non hai dato un comando accettabile");
         return;
      }
   }
}

per la parte seriale de dobbiamo gestire la comunicazione asincrona ed evitare eventuali time out del resto del sistema e prevedere errori, conferme e similia serve primaditutto creare un protocollo, stabilire start e stop della trasmissione ed implementare una macchina a stati che interpreti il protocollo

ma servono delle info da parte dell’autore:

cosa trasmetti, come e con che frequenza, nel frattempo cosa fai, è pensabile fermare tutto il resto oppure serve comunque una reattività dell’Arduino anche durante la ricezione?

programmi per leggere numeri dalla seriale negli anni passati ne ho scritti a badilate ma serve sempre di sapere cosa ci si vuole fare e cosa si ha a disposizione la prima legge di Nelson (che sono io) recita: Chi vuole sapere cosa deve fare deve sapere cosa vuole fare

Grazie per tutti i suggerimenti che metterò in pratica quanto prima. Chiarisco il motivo per cui vorrei impratichirmi nella comunicazione col monitor seriale. Il dispositivo da realizzare dovrebbe essere un'unità aggiuntiva al control box di un accordatore di antenna autocostruito. Per controllo vorrei mandare e ricevere da monitor seriale delle terne di posizionamento di 3 cifre da 1 a 100, da conservare per ora in variabili, ma in seguito da inviare alla eeprom, in modo da avere un giorno una decina di terne da utilizzare quando decidessi di muovere i componenti dell'accordatore in una delle posizioni memorizzate. Il progetto mi aiuterà ad impegnarmi ancora per qualche tempo... ho 70 anni: vorrei uno svago più distensivo che stare a trafficare, spesso anche con i 2400 V dei miei p.a. home made, come ho fatto finora... A livello programmazione mi ero fermato anni fa al Visual BASIC. Provengo dal BASIC 2 del C64. Ero insegnante di lettere. Grazie. Michele

Quindi sempre da monitor seriale Sempre scritto a mano giusto?

Ma l'accordatore va già?

Hai un programma più o meno funzionante?

L'accordatore funziona bene. Ha 3 componenti: C1, condensatore variabile doppio, alta tensione di isolamento, con una rotazione di 180 gradi, L1 bobina con una sessantina di spire, quindi 60 giri da compiere, C2 condensatore da 1500 pF max sempre 180 gradi. Tutti e 3 hanno concatenati dei potenziometri con cui rilevare la posizione ed ognuno dei pezzi è equipaggiato con relè e fine corsa. Al momento si comandano con 3 distinti interruttori a 0 centrale. Quando premo quello relativo a C1 verso l'alto, C1 si apre; viceversa se premo verso il basso. Sullo strumento leggo la sua posizione. Quando premo quello relativo a L1, tocca a L1 muoversi e inviare posizione. Ecc. Una volta completato, Arduino mi darà la terna su display. In più manderei gli stessi dati al monitor. Sul control box c'è un secondo strumento, relativo a un ROS metro che ho piazzato sull'uscita, così da poter monitorare l'accordo. Con un carico fittizio all'uscita l'ho testato costruendomi una tabella di base; poi con quella di massima sono passato a verificarlo su varie antenne. Da 80 a 10 m. Quando si accorda, agendo sui 3 pezzi e ritoccandoli, perché ognuno influenza leggermente l'altro, si vede la tensione relativa alla potenza riflessa scendere a livello bassissimo. Tutto qui. Saluti

Grazie per tutti i suggerimenti che metterò in pratica quanto prima. Chiarisco il motivo per cui vorrei impratichirmi nella comunicazione col monitor seriale. Il dispositivo da realizzare dovrebbe essere un'unità aggiuntiva al control box di un accordatore di antenna autocostruito.

Beh se hai avuto a che fare con il basic del C64 avrai sicuramente chiaro il concetto di codifica ASCII. Ciò che spedisci da seriale sono singolo byte uno dietro l'altro, Come interpreti questi byte fa la differenza. Visto che sul monitor seriale puoi scrivere solo caratteri stampabili (visualizzabili), lato arduino servirà trasformarli in numeri. Visto che il monitor seriale non può stampare certi codici ASCII li si usa ad esempio come marcatori.

Uno dei marcatori (che ti hanno suggerito di attivare nel serial monitor) è new line, il codice ascii in decimale è 10 (0x0A in esadecimale), vedi qui la tabella ascii. Nel codice sorgente il new line può essere specificato in decimale, esadecimale o come carattere singolo, poiché esso non è rappresentabile con un sibmolo, si usano due caratteri di cui il primo è '\' a seguire uno dei caratteri stampabili, per un esempio osserva la tabella ASCII sotto la colonna CEC.

//  esempio di sequenze di escape CEC
byte lineFeed = '\n';    // 10 (0x0A)
byte carriageReturn = '\r';  // 13 (0x0D)

Quindi arduino può contare i caratteri ricevuti fino a quando incontra il marcatore new line. Per separare i byte puoi usare la virgola , . Esempio da spedire via serial monitor: s1,10, 100

Ciò che viaggia nel fili sono i seguenti byte (che esprimo in base 10): 115 49 44 49 48 44 49 48 48 10 Sono 10 byte, il 10 finale viene aggiunto in automatico dal serial monitor (se lo hai abilitato) e corrisponde a new line.

Arduino riceverà e collezionerà i byte in un buffer (array), dati che poi dovrai decodificare. Per adesso direi che ti puoi limitare a collezionare i dati su arduino e poi spedirli verso il serial monitor.

Se in arduino prevedi del codice che oltre ad accettare una stringa che inizia con 's' anche con altri caratteri puoi ad esempio fare in modo che arduino scriva i dati (decodificati) direttamente in eeprom.

Nello specifico il tuo dispositivo dovrebbe avere due modalità: Configurazione o Operativo In modo Configurazione puoi tramite seriale inviare stringhe di configurazione. Quando in modo operativo può riceve da seriale dei comandi e inviare dati verso il monitor seriale, ma i comandi non modificheranno il funzionamento del dispositivo.

Ciao.

PS: IW9AYT era mio padre.

Secondo me se sei tu a decidere cosa inviare, che sia da monitor seriale o che sia da un programma creato appositamente, allora non c'è pericolo che non venga inviato un numero di 3 cifre o un numero non valido.

Per cui ti basta ricevere la stringa "che tu sai che è corretta perché in qualche modo sei tu che la trasmetti", e trasformarla in numero intero con atoi().

L'esempio che ti ho postato potrebbe essere una buona base di partenza, penso di aver capito che non dovrai trasmettere un unico numero ma diversi per cui il programma sarà più complesso.

Ma comunque la stringa che trasmetti è sempre di 3 cifre, tu ricevi semplicemente una stringa e la converti con atoi(), senza il pericolo che ad esempio ti vengono trasmesse solo 2 cifre.

i2srm: Grazie per tutti i suggerimenti che metterò in pratica quanto prima. Chiarisco il motivo per cui vorrei impratichirmi nella comunicazione col monitor seriale ....

mi pare che gli accordatori remoti non funzionano cosi (anche io sono un radioamatore) piuttosto cercano di salvare i finali e monitorino il ROS, E IN BASE AL ROS muovono qualcosa per portarlo al minimo

>elrospo: Quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce. Gli utenti da device "mobile" ringrazieranno per la cortesia ;)

Guglielmo

P.S.: Ho troncato io il quote del post qui sopra ;)

Quindi arduino non ha "attività sua", si limita a ricevere comandi da seriale ed eseguirli, ritrasmettendo la situazione finale, giusto? non entro nel merito di come funziona l'accrdatore, mi fido di quello che dici, tre comandi ognuno da 0 a 100, e l'accordatore li "esegue" rispondendo con tre letture, ognuna da 0 a 100 o cosa? e sono solo tre oppure leggi anche il ROSmetro? e se sì, come?

Tornando ai 3 caratteri con return da spedire e rinviare, quesito che penso molti avranno incontrato, questi mi servirebbero soprattutto in fase di collaudo. Perchè in seguito dovrei leggere gli ingressi analogici da predisporre, con qualche algoritmo ricavare dalla tensione letta convertita nel range degli step che permette l'analogico e in seguito trasformarla in un valore intero da 1 a 100. Così da poterla memorizzare nella eeprom. Per ora non vedo un'automazione completa: primo perchè Arduino dovrebbe essere spento mentre sono operativo in TX, per evitare schermature e accorgimenti vari contro i ritorni RF; secondo, perchè questo primo approccio al problema lo vedo più fattibile per le mie modeste possibilità. Comunque la soluzione di piazzare l'accordatore vicino all'antenna è vincente, a causa del breve tratto di cavo coassiale impegnato. Infine il mio accordatore contrariamente a quelli automatici da palo stagni sul mercato gestisce tranquillamente oltre 700 W. Ha il ritorno di 2 tensioni che debitamente limitate con un potenziometro e manopola mi permettono di leggere il ROS su un secondo strumento. E non s'inceppa: neanche un transistor, solo qualche diodo.

senza un protocollo non va e non andrà mai
serve almeno uno start ed un terminatore (al limite lo stesso start successivo)
se come start-terminatore usi un fine riga e fai la ricezione asincrona (come ti ha indicato Salvor) all’ora è facile
anche senza passare per atoi(), basta solo contare le cifre mano a mano che le ricevi

suggerimento in pseudocodice:

se è un fineriga
   abbasso flag di ricezione incorso
   uscita=variabilediappoggio
   variabilediappoggio=0
altrimenti
   alzo flag di ricezione in corso
   variabilediappoggio=variabilediappoggio*10 + valore della cifra ricevuta