Go Down

Topic: Topic permanente di programmazione newbie (Read 128288 times) previous topic - next topic

menniti


(spazio permettendo) si poteva anche convertire tutto in striga e usare gli appositi operatori
http://arduino.cc/en/Tutorial/StringCaseChanges

Non ho problemi di spazio :smiley-mr-green:; Comunque la funzione che mi risolve il problema di maiuscole/minuscole nella conversione a HEX è:
Code: [Select]
/************************ conversione di un carattere HEX in un numero *************************/
int hex2dec(byte c) {
  if (c >= '0' && c <= '9') {
    return c - '0';
  }
  // accetta indifferentemente maiuscole o minuscole
  else if (c >= 'A' && c <= 'F') {
    return c - 'A' + 10;
  }
  else if (c >= 'a' && c <= 'f') {
    return c - 'a' + 10;
  }
}

come vedi ho aggiunto il controllo delle minuscole. Invece ora ho il problema di dover ignorare tutti i valori che non rientrano nell'esadecimale.

brainbooster

spiega meglio cosa passa e cosa vuoi filtrare

menniti

In pratica devo restare in attesa di un carattere sulla seriale ma devo poter accettare solo i caratteri con valore decimale tra 48 e 57 (0-9), tra 65 e 70 (A-F) e tra 97 e 102 (a-f); se il carattere rientra in questi range allora esegue la riga successiva, caricando il valore nel buffer, altrimenti dovrebbe restare in attesa del carattere come se non fosse stato premuto alcun tasto.

brainbooster

#318
Apr 05, 2012, 08:32 pm Last Edit: Apr 05, 2012, 08:38 pm by BrainBooster Reason: 1
con if potresti fare esattamente quello che  hai detto :)
mettiamo che il carattere in entrata si chiami c
Code: [Select]

if (c>=48 ||c<=70 ||c>=65 ||c<=70 || c>=97 || c<=102){
c è un carattere valido
}
else
{
ignoralo
}

ho usato i valori decimali perchè li avevi già scritti :)

menniti

Perfetto, ma credo di dover mettere tutto in un while; la logica è:
aspetto un carattere
leggo il carattere e lo confronto con i codici
se è ok carico il carattere nel buffer
se non è ok aspetto un nuovo carattere

quindi ora il mio problema è come fargli rifare la lettura se il carattere è sbagliato, provo a "studiare" :D

brainbooster

perchè deve rileggere un carattere sbagliato?

menniti

#321
Apr 05, 2012, 08:55 pm Last Edit: Apr 05, 2012, 09:04 pm by Michele Menniti Reason: 1
Mi spiego meglio, io devo fornire al firmware due caratteri validi per programmare il fuse; allo stato attuale accetta qualsiasi schifezza e la riconverte a modo suo in un valore HEX; voglio fare in modo di poter scrivere solo valori HEX; se scrivo "X" lui deve ignorarlo ed aspettare un nuovo carattere che rientri tra quelli richiesti. Ho fatto così:
Code: [Select]
do {
   while (Serial.available() == 0);   // aspetta il primo carattere
   r = Serial.read();
 } while (r>=48 || r<=70 || r>=65 || r<=70 || r>=97 || r<=102);
 serbuffer[0] = Serial.read();      // lo imposta come HIGH byte del fuse


ma come faccio a trasformare il carattere letto nel suo valore ascii?
la riga  r = Serial.read(); dovrebbe essere qualcosa tipo  r = ASC(Serial.read());
c'è un comando di conversione?

EDIT: penso che così vada bene:
Code: [Select]
do {
    while (Serial.available() == 0);   // aspetta il primo carattere
    r = Serial.read();
  } while (r>=0 || r<=9 || r>='a' || r<='f' || r>='A' || r<='F');


ora a cena e poi provo



menniti

l'avevo visto ma sul mio manualetto non dice niente, ora ho visto che è proprio ciò che mi serve. Ma così mi funziona esattamente al rovescio, come faccio ad invertire la logica del while:
Code: [Select]
do {
    while (Serial.available() == 0);   // aspetta il primo carattere
    r = char(Serial.read());
  } while ((r>=48 && r<=57) || (r>=65 && r<=70) || (r>=97 && r<=102));
  serbuffer[0] = Serial.read();      // lo imposta come HIGH byte del fuse
 
  do {
    while (Serial.available() == 0);   // aspetta il primo carattere
    r = char(Serial.read());
  } while ((r>=48 && r<=57) || (r>=65 && r<=70) || (r>=97 && r<=102));
  serbuffer[1] = Serial.read();      // lo imposta come HIGH byte del fuse

leo72


ai miei tempi :smiley-red: mi pare che sommavo in basic 32 al minuscolo per ottenere il maiuscolo,

No si sommava 32 per passare da maiuscolo a minuscolo, oppure l'inverso cioè si sottraeva 32 per passare da minuscolo a maiuscolo. Questo perché A=65, a=97  ;)

