[risolto]Conversione hex a dec

Salve ragazzi, ho fatto le mie ricerche nel forum ed ho adattano ciò che mi serviva. Devo fare la conversione da hex a decimale. Non so dove sbaglio, ho fatto varie prove con numeri sballati , potreste darci uno sguardo ?

int id_dec = 0;
   int val = 0;
   String id_string= incString.substring(0,index); 
   
   for(int i=0; i<3; i++){
      if(id_string[i] == "A"){
         val = 10;
      }else if (id_string[2-i] == "B"){
         val = 11;
        } else if (id_string[i] == "C"){
          val = 12;
          }else if (id_string[i] == "D"){
           val = 13;
           }else if (id_string[i] == "E"){
            val = 14;
            }else if (id_string[i] == "F"){
             val = 15;
             } else {
                 val = id_string[i];
                 
                }
     id_dec = (int)val * pow(16,i)+ id_dec; 
    
    }

Il numero in esadecimale è di tre lunghezze per esempio 19B

Per me il problema é la else finale. Il valore del carattere che indica una cifra non é uguale alla cifra che indica, ma sono comunque in sequenza crescente (se '0'=50 allora '1'=51, '9'=59). Quindi, sperando che contenga solo cifre o lettere, modificherei l'assegnamento in

 val=in_string[i] -'0'

Poi modificherei il tutto usando solo due if al posto di tutte quelle if else, ma é un'altra storia

Non capisco perché il confronto con l'if è sempre falso. Per esempio se ho 19B quando verifico che B == "B" è falso.

Scusa, ma è tutto sbagliato.
Provo a spiegarti, per non darti la "pappa pronta" e portarti a capire da solo:

   if (id_string[i] == "A") {

Qui confronti un carattere con una stringa. In C non puoi farlo.
Devi quantomeno modificarlo per confrontare il carattere con un carattere quindi non "A" ma 'A'.

} else if (id_string[2 - i] == "B") {

Che è questo "2 - i"?? Lascia solo "i" come tutti gli altri simboli.

val = id_string[i];

Qui, come ti ha scritto anche Silente, stai prendendo il valore ASCII del carattere, non il suo valore. Devi fare la modifica che ti ha consigliato.

id_dec = (int)val * pow(16, i) + id_dec;

Anche questo è sbagliato. Il primo carattere della stringa (con i=0 per intenderci) è quello più significativo quindi va moltiplicato per 16^2 non per 16^i che significa 16^0! Devi mettere qui il "2 - i"...
Inoltre il cast "(int)" è superfluo in quel punto, "val" p già intero.

Una cosa che invece non è colpa tua è la "pow()", che restituisce un float e quindi devi fare qui il cast a "(int)", ma purtroppo è nota per dare problemi di decimali su Arduino, infatti "pow(16,2)" non dà 256 come atteso, ma dato che di fatto restituisce 255.99990844 troncando all'intero avresti 255!
Bisogna aggiungere un decimale per avere il valore intero corretto, esempio:

val * (int)(0.1+pow(16, 2-i))

Tutto questo si può anche fare in un modo molto più rapido ed elegante, ma inanto modifica il tuo programma in base a quello che ti ho indicato, e quando funziona fammi sapere se vuoi la soluzione più rapida e breve, e te la posto :wink:

grazie ai vostri suggerimenti tutto funziona. Qual'è la soluzione più rapida ? :slight_smile: Avevo letto che esiste una funzione strtol ma che non avevo capito molto bene come funzionasse

Al posto di quel pesante pow non si può mettere un if/else o switch/case che moltiplichi per 1, 16, 256, ottenendo un bellissimo int?
Altrimenti un for che moltiplichi per n volte, da 0 a 2, per 16, ottenendo ancora una moltiplicazione per 1, 16, 256.

Potrei dire una caxxata, ma io normalmente per passare da decimale a binario faccio così

int valore=0;
char stringa[dim];
//stringa contiene solo caratteri corrispondenti a cifre
for (byte i=0;i<dim;i++)
valore=valore*10+(stringa[i]-'0');

Dove stringa -'0' é il valore della nuova cifra, non potrei fare qualcosa di simile in base 16?(dopo aver opportunamente calcolato il valore della cifra, ovviamente)

Per quanto riguarda il valore della cifra tutti quelli if non servono. Come i numeri anche le lettere sono in sequenza, quindi come se il carattere é compreso tra '0' e '9' tu ottieni direttamente il valore facendo carattere-'0'... Se il carattere é compreso tra 'A' e 'F' la cifra é solo 10+carattere- 'A'

Silente:
Potrei dire una caxxata, ma io normalmente per passare da decimale a binario faccio così

int valore=0;

char stringa[dim];
//stringa contiene solo caratteri corrispondenti a cifre
for (byte i=0;i<dim;i++)
valore=valore*10+(stringa[i]-'0');



Dove stringa -'0' é il valore della nuova cifra, non potrei fare qualcosa di simile in base 16?(dopo aver opportunamente calcolato il valore della cifra, ovviamente)

Per quanto riguarda il valore della cifra tutti quelli if non servono. Come i numeri anche le lettere sono in sequenza, quindi come se il carattere é compreso tra '0' e '9' tu ottieni direttamente il valore facendo carattere-'0'... Se il carattere é compreso tra 'A' e 'F' la cifra é solo 10+carattere- 'A'

ci proverò

Magari usando le librerie del C si risolve con una istruzione: strtol
long valore=strtol(stringa,NULL,16);

Ovviamente stringa non è una variabile String ma devi avere una stringa classica del C
Converti String in un array di char con Stringa.toCharArray()

char cstr[20]; 
String id_string=incString.substring(0,index); 
id_string.toCharArray(cstr,20);
long valore=strtol(cstr,NULL,16);

Forse poi si può evitare una ulteriore String per avere solo un pezzo del testo:

char cstr[20]; 
id_string.toCharArray(cstr,20);  // la prendo tutta
cstr[index]='\0';                // taglio stringa a posizione index
long valore=strtol(cstr,NULL,16);

centurione_agrippa:
ci proverò

Tutto quello che hai riportato prima lo avevamo già letto! Nell'email di notifica ho faticato per trovare che cosa avevi aggiunto! :frowning:

centurione_agrippa:
grazie ai vostri suggerimenti tutto funziona. Qual'è la soluzione più rapida ? :slight_smile: Avevo letto che esiste una funzione strtol ma che non avevo capito molto bene come funzionasse

Si, allora, sempre per farti capire meglio, intanto butta via le variabili String perché sono sicura fonte di instabilità: devi farlo sempre, sono altamente sconsigliate su Arduino, devi usare le "stringhe C".

Quindi una prima soluzione simile alla tua ma senza "String" e più "compatta" e generica (funziona anche con stringhe di lunghezza diversa da 3) è questa:

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

  char str[] = "19B";
  Serial.println(hex2int(str));
}

