Convertire sub string in intero

ho una stringa così composta "12#1" cioè un numero intero compreso tra 0 e 23, un cancelletto, ed uno 0 o un 1.

devo seprare la stringa nelle due parti che chiamo, indirizzo e comando... faccio così;

 int posizione; byte indirizzo, azione;
              for( int i = 1; i <= indiceComando; i++)
                 {posizione = comando[i].indexOf("#");
                    indirizzo  = atoi (comando[i].substring(0, comando[i].indexOf("#")));
                    azione     = atoi (comando[i].substring(comando[i].indexOf("#")+1));
                    Serial.print("\n"); Serial.print("indirizzo:"); Serial.print(comando[i].substring(0, comando[i].indexOf("#")));Serial.print("   azione:");    Serial.print(comando[i].substring(comando[i].indexOf("#")+1));
                  }

ma atoi non funziona... mi da quest'errore in fase di compilazione:
DecoderDTMF6.cpp: In function 'void rilevaStringaDTMF()':
DecoderDTMF6:80: error: cannot convert 'String' to 'const char*' for argument '1' to 'int atoi(const char*)'
DecoderDTMF6:81: error: cannot convert 'String' to 'const char*' for argument '1' to 'int atoi(const char*)'

la separazione delle stringhe è giusta perchè se commento le due righe
// indirizzo = atoi (comando_.substring(0, comando*.indexOf("#")));_
// azione = atoi (comando_.substring(comando.indexOf("#")+1));
la stampa su seriale è perfetta, nel separare la componente indirizzo dalla componente azione.
suggerimenti????
devo necessariamente passare attraverso un'altra stringa prima di utilizzare il metodo atoi????
grazie
[quote author=Michele Menniti link=topic=114509.msg861642#msg861642 date=1342459601]
Ciao Paolo, se posso darti un suggerimento, sposta il Topic nella nuova sezione software, è la sua collocazione ideale, poi questo lo elimini.
[/quote]*

Grazie Michele... non mi ero neppure accorto di questa nuova sezione ...._

Qualcuno sa suggerirmi una soluzoine al mio problema senza dover trasformare l'oggetto String in Char * .. perchè mi si complica troppo il resto dello script ...

atoi si aspetta una stringa che é terminata con un zero, ma questo non mi sembra la causa dei mesaggi di errore.
Ciao Uwe

non so il perche' degli errori, pero' con la nuova funzione String (non quella che usa array) puoi farlo senza usare atoi

uwefed:
atoi si aspetta una stringa che é terminata con un zero, ma questo non mi sembra la causa dei mesaggi di errore.
Ciao Uwe

Invece sembra proprio essere questo il problema. Non può fare cast dal tipo stringa a const *char.

Il risultato di questo:

comando[i].substring(0, comando[i].indexOf("#"))

deve essere di tipo const *char e per uscire con quell'errore il risultato deve essere di tipo String.

Ciao.

MauroTec:
Invece sembra proprio essere questo il problema. Non può fare cast dal tipo stringa a const *char.

Il risultato di questo:

comando[i].substring(0, comando[i].indexOf("#"))

deve essere di tipo const *char e per uscire con quell'errore il risultato deve essere di tipo String.

Ciao.

mauro... grazie intanto... ma non è che ho capito bene cosa intendi......

ad atoi devo passare un const * char perchè non mi dia errore ???? .. intendi questo???

posso cambiare la parte precedente del codice in modo da mettere su:

  • char * indirizzo (composto da 1 o caratteri - compresi tra 0 e 24)
  • char comando (composto da un carattere 0 o 1)
    in modo da trasformare entrambe le stringhe in un numero ...
    è giusto????

Si, non è che mi sono dilungato molto a spiegare. Ci riprovo.

Io non conosco bene la libreria String di Arduino, so che è una classe è presumo che il metodo "substring" da come ritorno un'oggetto dello stesso tipo, cioè String, e i messagi di errore confermano quanto presumo.

Se sei costretto ad usare la classe String vai avanti con questa e cerca un metodo offerto da String per ritornare un puntatore a char (char *) che poi non è altro che un array di char dove l'ultimo elemento vale "\0", quindi puoi leggere ogni carattere da un puntatore a char e fermarti quando l'elemento letto vale "\0".

Oppure fai tutto con char* dall'inizio senza usare String, so che è comoda ma porta via tanti cicli di clock.

Anche questa potrebbe essere una idea risolutiva.

non so il perche' degli errori, pero' con la nuova funzione String (non quella che usa array) puoi farlo senza usare atoi

Ciao.

Grazie Mauro ..... ho quasi risolto... nel senso che cè ancora un malfunzionamento ma la conversione la fà.......

ho fatto così:

void estraiComandi(int i, String str )
   {
    String str_I, str_A;
    str_I = str.substring(0, str.indexOf("#")); char Chr_I[str_I.length()+1]; str_I.toCharArray(Chr_I, str_I.length()+1) ; indirizzo[i] = atoi(Chr_I);
    str_A = str.substring(str.indexOf("#")+1);  char Chr_A[str_A.length()+1]; str_A.toCharArray(Chr_A, str_A.length()+1) ;    azione[i] = atoi(Chr_A);
    //str_I = str.substring(0, str.indexOf("#")); Serial.print ("\n I: ");  Serial.print (str_I);
    //str_A = str.substring(str.indexOf("#")+1);  Serial.print ("   A: ");  Serial.print (str_I);
    }

ciao

Vedo, ma il codice è poco leggibile e allora lo riporto sotto con la formattazione più leggibile.

void estraiComandi( int i, String str )
{

    String str_I, str_A;

    str_I = str.substring(0, str.indexOf("#"));
    char Chr_I[str_I.length()+1]; 
    str_I.toCharArray(Chr_I, str_I.length()+1) ;
    indirizzo[i] = atoi(Chr_I);

    str_A = str.substring(str.indexOf("#")+1); 
    char Chr_A[str_A.length()+1];
    str_A.toCharArray(Chr_A, str_A.length()+1) ;
    azione[i] = atoi(Chr_A);

#if(0) // change zero to one to compile this code
    str_I = str.substring(0, str.indexOf("#")); 
    Serial.print ("\n I: ");  Serial.print (str_I);
    str_A = str.substring(str.indexOf("#")+1);  
    Serial.print ("   A: ");  Serial.print (str_I);
#endif

}

Io non so se sei costretto ad usare quella formattazione ma se usassi un frame fisso per la stringa risolveresti più facilmente. Cioè il comando è composto sempre da 2 caratteri, (es. 00, 01, 02 ecc).
Se non sei vincolato a quel formato ne possiamo parlare.

PS: per ogni riga sempre e solo una istruzione, cioè ogni riga deve avere solo un ;

Ciao.

MauroTec:
Vedo, ma il codice è poco leggibile e allora lo riporto sotto con la formattazione più leggibile.

void estraiComandi( int i, String str )

{

String str_I, str_A;

str_I = str.substring(0, str.indexOf("#"));
    char Chr_I[str_I.length()+1];
    str_I.toCharArray(Chr_I, str_I.length()+1) ;
    indirizzo[i] = atoi(Chr_I);

str_A = str.substring(str.indexOf("#")+1);
    char Chr_A[str_A.length()+1];
    str_A.toCharArray(Chr_A, str_A.length()+1) ;
    azione[i] = atoi(Chr_A);

#if(0) // change zero to one to compile this code
    str_I = str.substring(0, str.indexOf("#"));
    Serial.print ("\n I: ");  Serial.print (str_I);
    str_A = str.substring(str.indexOf("#")+1); 
    Serial.print ("  A: ");  Serial.print (str_I);
#endif

}




Io non so se sei costretto ad usare quella formattazione ma se usassi un frame fisso per la stringa risolveresti più facilmente. Cioè il comando è composto sempre da 2 caratteri, (es. 00, 01, 02 ecc).
Se non sei vincolato a quel formato ne possiamo parlare.

PS: per ogni riga sempre e solo una istruzione, cioè ogni riga deve avere solo un ;

Ciao.

Ciao... Mauro ..
1)
io lo trovo più leggibile nella prima forma .. cioè una volta verificato che un blocco di codice funziona.. preferisco accorparlo.
cioè cerco di raggruppare le singole sub.istruzioni fino al risultato finale , e magari incolonnarlo con un altro blocco simile.. cosi posso verificare con un solo colpo d'occhio che sia tutto ok....
inoltre nella stessa videata riesco a tenere più codice e quindi a tenere sotto occhio parti di codice più ampio.
Ma (credo) sia solo questione di abitudine personale......

