Corversione da char a float

Buongiorno a tutti,
mi chiamo Gianni ed chiedo gentilmente il vostro aiuto per risolvere il problema che vi vado a descrivere.
Purtroppo sono inesperto di programmazione ma mi sto trovando comunque a combattere con arduino.

Sto provando a realizzare un sistema di controllo che mi permetta di regolare un motore elettrico sulla base (in funzione) dei valori di peso che ricevo da una bilancia digitale, tramite connessione seriale RS232.

Per acquisire i dati dalla RS232 utilizzo il seguente sketch:

#include <SoftwareSerial.h>

#define SOFTRX 10
#define SOFTTX 11

SoftwareSerial softSerial(SOFTRX, SOFTTX);
void setup() {

Serial.begin(9600);

softSerial.begin(9600);

}

void loop() {
  byte n = softSerial.available();
  if (n!=0) {
    char data = softSerial.read();
    Serial.print(data);
  }
}

Il problema è che i dati che acquisico sono in formato char e quindi non riesco a trattarli come dei valori numerici.
Nello specifico ricevo, in maniera continua, delle righe di dati simili alla seguente:

ST, GS 15.352 g

  • ST e GS non so che cosa siano
  • 15.352 g è la pesata.

In questo caso, visto che la massa pesata è di 15,352 g, avrei bisogno di acquisire un float pari a 15,352.

Come posso fare?
SUl forum ho trovato tante/troppe soluzioni che, forse in consierazione della mia inesperienza, non mi sono risultate utili
Faccio presente inoltre che qualora la pesata rientrasse nelle unità, non mi dovrei acquisire 6 caratteri, ma 5 (es. 1.234 sono cinque caratteri, mentre 15,352 sono sei caratteri).

Mi sono veramente arenato...

Grazie a tutti coloro che vorranno darmi una mano!

Mi permetto di copiare quanto scrive solitamente la moderazione

Non me ne vogliate

Buongiorno,

essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il succitato REGOLAMENTO ... Grazie.

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nel rispetto del suddetto regolamento nessuno ti risponderà (eventuali risposte verrebbero temporaneamente nascoste), quindi ti consiglio di farla al più presto. :wink:

Di mio mi permetto solo di aggiungere che fatta la presentazione sarà un piacere aiutarti

Grazie molte,
ti chiedo scusa per aver saltato la mia presentazione.
Ho appena provveduto a farla

Al momento non collezioni i dati acquisita da seriale ma ti limiti a stampare un byte dopo l'altro. Quindi c'è un problema nel modo di collezionare i dati che arriva e salvarli (accumularli) in una variabile. Dopo che i dati acquisiti si trovano nella variabile, si usa una funzione dtostrf() che trasforma la variabile in un altra variabile di tipo float (virgola mobile).

Ora se mi apporti una modifica al tuo codice possiamo vedere anche i caratteri non rappresentabili inviati dalla tua bilancia.
Solitamente si tratti di caratteri (codici) terminatori.

Serial.print(data);

La modifichi così:

Serial.print((uint8_t)data, HEX);
Serial.print(" ");

Copia ciò che appare nel serial monitor e incollalo nel prossimo post.

Ciao.

Ciao e grazie per il tuo aiuto.

Ho modificato il mio sketch secondo quanto mi hai indicato:

#include <SoftwareSerial.h>

#define SOFTRX 10
#define SOFTTX 11

SoftwareSerial softSerial(SOFTRX, SOFTTX);
void setup() {

Serial.begin(9600);

softSerial.begin(9600);

}

void loop() {
  byte n = softSerial.available();
  if (n!=0) {
    char data = softSerial.read();
    Serial.print((uint8_t)data,HEX);
    Serial.print(" ");
  }
delay(2000);

}

(ho aggiunto anche un delay di 2 secondi, altrimenti avei acquisisco troppi dati)

Adesso sul serial monitor appare una sequenza di numeri a due cifre:

52 53 52 53 47 ecc...

Sinceramente non so a cosa corrispondano questi numeri.
Forse sono le ultime 2 cifre del peso (che corrisponde a 15,352 g) e variano nel tempo in quanto la bilancia in uso è molto sensibile.

Comunque riesco ad "accumulare" i dati ricevuti?

Ti ringrazio veramente molto!

Non ci siamo capiti, mi servono tutti i byte non i ...

Troppa premura, non stai accumulando nulla, per andare avanti servono quei dati che ti spuntano nel serial monitor.

Ciao.

domani, se riesco a mettere da parte un po' di tempo, comincio una "monografia" su come riconoscere valori da stream