void loop() {

}

int hex2int(char* str)
{
  int val = 0; // Valore totale
  int ex = 1;  // Moltiplicatore per la cifra hex
  // Nel for parto dalla cifra meno signfiicativa
  for (int i = strlen(str)-1; i >=0 ; i--) {
    int delta = '0';
    if ( str[i] >= 'A' ) // Se è una lettera parto da 10
      delta = 'A' - 10;
    val += (str[i] - delta) * ex;
    ex *= 16; // Aggiorno il moltiplicatore
  }
  return val;
}

Ma quella più pratica e rapida è questa, e proprio con la strtol(): :slight_smile:

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

  char str[] = "19B";

  Serial.println(strtol(str,0,16));
}

void loop() {

}

Il primo parametro è la stringa di input, il secondo è un eventuale puntatore (puoi ottenere il puntatore all'ultimo carattere convertito, se non ti interessa metti zero) e l'ultimo la base numerica di conversione (16 = esadecimale).

docdoc:
Si, allora, sempre per farti capire meglio, intanto butta via le variabili String perché sono sicura fonte di instabilità: devi farlo sempre, sono altamente sconsigliate su Arduino, devi usare le "stringhe C"........

Una volta completato il tutto cerco di ottimizzarlo

Caro centurione, anche tutto questo l'abbiamo già letto!!! Perché ripeti sempre tutto il messaggio precedente??? Non serve, ingombra, da fastidio soprattutto leggendo dal telefonino ed è ancora più fastidioso nelle notifiche via email!

Spero di essere stato chiaro, questa volta.

>centurione_agrippa: 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 :wink:

Guglielmo

P.S.: Ho troncato io il lunghissimo QUOTE del tuo post #11