il pattern l'ho stabilito io...
la stringa originaria che ricevo, tramite toni DTMF, è di questo tipo
yyyyyxx#0|1xx#0|1 ...... xx#0|1*
dove
yyyyy sono la password per abilitare l'esecuzione dei comandi..
*xx#0|1 questo è il generico comando, composto da un indirizzo xx, ed un'azione 0 o 1. lo uso per "accendere o spegnere" il bit in posizione xx ... con uno shift register praticamente accendo o spengo dei bit (e conseguentemente dei led, che poi userò per controllare dei relè) .. così ottengo il generico comando acceso spento, su una serie di indirizzi ....
** i due asterischi finali segnano la fine della stringa di comando ....

ma mi sembra che, per chi invia il comando, digitare nella tastiera del telefono:
1#1 --- > azione 1 (acceso) sul bit indirizzo 1;...
1#0 --- > azione 0 (spento) sul bit indirizzo 1;
oppure, più precisamente ...
A1B2C3
1#1
14#112#111#0** --- > per inviare contemporanemente 4 comandi, cioè accendere 1, 14, 12 e spegnere 11...(NB i primi 6 caratteri sono la password) ...
il sistema mi pare molto flessibile, perchè dal codice stabilisco la password come deve essere composta, quindi quanti caratteri massimi possono essere inviati, altrimenti mando la stringa all'interpretazione come se fosse terminata con i due asterischi, ed anche quanti comandi possono essere inviati ed interpretati...