e se no, amen

Per Maurotec:

di seguito la copia di quanto stampato sul serial monitor (dopo un certo tempo):

B2 A2 2 3A 81 D A 53 54 2C 47 53 20 20 31 35 2E 33 36 34 20 67 20 D A 53 54 2C 47 53 20 20 31 35 2E 33 36 32 20 67 20 D A 53 54 2C 47 53 20 20 31 35 2E 33 36 32 20 67 20 D A 53 54 53 2E 53 55 55 53 20 55 55 20 47 53 53 53 53 38 55 53 53 53 2C 20 53 55 55 53 53 20 55 55 53 55 55 53 20 20 55 55 53 53 55 53 53 55 D 55 35 20 53 47 53 53 53 67 53 31 53 D 53 53 55 55 A 55 20 55 A 55 2C 47 53 53 D 55 55 53 53 53 53 20 55 31 D 53 53 53 67 53 53 53 53 53 55 55 53 20 53 53 20 53 2E 55 33 A 33 53 53 53

Attendo le tue considerazioni a tal proposito, sinceramente non riesco proprio ad interpretare la sequenza.

Per Standardoil:
grazie!

RINGRAZIO TUTTI PER IL SUPPORTO CHE MI STATE DANDO!

Sono i valori dei byte trasmessi dalla bilancia rappresentati in esadecimale. I valori sono i codici dei caratteri ASCII. Se ristampiamo i caratteri:

a = """53 54 2C 47 53 20 20 31 35 2E 33 36 34 20 67 20 D A
       53 54 2C 47 53 20 20 31 35 2E 33 36 32 20 67 20 D A
       53 54 2C 47 53 20 20 31 35 2E 33 36 32 20 67 20 D A
       53 54 53 2E 53 55 55 53 20 55 55 20 47 53 53 53 53 38
       55 53 53 53 2C 20 53 55 55 53 53 20 55 55 53 55 55 53
       20 20 55 55 53 53 55 53 53 55 D 55 35 20 53 47 53 53
       53 67 53 31 53 D 53 53 55 55 A 55 20 55 A 55 2C 47 53
       53 D 55 55 53 53 53 53 20 55 31 D 53 53 53 67 53 53 53
       53 53 55 55 53 20 53 53 20 53 2E 55 33 A 33 53 53 53"""

for b in a.strip().split():
    print(chr(int(b, 16)), end="")

Otteniamo:

ST,GS  15.364 g 
ST,GS  15.362 g 
ST,GS  15.362 g 
SSUUGSSSgS1SGSSSS8USSS, SUUSS UUSUUS  UUSSUSSU
U U
SSSgSSSSSUUS SS S.U3
3SSS

La cosa strana sono i terminatori di stringa "parziali" A e D isolati:

Ma a quanto pare a noi interessano solo i frammenti che iniziano con ST,GS e finiscono con il terminatore CR LF (\r \n), cioè i byte di valore 13 10, o, in esadecimale, D A.

53 54 2C 47 53 20  20  31 35 2E 33 36 34 20   67  20   D    A
S  T  ,  G  S  sp  sp  1  5  .  3  6  4  sp   g   sp   \r   \n   

sp = space
\r = return carriage
\n = new line
0x67 = g unità di misura
https://www.ascii-code.com/

Neanche dopo l'analisi di @Claudio_FF?

@Claudio_FF
Questi:

SSUUGSSSgS1SGSSSS8USSS, SUUSS UUSUUS  UUSSUSSU
U U
SSSgSSSSSUUS SS S.U3

non ho idea di cosa siano, c'è da vedere se da sempre 3 letture e poi sbarella.

Ciao.

O la bilancia invia altri tipi di informazioni codificate, o la lettura tramite software serial perde colpi :slightly_smiling_face:

Il delay dopo ogni carattere

Provoca ritardi inaccettabili, riempie il buffer e a buffer pieno perdiamo gli arrivi

Questo lo dirà il manuale della bilancia

[Modo chiarimento ON]
Significa che lo deve dire Gianni82
[Modo chiarimento OFF]

Vero, mi è sfuggito che il delay è dopo OGNI byte ricevuto. Altra informazione utile sarebbe sapere quante pesate al minuto o secondo vengono trasmesse.

Sono 18 byte, al 16° ci mettiamo '\0' e lo diamo in pasto a dtostrf.
Contando i due spazi precedenti 15.364 incluso il punto:

Quando incontra come byte 0x53 inizia a collezionare 18 byte e l'ultimo deve essere '\n'

