problema atoi()

Salve a tutti,
come ho detto al mio primo post, sto cercando di realizzare un controllo di temperature in fase di preparazione della birra.
Il tutto funziona bene grazie ai vostri consigli ma adesso vorrei passare i valori delle variabili di temperatura e tempo tramite la porta seriale in modo da poterli leggere da excel

ecco il mio codice completo

//controllo temperature in fase di mash
//definisco tempi e temperature
int prt = 60; //tempo di protein rest
int prc = 0; //temperatura protein rest
int m1t = 5; //primo step tempo di mash 
int m1c = 63; //primo step temperatura di mash
int m2t = 5; //secondo step tempo di mash 
int m2c = 68; //secondo step temperatura di mash
int mot = 6; //tempo di mash out
int moc = 78; //temperatura di mash out
int ciclo=1;//conto i cicli
int Temp=0;//temperatura del ciclo
int Tempo=0;//tempo del ciclo
int R=0; //controllo se ho già scaldato
char cifre[3]; //imposto il vettore che contiene le letture da seriale
#define ITP A1 //temperatura Mosto
#define ITM A2 //temperatura Piastra
#define P 1
#define F1 13
#define F2 12
#define F3 11
#define F4 10
#define FR 9
#define FINE 8

void setup()
{
  Serial.begin(9600);//inizializzo porta seriale
  pinMode (P, OUTPUT);//piastra
  pinMode (F1, OUTPUT); //fase1
  pinMode (F2, OUTPUT); //fase2
  pinMode (F3, OUTPUT); //fase3
  pinMode (F4, OUTPUT); //fase4
  pinMode (FR, OUTPUT); //riscaldamento
  pinMode (FINE, OUTPUT);//fine cottura
  
}
void loop(){
  switch (ciclo){//eseguo il primo ciclo di riscaldamento e cottura
  case 1:
  
  leggoseriale();//richiamo la funzione per leggere la seriale
  prc= atoi(cifre);//scrivo il valore letto nella temperatura
  
    Tempo=prt*60;
    R=0;
    do{
      riscaldamento (prc);//riscaldo il mosto
      R++;
    }while (R<1);
    digitalWrite (F1,HIGH);//indico che sono in fase 1
    mantenimento(Tempo,prc);//cottura mosto
    
  case 2:
    Tempo=m1t*60;
    R=0;
    do{
      riscaldamento (m1c);
      R++;
    }while (R<1);
    digitalWrite (F2,HIGH);
    mantenimento(Tempo,m1c);
  case 3:
    Tempo=m2t*60;
    R=0;
    do{
      riscaldamento (m2c);
      R++;
    }while (R<1);
    digitalWrite (F3,HIGH);
    mantenimento(Tempo,m2c);
  case 4:
    Tempo=mot*60;
    R=0;
   do{
      riscaldamento (moc);
    }while (R<1);
    digitalWrite (F4,HIGH);
    mantenimento(Tempo,moc);
    case 5:
    digitalWrite(FINE,LOW);
    finecottura();
  }
}


void riscaldamento(int Temp){ //inizio a riscaldare il mosto per la fase successiva

  while (R<1){
  if (analogRead(ITM)<Temp)
  {
    digitalWrite(P, HIGH);

  }
  if (analogRead(ITM)>=Temp)
  {
    digitalWrite (P,LOW);
    R=1;
    return ;
  }
  }
}
int mantenimento (int Tempo, int Temp){ //mantengo la temperatura impostata
 int TC=290;
 while (TC<Tempo){
   if (analogRead(ITP)<Temp&&Tempo>TC){//accendo la piastra se la temperatura è bassa
   digitalWrite(P,HIGH);
   digitalWrite(FR,HIGH);
 }
 if (analogRead(ITP)>Temp&&Tempo>TC){//spengo la piastra se la temperatura è alta
 digitalWrite(P,LOW);
 digitalWrite(FR,LOW);
 }
 
 if (TC==Tempo){ //interrompo il ciclo allo scadere del tempo di fase
 ciclo++;

 return ciclo;
 }
 delay(1000);
 TC++;
}
}
int finecottura(){
digitalWrite(P,LOW);
digitalWrite(FINE,HIGH);
delay(1000);

ciclo=5;

}
String leggoseriale(){
while (Serial.available()>0){

for (int i=0;i<3;i++){
cifre[i]=Serial.read();
}
return cifre;
}
}

in questo punto:

  leggoseriale();//richiamo la funzione per leggere la seriale
  prc= atoi(cifre);//scrivo il valore letto nella temperatura

richiamo la funzione per leggere le cifre da seriale e cerco di convertire il tutto in un intero da poter usare dopo
il problema è che il valore di quell'intero è sempre 0
ho provato ad inizializzare il valore di prc ad un valore diverso da 0 ma al passaggio in atoi mi ritorna 0.
cosa sbaglio??? :blush:
grazie a tutti