ogni suggerimento è, naturalmente, non solo ben accetto ma, anzi, auspicato ....

comunque appena avrò messo su la forma funzionante del tutto metterò tutto qui ...
grazie ciao

io lo trovo più leggibile nella prima forma .. cioè una volta verificato che un blocco di codice funziona.. preferisco accorparlo.
cioè cerco di raggruppare le singole sub.istruzioni fino al risultato finale , e magari incolonnarlo con un altro blocco simile.. cosi posso verificare con un solo colpo d'occhio che sia tutto ok....
inoltre nella stessa videata riesco a tenere più codice e quindi a tenere sotto occhio parti di codice più ampio.
Ma (credo) sia solo questione di abitudine personale......

Capisco le tue motivazioni, ma purtroppo il codice sorgente non lo leggi solo tu. Come dici tu si tratta solo di abitudine e aggiungo cattiva abitudine, dico questo perchè non ho inventato io quella formattazione io mi sono solo adeguato a quello che scrivono i libri e al codice sorgente in circolazione, come il codice della libreria core ed estesa che usa quella formattazione. Solitamente quando un blocco di codice è pronto ci si chiede se è il caso di spostarlo all'interno di una funzione.

Ok ora andiamo al protocollo.

ogni suggerimento è, naturalmente, non solo ben accetto ma, anzi, auspicato ....

Certo la visione globale del problema la puoi avere solo tu, quindi alla fine sei tu che scegli il codice in base alle funzionalità.

Il frame fisso o pattern fisso ti evita anche di usare caratteri sentinella che prendono anche loro tempo e spazio, ma è meno flessibile in quanto il numero di comandi da inviare è prestabilito prima. Se in base al problema ti sembra la via migliore seguila.

L'uso della classe String consumo di risorse e se fosse possibile farne a meno sarebbe meglio, se ti ritrovi alle strette con la ram poi in caso si vede di usare un buffer di char per salvare il frame e poi effettuare il parser. Gli array sono velocissimi da scanzionare e non c'è la necessità di effettuare chiamate a metodi o funzioni per parsare il contenuto.

Ok appena sei pronto posta pure, poi magari si riesci a combattere con il playground puoi mettere tutto li.

Ciao.

#include <stdlib.h>

...

char* p,*i;
char str[] = "16#1";
int primo, secondo;