Tornando al tuo problema, tu devi fare la conversione di un dato esadecimale in decimale. Se ad esempio ti arriva E2 devi convertirlo in 226, ma non puoi farlo come pensi tu. Cioè la conversione da esadecimale a decimale si fa con
(valore del 1° carattere*16)+valore del 2° carattere.
Quindi E*16+2 -> 14*16+2 -> 224+2 = 226

Io allora farei così

Code: [Select]
char carattere;
byte contatore=2;
byte risultato=0;
while (contatore) { //loop finché non sono arrivati 2 cifre
  if (Serial.available()) {
    carattere=Serial.read();
    if ((carattere>='0') && (carattere<='9')) { //cifra numerica
      contatore--;
      risultato+=(carattere*(contatore>0?16:1)); //sommo il valore esadecimale
     
    } else if ((carattere>='A') && (carattere<='F')) { //
      contatore--;
      risultato+=(carattere-55)*(contatore>0?16:1); //A=65 -> 65-55=10 ecc..
    } else if ((carattere>='a') && (carattere<='f')) {
      contatore--;
      risultato+=(carattere-87)*(contatore>0?16:1); //a=97 -> 97-87=10 ec...
    }
  }
}


In questo modo dovrebbe funzionare. Dovrebbe leggere 2 cifre, e continuare a leggere finché il carattere ricevuto non ricade nell'intervallo 0-9, oppure A-F oppure a-f. "contatore" serve per eseguire il ciclo solo 2 volte (2 cifre), viene anche usato per la conversione in questo modo: all'avvio vale 2, se si riceve un carattere valido, passa a 1, poi viene moltiplicato per 16 ed il risultato moltiplicato per il valore ricevuto. Vien da sé che l'operatore condizionale su contatore quando vale 1 dia 16 mentre quando vale 0 (caso della seconda cifra), dia come risultato 1.
Non so nemmeno se compila, l'ho scritta di getto

menniti

No, Leo, la mia situazione è molto più semplice, io non devo controllare la validità del valore esadecimale, semplicemente devo impedire di comporlo usando caratteri diversi da quelli previsti. Ciò che faccio è:
leggo il primo carattere
se non è 0-9, A-F, a-f rileggo il carattere
quando il carattere è corretto lo memorizzo
faccio lo stesso col secondo carattere alla fine ottengo due caratteri, p.es. F9 che passo alla procedura di scrittura del fuse. Quindi il code che ho postato prima funziona benissimo, ma al rovescio, cioè mi accetta SOLO i caratteri diversi da quelli che mi servono.
Come faccio ad invertire la logica del do-while?

leo72

Anche il mio codice fa questo, forse non l'ho spiegato bene.
Tornando al tuo, mi pare che non vada bene:

Code: [Select]

do {
    while (Serial.available() == 0);   // aspetta il primo carattere
    r = char(Serial.read());
} while ((r>=48 && r<=57) || (r>=65 && r<=70) || (r>=97 && r<=102));
serbuffer[0] = Serial.read();      // lo imposta come HIGH byte del fuse

Nel momento in cui esci dal ciclo do..while perdi il carattere che leggevi e memorizzi il secondo in arrivo. Questo perché la Serial.read preleva materialmente dal buffer seriale il carattere che leggi, perdendolo del tutto se non lo memorizzi. Ma tu l'hai memorizzato in "r", quindi metti quello direttamente in serbuffer[0] oppure usi Serial.peek() che ti dice qual è il prossimo carattere che viene prelevato dal buffer: in pratica lo leggi ma non lo togli dal buffer.

leo72

Prova così:
Code: [Select]
while (true) {
  r=Serial.read();
  if ((r>=48 && r<=57) || (r>=65 && r<=70) || (r>=97 && r<=102)) {
    break;
  }
}
serbuffer[0]=r;

menniti

Allora, della spiegazione del tuo codice non ho capito niente, e il mio stato psico-fisico attuale non mi aiuta :smiley-sad-blue:

chiari invece i suggerimenti peek e r, ma correggimi se sbaglio:
il mio codice resta in attesa di un carattere dalla seriale fintanto che il carattere ricevuto rientra in quelli scritti nel while, che è esattamente l'opposto di ciò che voglio ottenere.
Cioè lui legge il carattere, se è 0-9, A-F, a-f lo ignora e si rimette in lettura, mentre io devo proseguire quando il carattere letto è appunto uno di quelli che mi aspetto.

leo72

Non è che lo ignora, semplicemente esci dal ciclo do..while quando arriva un carattere giusto (corretto) poi però va a leggere un'altra volta dalla seriale (sbagliato): in questo modo memorizzi il carattere successivo. Hai provato col codice che ti ho messo nel 2° post?

Intanto vado a dormire, dopo 2 notti insonni causa influenza non ce la faccio più  :smiley-roll-blue:

Go Up