A prima vista direi che atoi non chiede quanti caratteri formano la stringa (anzi il vettore di caratteri)
Perciò la funzione ha un solo modo di sapere quando finiscono i caratteri, cercare il finestringa ovvero il carattere \0 (zero)

La tua leggoseriale prende il vettore cifre e lo ripassa indietro come una String. La macchina dovrà convertire da vettore di char a String (che è un oggetto, non un insieme di caratteri) il tutto senza mai un finestringa.

Prova ad aggiungere:

for (int i=0;i<3;i++){
  cifre[i]=Serial.read();
}
cifre[i]='\0';     // oppure semplicemente cifre[i]=0;

nulla continua ad essere 0! =(

scusate per completezza:
per provare sto usando simulator for arduino.

Ma sei sicuro che il siulatore simuli al 100% l'arduino?
Prima di dire che hai problemi prova per favore lo sketch su un Arduino.
Ciao Uwe

Almeno a me non sembra chiaro cosa stai facendo e come lo stai facendo.
Hai un qualcosa che funziona, presumo uno sketch Arduino che funziona.
Aggiungi l'invio tramite seriale, ma verso chi? Se spedisci i dati su seriale perchè il programma che hai postato legge da seriale?
Se vuoi leggerli da excel li spedisci verso un pc, presumo, perchè c'è la lettura nell'Arduino invece della scrittura?

uwefed:
Ma sei sicuro che il siulatore simuli al 100% l'arduino?
Prima di dire che hai problemi prova per favore lo sketch su un Arduino.
Ciao Uwe

Giusto, era solo per fare qualche esperimento prima dell'arrivo dei sensori che mi mancano.
Comunque hai ragione.

nid69ita:
Almeno a me non sembra chiaro cosa stai facendo e come lo stai facendo.
Hai un qualcosa che funziona, presumo uno sketch Arduino che funziona.
Aggiungi l'invio tramite seriale, ma verso chi? Se spedisci i dati su seriale perchè il programma che hai postato legge da seriale?
Se vuoi leggerli da excel li spedisci verso un pc, presumo, perchè c'è la lettura nell'Arduino invece della scrittura?

sto cercando di fare il contrario:
Ho uno sketch che imposta e controlla le temperature durante le fasi di cottura.
Adesso vorrei passare ad arduino le temperature e i tempi tramite excel.
Per ogni fase dovrò inserire la chiamata alla funzione che legge la seriale per leggere questi due valori e usarli all'interno dello sketch.
Spero di essere stato più chiaro :stuck_out_tongue:
Grazie

La logica mi dice, dopo quello che dichiari, che allora hai 2 programmi, uno in Arduino che riceve ma l'altro spedisce dati da Excel.

Prima di tutto bisogna stabilire che chi spedisce sia corretto. Siccome hai 2 soggetti, escludiamo che il problema sia chi spedisce.
Sei sicuro che il programma che spedisce invii i dati correttamente?

whteice:

...

void loop(){
 switch (ciclo){//eseguo il primo ciclo di riscaldamento e cottura
 case 1:
 leggoseriale();//richiamo la funzione per leggere la seriale
 prc= atoi(cifre);//scrivo il valore letto nella temperatura
...
String leggoseriale(){
 while (Serial.available()>0){
 for (int i=0;i<3;i++){
 cifre[i]=Serial.read();
 }
return cifre;
}
}

Di base ci sono alcune cose che fai che non hanno senso.

  1. ripeto che tu nel vettore cifre non metti mai un fine stringa '\0' e le funzioni base del C si aspettano di trovarlo se no non sanno dove termina la stringa.
  2. se inizializzi prc a che serve visto che prendi cifre e le sbatti dentro a prc?
  3. la funzione leggiseriale è un pò un casino.
    Ovvero, lavori con una variabile globale cifre che poi metti in return
    Ma allora dovresti fare
  String x=leggoseriale();//richiamo la funzione per leggere la seriale
  prc= atoi(x);//scrivo il valore letto nella temperatura

ovvero sfrutti il ritorno della String e perciò cifre dovrebbe essere una variabile privata della funzione
quindi:

  String x=leggoseriale();//richiamo la funzione per leggere la seriale
  prc= atoi(x);//scrivo il valore letto nella temperatura
...
String leggoseriale()
{ char cifre[3];   // metto qui cifre, variabile privata
  while (Serial.available()>0)
  { for (int i=0;i<3;i++)
    { cifre[i]=Serial.read();
    }
  }
  return cifre;
}

Sai che forse hai anche errato il numero di graffe della leggiseriale? la return deve essere fuori dal while
Metti le graffe come faccio io. Non sono un fastidio le graffe, evidenziale per fare meno errori. Lascia stare gli esempi in giro che la graffa quasi la "nascondono".

edit: per favore includere il codice usando gli appositi tag

Ho corretto l'errore del return nel while grazie.
Per il resto se faccio come mi hai detto tu durante la compilazione ricevo una serie di errori:

controllo_temperature2_0.ino: In function 'void loop()':
controllo_temperature2_0:43: error: cannot convert 'String' to 'const char*' for argument '1' to 'int atoi(const char*)'
controllo_temperature2_0:54: error: jump to case label
controllo_temperature2_0:42: error: crosses initialization of 'String x'
controllo_temperature2_0:64: error: jump to case label
controllo_temperature2_0:42: error: crosses initialization of 'String x'
controllo_temperature2_0:74: error: jump to case label
controllo_temperature2_0:42: error: crosses initialization of 'String x'
controllo_temperature2_0:83: error: jump to case label
controllo_temperature2_0:42: error: crosses initialization of 'String x'

Per la funzione e il ritorno non era una soluzione ma solo una spiegazione che se usi una funzione che ritorna qualcosa, allora dovresti usarlo, altrimenti lavori con variabili globali e fai a meno del return.
Immaginavo poi che la atoi() si aspetta di lavorare con vettori di caratteri e non con oggetti String. Perciò non userei l'oggetto String tanto per fare.

  leggoseriale(); //richiamo la funzione per leggere la seriale
  prc= atoi(cifre);   //scrivo il valore letto nella temperatura
...
void leggoseriale()  // non ritorno nulla, lavoro con cifre, variabile globale
{ while (Serial.available()>0)
  { for (int i=0;i<3;i++)
    { cifre[i]=Serial.read();
    }
  }
}

Prova poi ad aumentare di 1 la dimensione di cifre ma lascia il resto invariato.
Nella leggoseriale aggiungi solo:

void leggoseriale()  // non ritorno nulla, lavoro con cifre, variabile globale
{ while (Serial.available()>0)
  { for (int i=0;i<3;i++)
    { cifre[i]=Serial.read();
    }
  }
  cifre[i]='\0';
}

ho capito,
grazie per le spiegazioni mi sa che faccio ancora confusione con la visibilità delle variabili :~
faccio qualche prova e ti faccio sapere
grazie mille per la disponibilità

Attento!
non puoi scrivere commenti nel #define

#define ITP A1 //temperatura Mosto
#define ITM A2 //temperatura Piastra

devi spezzare le righe

//temperatura Mosto
#define ITP A1
//temperatura Piastra
#define ITM A2

--> #define - Arduino Reference

ah cavolo, grazie, non lo sapevo.

A parte l'errore, l'uso di costanti è da preferire. Le #define sono direttive per il compilatore, è uno spreco usarle per dichiarare delle costanti.

const byte ITP = A1; //temperatura Mosto
const byte ITM = A2; //temperatura Piastra

PaoloP:
Attento!
non puoi scrivere commenti nel #define

devi spezzare le righe

--> #define - Arduino Reference

Scusa Paolo, ma nel link riportato non mi sembra si dica che le #define non possano essere seguite da commenti ... nei "Tip" si indica solo che :

  1. La #define NON deve essere conclusa con il ";" come invece va normalmente fatto con le altre istruzioni
  2. La #define NON deve contenere il segno di "=" per l'assegnazione di un valore

... dove vedi che NON deve contenere commenti ??? Io li ho sempre usati senza alcun problema ... :wink:

Guglielmo

Ho ricontrollato la cosa e in effetti i commenti vengono eliminati prima di passare il codice al pre-processore.
Comunque in caso di bug il testo potrebbe essere accodato al define. Vedi ad esempio il bug dell'IDe quando, in alcuni casi si usa il /* */ su più righe.
Quindi diciamo che non è un obbligo ma una buona prassi. :grin:

Anch'io ero della convinzione che i commenti cozzassero in fase di compilazione. Tant'è che non più di un paio di giorni fa un utente aveva un problema simile e togliendo i commenti dal #define aveva risolto i suoi guai.

PaoloP:
Ho ricontrollato la cosa e in effetti i commenti vengono eliminati prima di passare il codice al pre-processore.
...

... che sarebbe il corretto comportamento secondo le specifiche C99 (http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1124.pdf) :wink:

Ad esempio, GNU C, seguendo dette specifiche, converte i commenti in uno spazio prima di processare il codice (The C Preprocessor: 1. The C Preprocessor al punto 1.1) ...

... in ogni caso buono a sapere che, con l'IDE di Arduino, questo potrebbe a volte creare problemi.

Grazie,

Guglielmo

Però c'è da dire anche che noi stiamo usando avr-gcc, non gcc. E non è detto che tutto quello che è supportato da gcc lo sia anche su avr-gcc e nello stesso modo.