if ( p = strtok_r(str, "#",&i) ) { primo= atoi(p); }
if ( p = strtok_r(NULL, "#",&i) ) { secondo = atoi(p); }

Caro Paolo,

credo che il tuo problema sia facilmente risolvibile: è sufficiente usare una funzione esistente ma inspiegabilemente non documentata della classe String sin dall'IDE 0023 (ho segnalato la cosa a Banzi, per la cronaca, prorio ieri notte).

La funzione è .toInt().

String X = "123#4567";
byte I = X.indexOf("#");
int Indirizzo = X.substring(0, I).toInt(); 
int Comando = X.substring(I + 1).toInt();

da notare il risparmio di codice utilizzando il subclassing.

Ettore Massimo Albani

La soluzione in caso di stringa con più campi non è molto breve in termine di codice, oltre ai noti problemi di spazio della libreria string.
La funzione strtok_r ( strtok) può essere invece ricorsivamente applicata ad un stringa che ha un numero indefinito di campi divisi da caratteri specifici.
Comunque capisco che è anche una questione di gusti ....

e' anche una questione di competenze, per me che non nasco programmatore, la tua soluzione con strtok non la caspisco al volo, quella con String si.
Se non ci sono problemi di ram ben venga String e la sua semplicita'

complimenti ad entrambi, si nota subito la Vs preparazione :slight_smile:

Ciao a tutti, anche io sto provando substring e toInt con una stringa scritta nel server del tipo HTTP://192.168.1.100/12#1 ma non mi funziona, dove sbaglio?
Grazie in anticipo.

#include <Shifter.h>
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x3A, 0x06 };
byte ip[] = { 192,168,1,100 };
EthernetServer server(80);
String query;
//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 6;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 7;

#define NUM_REGISTERS 2

Shifter shifter(dataPin, latchPin, clockPin, NUM_REGISTERS);

void setup()
{
query = String("");
Ethernet.begin(mac, ip);
server.begin();
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop()
{

EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
query.concat(c);
if (c == '\n') {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();

String X = "";
byte I = X.indexOf("#");
int Indirizzo = X.substring(0, I).toInt();
int Comando = X.substring(I + 1).toInt();

if (query.indexOf('X') > 0) {
shifter.setPin(Indirizzo, Comando);
shifter.write();
delay(1000);
shifter.clear();
shifter.write();
}

client.print("

");//DEBUG
client.print(query);// DEBUG
client.print("
");//DEBUG
break;//fermo il ciclo
}
}
}
delay(1);
client.stop();
query = String("");
}
}

Ho provato a ragionarci di più e questo è il mio sketch ma NON mi funziona ugualmente. Come dicevo prima avrei intenzione di dare un comando tipo
Http://192.168.1.100/11#1
dove
11 è l'indirizzo (da 00 a ipotetico 99)
1 è il comando (0 spento e 1 acceso)

Qualcuno sa dove sto sbagliando?

#include <Shifter.h>
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x3A, 0x06 };
byte ip[] = { 192,168,1,100 };
EthernetServer server(80);
String query;
//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 6;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 7;

#define NUM_REGISTERS 2

Shifter shifter(dataPin, latchPin, clockPin, NUM_REGISTERS);

void setup()
{
query = String("");
Ethernet.begin(mac, ip);
server.begin();
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop()
{

EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
query.concat(c);
if (c == '\n') {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();

byte I = query.indexOf("#");
int Indirizzo = query.substring(I - 2).toInt();
int Comando = query.substring(I + 1).toInt();

if (query.indexOf("#") > 0) {
shifter.setPin(Indirizzo, Comando);
shifter.write();
delay(3000);
shifter.clear();
shifter.write();
}

client.print("

");//DEBUG
client.print(query);// DEBUG
client.print("
");//DEBUG
break;//fermo il ciclo
}
}
}
delay(1);
client.stop();
query = String("");
}
}

Però sei testina ehh ... ti avevo postato qui lo sketch che ti serviva http://arduino.cc/forum/index.php/topic,102505.15.html, ma evidentemente non hai guardato.

Esempio

porte da 10 a 99
http://192.168.2.177/110 >> on porta 10
http://192.168.2.177/010 >> off porta 10
...
http://192.168.2.177/199 >> on porta 99
http://192.168.2.177/099 >> off porta 99

