Go Down

Topic: problema atoi() (Read 9825 times) previous topic - next topic

whteice

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
Code: [Select]
//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:
Code: [Select]
  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???  :smiley-red:
grazie a tutti

nid69ita

#1
Mar 23, 2013, 05:20 pm Last Edit: Mar 23, 2013, 05:22 pm by nid69ita Reason: 1
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:
Code: [Select]

for (int i=0;i<3;i++){
 cifre[i]=Serial.read();
}
cifre[i]='\0';     // oppure semplicemente cifre[i]=0;
my name is IGOR, not AIGOR

whteice

nulla continua ad essere 0!  =(

whteice

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

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

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?

my name is IGOR, not AIGOR

whteice


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.


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  :P
Grazie

nid69ita

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?
my name is IGOR, not AIGOR

nid69ita

#8
Mar 24, 2013, 02:22 pm Last Edit: Mar 24, 2013, 04:18 pm by leo72 Reason: 1

Code: [Select]

...
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
Code: [Select]
 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:
Code: [Select]
 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
my name is IGOR, not AIGOR

whteice

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'

nid69ita

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.

Code: [Select]

  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:
Code: [Select]

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';
}

my name is IGOR, not AIGOR

whteice

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à

PaoloP

Attento!
non puoi scrivere commenti nel #define
Code: [Select]
#define ITP A1 //temperatura Mosto
#define ITM A2 //temperatura Piastra


devi spezzare le righe
Code: [Select]
//temperatura Mosto
#define ITP A1
//temperatura Piastra
#define ITM A2


--> http://arduino.cc/en/Reference/Define

whteice

ah cavolo, grazie, non lo sapevo.

leo72

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

Code: [Select]
const byte ITP = A1; //temperatura Mosto
const byte ITM = A2; //temperatura Piastra

Go Up