dtostrf(wf, 8, 3, cBuff); // sbagliato
Giusto come dice @ilguargua, ascii to float abbrv. atof.
in wf avri il peso in virgola mobile e lo potrai stampare con lcd.print o Serial.print ecc farci quello che vuoi.
Scusate nel pomeriggio sistemo.

Ciao.

Mi sfugge qualcosa o dtostrf() fa alla rovescia di quello che serve? Non andrebbe invece usato atof()?

Ciao, Ale.

No non ti sfugge nulla, ho rettificato alla meno peggio.
Ciao. :grinning:

Buongiorno a tutti!

  1. dal manuale della bilancia (che allego) non risulta la trasmissione di altri tipi di dato.
    HLD_1.013_21.07_EN_DE_FR_IT_ES_U.pdf (1.9 MB)

  2. la seriale (sia lato arduino, sia lato bilancia) è impostata a 9600 Bd.

  3. al fine di evitare gli altri problemi che avete descritto, ho eliminato il delay ed ho ottenuto la sequenza di byte che riporto di seguito:
    33 37 36 20 67 20 53 54 2C 47 53 20 20 31 35 2E 33 37 36 20 53 54 2C 47 53 20 20 31 35 2E 33 37 36 20 67 20 D 53 54 2C 47 53 20 20 31 35 2E 33 37 67 A 53 54 2C 47 53 20 20 31 35 2E 33 36 20 53 54 2C 47 53 20 20 31 35 2E 33 37 36 20 20 53 54 2C 47 53 20 20 31 35 2E 33 36 20 53 54 2C 47 53 20 20 31 35 2E 33 37 36 20 53 54 2C 47 53 20 20 31 35 2E 33 37 20 D 53 54 2C 47 53 20 20 31 35 2E 33 37 36 67 A 53 54 2C 47 53 20 20 31 35 2E 33 36 20 53 54 2C 47 53 20 20 31 35 2E 33 37 67 A 53 54 2C 47 53 20 20 31 35 2E 33 37 36 67 A 53 54 2C 47 53 20 20 31 35 2E 33 36 20 53 54 2C 47 53 20 20 31 35 2E 33 37 20 20 53 54 2C 47 53 20 20 31 35 2E 33 37 34 20 67 20 A 53 54 2C 47 53 20 20 31 35 2E 33 34 20 53 54 2C 47 53 20 20

tramite un convertitore ottengo:
376 g ST,GS 15.376 ST,GS 15.376 g
ST,GS 15.37g
ST,GS 15.36 ST,GS 15.376 ST,GS 15.36 ST,GS 15.376 ST,GS 15.37
ST,GS 15.376g
ST,GS 15.36 ST,GS
molto più pulito rispetto a prima che avevamo il delay (anche se non capisco perché non va sempre a capo).

  1. ho provato a mettere sul piatto della bilancia un oggetto di massa più piccola, inferiore a 10 g, ed ho notato che i byte che mi interessano non sono più quelli che partono dall'ottavo di ogni serie, ma dal nono:

53 54 2C 47 53 20 20 20 31 2E 38 31 38 20 67 20 D A
che significa:
S T , G S sp sp sp 1 . 8 1 8 sp g sp \r \n

sto nel panico più totale!

Non c'è motivo, tutto come previsto.
Qui c'è un post da cui prendere spunto per collezionare i byte in un array, vedi se ti torna utile.

Una volta collezionati i byte è modificato il giusto byte con il terminatore '\0' ci pensa atof a restituirti il valore in una variabile di tipo float,

Ciao.

Io vedo sempre dati corrotti... g mancanti, fineriga mancanti, ST senza la S ecc... qualcosa non va nel collegamento fisico? Il fatto di saturare il buffer in uscita manda in crisi la ricezione della serial software?

ST,GS  15.37g15.376 ST,GS  15.376 g 
ST,GS  15.376gT,GS  15.376  ST,GS  15.36 ST,GS  15.376 ST,GS  15.37 
ST,GS  15.36 ST,GS  15.37g
ST,GS  15.376g
ST,GS  15.36 ST,GS  15.37  ST,GS  15.374 g 
ST,GS  15.34 ST,GS  

Facciamo così... prima acquisiamo in blocco un kB di dati senza alcun ritardo, e dopo li stampiamo. Cosa si ottiene?

byte a[1024];
int i = 0;
while (i < 1024)
    if (softSerial.available())
        a[i++] = softSerial.read();

for (i=0; i<1024; i++)
{
    Serial.print((uint8_t)a[i], HEX);
    Serial.print(" ");
}
1 Like