porte da 0 a 9
http://192.168.2.177/100 >> on porta 0
http://192.168.2.177/000 >> off porta 0
...
http://192.168.2.177/109 >> on porta 9
http://192.168.2.177/009 >> off porta 9

Non ho lo shifter quindi dovrai sostituire i digitalWrite(port,0); con le tue righe, l'ip e company, ma il principio è lo stesso

shifter.setPin(Indirizzo, Comando);
shifter.write();
delay(3000);
shifter.clear();
shifter.write();

#include <SPI.h>
#include <Ethernet.h>
 
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 2, 177 };
EthernetServer server(80);
String query;
byte out_1 = 40;
byte out_2 = 41;
byte out_3 = 42;
byte out_4 = 43;
 
void setup(){ 
  Ethernet.begin(mac, ip);
  pinMode(out_1, OUTPUT); 
  pinMode(out_2, OUTPUT); 
  pinMode(out_3, OUTPUT); 
  pinMode(out_4, OUTPUT); 
}
 
void loop()
{ 
 EthernetClient  client = server.available();
 
  if (client) 
  {
    boolean currentLineIsBlank = true;
   
    while (client.connected()) 
    {
      if (client.available()) 
      { 
        char c = client.read();
        query.concat(c);   
        if (c == '\n' && currentLineIsBlank) 
        {
                String Digi_port = query.substring(6,8) + "0";
                char thisChar[Digi_port.length()];
                Digi_port.toCharArray(thisChar, Digi_port.length());
                int port = atoi(thisChar);                                
                String on_off = query.substring(5,6);
                                                       
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println();
        client.print("<html><head><title>ARDUINO WEB</title></head><body>");
                
        if (on_off != "0" && on_off != "1")
        {
          client.println("ERRORE IMMISSIONE DATO !! 
");// DEBUG 
        }
        else
        {
          client.println("Stringa inviata ad Arduino >> " + query +  "
");// DEBUG
          client.println("Stringa ricevuta da Arduino parse  >> " + (String)port +  "
");// DEBUG
          client.println("Comando da eseguire sulla porta " + (String)port + " >> "+ on_off +  "
");// DEBUG
            if(on_off == "0") digitalWrite(port,0); 
            if(on_off == "1") digitalWrite(port,1);
        }
        
        client.println("</body></html>");

        query="";
        
        delay(1);
        client.flush();
        client.stop(); 
        }
     } 
   }
  }
}

L'ho fatto sul mio quindi deve andare anche sul tuo, fammi sapere ciao

Ciao Pablos, grazie delle info...stasera guarderò...comunque non vedo più il tuo post dall'altra parte...
Cmq grazie ancora poi ci guardo e studio bene :slight_smile:
Ciao

visto che qualcuno giustamente fa notare l'uso del toInt() l'ho applicato modificando il precedente programma con lo stesso risultato

#include <SPI.h>
#include <Ethernet.h>
 
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 2, 177 };
EthernetServer server(80);
String query;
byte out_1 = 40;
byte out_2 = 41;
byte out_3 = 42;
byte out_4 = 43;
 
void setup(){ 
  Ethernet.begin(mac, ip);
  pinMode(out_1, OUTPUT); 
  pinMode(out_2, OUTPUT); 
  pinMode(out_3, OUTPUT); 
  pinMode(out_4, OUTPUT); 
}
 
void loop(){ 
 EthernetClient  client = server.available();
 
  if (client) {
    boolean currentLineIsBlank = true;
   
    while (client.connected()) 
    {
      if (client.available()) 
      { 
        char c = client.read();
        query.concat(c);   
        if (c == '\n' && currentLineIsBlank) 
        {                             
        digitalWrite(byte(query.substring(6,8).toInt()), byte(query.substring(5,6).toInt()));  
          
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println();
        client.print("<html><head><title>ARDUINO WEB</title></head><body>"); 
        client.println("Stringa inviata ad Arduino >> " + query +  "
");// DEBUG        
        client.println("</body></html>");

        query="";
        
        delay(1);
        client.flush();
        client.stop(); 
        }
     } 
   }
  }
}