"estrarre" il punto decimale da un float, come fare?

lesto:
mi son ricordato dopo che arduino IDE ha questa mancanza) su gcc, e tutti i linguaggi che possiedono nativamente l'operatore modulo non ho mai trovato questo comportamento

Il compilatore di Arduino è il GCC, non c'entra nulla con l'IDE e le librerie di Arduino, l'operatore % è gestito dal GCC e l'errore lo da proprio il GCC, non mi obbligare a fare copia e incolla di pagine e pagine di manuali C dove si dice chiaramente che l'operatore % è esclusivamente per gli INTERI.
Se non ci credi guarda che errore mi da il C30 di Microchip, che si basa sul GCC, per una operazione % con i float:

// pezzo di codice incriminato
float pippo;
int pluto;

int main (void)
{
 pluto = pippo%10;	
	
//errore del compilatore
src\main.c: In function 'main':
src\main.c:132: error: invalid operands to binary %
Halting build on first failure as requested.

ok, ero convinto che il c ansi lo supportasse anche per float e double.

Comunque per tagliare la testa al toro il gioco del contare i numeri dopo la virgola si può fare anche senza usare il modulo usando una moltiplicazione per 10 finchè il numero moltiplicato (e diviso per 10^numero cifre contate) non è uguale alla forzatura del numero int

sto provando questo sketc a volte funziona a volte no
e piu precisamente sembra che ha la tendenza ad arrotondare la cifra immessa

MA CHI GLIELO HA ORDINATO IL MEDICO!!!!!!!!!!!!! ]:smiley:

ES: il valore 577.777 allinizio la prende (secondo il serial print 577.78)
e poi diventa 577.77696 =(

esempio se metto
valore_reale = 444.444;

tutto fila liscio il serial print da punto sulla 4 cifra (partendo da destra) e valore da inviare 444444 corretto,

l'idea di questo sketct è quello di prendere il numero
come int e float
sottrare float da int se da diverso da zero moltiplico per 10 e un contatore che e a 1 aumeta di un unita (posizione punto decimale)

se c'è un sistema per non fare arrotondare il float siamo sulla buona strada

unsigned long mela;

float pesca;
float valore_reale;
byte posizione_punto_sulla_cifra =1;
float k=0;
unsigned long p;

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

valore_reale = 444.444; //cifre massime 7
//if (valore_reale > 1 && valore_reale <10) valore_reale = valore_reale * 1000000;

pesca = valore_reale; //cifre massime 7

}

void loop()
{
mela= pesca;

if (pesca-mela>0) posizione_punto_sulla_cifra = posizione_punto_sulla_cifra + 1, pesca = pesca*10;

Serial.print("posizione_punto_sulla_cifra ");
Serial.println(posizione_punto_sulla_cifra);

Serial.print("valore_reale ");

Serial.println(valore_reale, (posizione_punto_sulla_cifra-1) );

if(posizione_punto_sulla_cifra == 1) p= 1;
if(posizione_punto_sulla_cifra == 2) p= 10;
if(posizione_punto_sulla_cifra == 3) p= 100;
if(posizione_punto_sulla_cifra == 4) p= 1000;
if(posizione_punto_sulla_cifra == 5) p= 10000;
if(posizione_punto_sulla_cifra == 6) p= 100000;
if(posizione_punto_sulla_cifra == 7) p= 1000000;

//if (valore_reale > 999999) posizione_punto_sulla_cifra =posizione_punto_sulla_cifra-1;
//if (valore_reale > 999999) valore_reale =valore_reale/10;
Serial.print("valore da mandare al display ");
Serial.println(valore_reale*p,0 );

}


Io non sono un genio in programmazione devo spesso documentarmi per fare cose un po' più complesse, e molte volte non mi escono come vorrei, però quando posto un pezzetto di sketch è assicurato al 100% che l'ho provato prima sul mio arduino. Diversamente farei perdere tempo a chi già sta diventando scemo per capire come fare.
In conclusione se provaste ciò che suggerite in 2 post sarebbe chiuso il caso XD

lesto:
ok, ero convinto che il c ansi lo supportasse anche per float e double.

Vale anche per il C++ perché % è un operatore vero e proprio del C, cioè fa parte del linguaggio, per i float si usa fmod() che è una funzione di libreria.

pablos:
In conclusione se provaste ciò che suggerite in 2 post sarebbe chiuso il caso XD

+1 :slight_smile:
Sagge parole, prima di postare del codice tocca sempre provarlo, o almeno avvisare che non è testato, altrimenti si fa solo perdere tempo alla gente.

pablos:
Io non sono un genio in programmazione devo spesso documentarmi per fare cose un po' più complesse, e molte volte non mi escono come vorrei, però quando posto un pezzetto di sketch è assicurato al 100% che l'ho provato prima sul mio arduino. Diversamente farei perdere tempo a chi già sta diventando scemo per capire come fare.
In conclusione se provaste ciò che suggerite in 2 post sarebbe chiuso il caso XD

se no fossi al lavoro.... io ho dato la logica e gli strumenti, che ce lo mettano loro il compilatore. xD

@gingardu: credo che il problema con cui ti scontri è il fatto che i float, per come vengono memorizzati, possiedono un errore. Non puoi farci niente, se vuoi usare i float. per maggiori info: IEEE 754 - Wikipedia

gingardu:
sto provando questo sketc a volte funziona a volte no
e piu precisamente sembra che ha la tendenza ad arrotondare la cifra immessa

Ed ecco il classico caso di chi fa le domande e non legge tutte le risposte, ti ho avvisato molti post dietro che i float sono una rappresentazione esponenziale e che ti puoi scordare dei valori precisi, sono sempre leggermente diversi dal reale valore, calcolato con molta più risoluzione, per via degli arrotondamenti durante i calcoli e il particolare formato di rappresentazione.

Scusa gingardu però è difficile capire cosa vuoi fare, nel primo post chiedi di sapere in che posizione numerica si trova la virgola, quindi di conoscere i valori prima della virgola e dopo non ti interessa come scrivi qui:

cifra1=0 // non ha il punto decimale
cifra2=0 // non ha il punto decimale
cifra3=1 // HA il punto decimale
cifra4=0 // non ha il punto decimale
cifra5=0 // non ha il punto decimale
cifra6=0 // non ha il punto decimale

quindi qualcuno non approva a convertire il valore in string, però se ti serve sapere la posizione perchè non farlo?

Se poi tu dicessi in sintesi perchè vuoi questo valore, da dove arriva questo numero float, cosa devi fare una volta trovato questo valore ti si può suggerire un altra soluzione, ti ho chiesto in un post precedente che hai ignorato perchè questa insolita domanda sulla posizione della virgola.... te lo faccio io lo sketch dimmi cosa vuoi fare :slight_smile:

ciao

se è solo la posizione che ti serve

String stringa = "6546456456457.56720";
byte x; byte c; byte par;
char charBuf[30];

void setup()
{
  Serial.begin(9600);
 
  stringa.toCharArray(charBuf, 40);   
  char *p = charBuf;   
  while (*p != '\0') 
  {
    c++;
    if (*p == '.') { par=c; ++p; continue;}           
    ++p;
  }   	
 
 //----------------------------------debug-----------------------------------------------
   Serial.println("stringa esaminata " + stringa);
   Serial.println("il punto si trova alla posizione " + (String)(par) + " da sinistra");
   Serial.println("il punto si trova alla posizione " + (String)(c-par+1) + " da destra");   
   Serial.println("totale dei caratteri  " + (String)c);     
}

void loop(){}

pablos:
Scusa gingardu però è difficile capire cosa vuoi fare, nel primo post chiedi di sapere in che posizione numerica si trova la virgola, quindi di conoscere i valori prima della virgola e dopo non ti interessa come scrivi qui:

cifra1=0 // non ha il punto decimale
cifra2=0 // non ha il punto decimale
cifra3=1 // HA il punto decimale
cifra4=0 // non ha il punto decimale
cifra5=0 // non ha il punto decimale
cifra6=0 // non ha il punto decimale

quindi qualcuno non approva a convertire il valore in string, però se ti serve sapere la posizione perchè non farlo?

Se poi tu dicessi in sintesi perchè vuoi questo valore, da dove arriva questo numero float, questa insolita domanda sulla posizione della virgola.... te lo faccio io lo sketch dimmi cosa vuoi fare :slight_smile:

ciao

ovviamente le cose le chiedo perche ho intenzione poi di "usarle" voglio sapere dove si trova la virgola perche il tutto va "inviato" a 6 display 7 segmenti quindi teoricamente dovvrebbe esserre tutto semplice,
ma vedo che all'atto pratico non è cosi,
ora se la variabile assume un valore intero tra zero e 999999 il tutto viene visualizzato correttamente,
(il contenuto della variabile arriva da una lettura di un sensore, ma questo non vedo che importanza puo avere)

(metto xx per ricordare che il display ha 6 cifre)
se la variabile ha i decimali esempio xx99.99 deve succedere questo

mi deve portare a uno la cifra che ha il punto decimale e a zero quelle che non c'è l'hanno
attenzione queste variabili che sono che sono chiamate cifra1 cifra2 ...cifra 6 servono solo come "segnali,
potevo benissimo chiamarli mela1 mela2 mela3

cifra1=0 // non ha il punto decimale
cifra2=0 // non ha il punto decimale
cifra3=1 // HA il punto decimale
cifra4=0 // non ha il punto decimale
cifra5=0 // non ha il punto decimale
cifra6=0 // non ha il punto decimale

è in piu mi deve trasformare il numero con decimale in numero intero
in questo caso 99.99 va trasformato in 9999

altro esempio x123.66

cifra1=0 // non ha il punto decimale
cifra2=0 // non ha il punto decimale
cifra3= 0 // non ha il punto decimale
cifra4=1 // HA il punto decimale
cifra5=0 // non ha il punto decimale
cifra6=0 // non ha il punto decimale

in questo caso 123.66 va trasformato in 12366

da notare che
1.1 1.11 1.111 hanno il punto decimale su cifra diversa precisamente quinta quarta e terza,

invece 1.1 11.1 111.1 1111.1 11111.1 hanno il decimale tutti sulla stessa cifra guardando il display e precisamente la penultima contando da sinista (la quinta)

pablos:
se è solo la posizione che ti serve

String stringa = "6546456456457.56720";

byte x; byte c; byte par;
char charBuf[30];

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

stringa.toCharArray(charBuf, 40);  
 char *p = charBuf;  
 while (*p != '\0')
 {
   c++;
   if (*p == '.') { par=c; ++p; continue;}          
   ++p;
 }

//----------------------------------debug-----------------------------------------------
  Serial.println("stringa esaminata " + stringa);
  Serial.println("il punto si trova alla posizione " + (String)(par) + " da sinistra");
  Serial.println("il punto si trova alla posizione " + (String)(c-par+1) + " da destra");  
  Serial.println("totale dei caratteri  " + (String)c);    
}

void loop(){}

ho provato questo codice ma se lo sposto nel loop inizia a "dare i numeri"
potrebbe essere valido a patto che puo stare nel loop, e dia sempre lo stesso risultato se il numero e lo stesso
bisognerebbe anche associare string al numero (variabile) da analizzare

infatti è tutto più semplice se dici che devi inviarli a dei display a 7 seg, ecco perchè volevi il numero prima della virgola!! per accendere il punto!! ...

come sono collegati ad arduino questi display? tutti in parallelo, usi un MAX o un 595?
quanti sono i display? bisognerebbe saperlo per dare una grandezza massima alle variabili.

i pin usati dovrebbero essere 8 + n° ENABLE di ogni display dico bene?

ora penso che sia molto più semplice XD dato che c'è una vastità di esempi compresi gli sketch

http://www.sqlskills.com/blogs/paulselec/post/Arduino-cascading-shift-registers-to-drive-7-segment-displays.aspx
http://arduino.cc/forum/index.php/topic,36600.15.html
http://arduino.cc/forum/index.php/topic,95817.0.html

http://arduino.cc/playground/Main/DirectDrive88884Digit7SegmentDisplay

i display sono 6 collegatì in parallelo nessun integrato aggiuntivo solo trasistor su i segmenti e sul comune

piu che i display il problema e il numero

basterebbe che una variabile (tipo byte) prende il valore della posizione della cifra con la virgola partendo da destra,
cosi non ci sono frantendimenti.

e una variabile (tipo long) che prende il valore del numero senza virgola,

es: numero 1.99999

byte a=6;
long b=199999;

es: numero 345.654

byte a=4;
long b=345654;

gingardu:
i display sono 6 collegatì in parallelo nessun integrato aggiuntivo solo trasistor su i segmenti e sul comune

piu che i display il problema e il numero

basterebbe che una variabile (tipo byte) prende il valore della posizione della cifra con la virgola partendo da destra,
cosi non ci sono frantendimenti.

e una variabile (tipo long) che prende il valore del numero senza virgola senza arrotondare però ]:D,

es: numero 1.99999

byte a=6;
long b=199999;

es: numero 345.654

byte a=4;
long b=345654;

ho capito, ma non ti conviene stabilire 2 decimali dopo la virgola lasciando il punto sempre acceso al massimo avrai xxxx.00, se stabilisci delle regole si semplifica lo sketch.
Ora non so che valori devi rappresentare, ma se prendi le ultime 2 cifre a destra sai che sono i decimali sempre senza cercare il punto, tutte le cifre che vengono prima del punto possono variare da 1 a 4 cifre

es
1234.56
989.23
25.12
4.00

più o meno uno schema tipo questo

display7seg_anim_preview.gif

non so come hai sviluppato il programma fino ad ora e ne che arduino hai.

Per semplificare il processo sarebbe bello prendere ad esempio il gruppo D di pin che sono 8 (D0-D7)
e fare una cosa simile:

Segmento A - Pin 0
Segmento B - Pin 1
Segmento C - Pin 2
Segmento D - Pin 3
Segmento E - Pin 4
Segmento F - Pin 5
Segmento G - Pin 6
Segmento H - Pin 7
Enable displ 1 - pin ...
Enable displ 2 - pin ...
Enable displ 3 - pin ...
....

i valori corrispondenti decodifica BCD
0 => B00111111
1 => B00000110
2 => B01011011
3 => B01001111
4 => B01100110
5 => B01101101
6 => B01111101
7 => B00000111
8 => B01111111
9 => B01101111

int val[]={B00111111, B00000110, B01011011, B01001111, B01100110, B01101101, B01111101, B00000111, B01111111, B01101111};
byte num[6];

void setup(){
  DDRD = B11111111; //imposto i pin in OUTPUT 
}

void loop(){

//-----scomposizione delle cifre in byte da caricare nell'array "num[]"
//...
//...
//...

   for(int i=0; i<7;i++)
  {
    //il numero che possiede la virgola accenderà anche il pin 0  val[numero da rappresentare]+1
    PORTD = val[numero da rappresentare contenuto nell' array es. num[i] ]; //0-9
    delay(1000);
  }
}

ora resta ricavare le cifre singolarmente (le metterei in un array di byte a 6 celle), e pilotare i singoli display, domani ci do un occhio

ciao

il lavoro per visualizzare le cifre c'è gia qualsiasi valore che assume una certa variabile (x)
viene visualizzata,

quello che sto cercando di fare e di far visualizzare anche numeri con la virgola,

e per far accendere il punto decimale ci vuole un riferimento di qualche tipo
piu che altro bisogna trovare un sistema tipo prendere il numero es 123.456

se necessario trasformarlo in stringa e contare da destra verso sinistra fino a trovare la virgola associare il conteggio a una variabile, questo è gia metà del lavoro

l'altra metà consiste di prendere sempre lo stesso numero trasfotmarlo in stringa (suppongo) eliminare la virgola e ritrasformare il numero stringa in numero normale senza virgola tipo lon 123456

un sistema l'avevo trovato ma arduino ha una tendenza ad arrotondare in maniera assurda se metto1.99998 lo ttasforma in 2.00 in automatico e vanifica tutto

sembrache ho risolto 8)
il float xx viene trasformato in stringa dalla prima parte del codice
la seconda parte del codice che il codice postato da pablos aggiustato (o massacrato) da me
trova la posizione della virgola partendo da destra

questa parte

if (posizione == 1 ) ff=xx1;
if (posizione == 2 ) ff=xx
10;
if (posizione == 3 ) ff=xx100;
if (posizione == 4 ) ff=xx
1000;
if (posizione == 5 ) ff=xx10000;
if (posizione == 6 ) ff=xx
100000;

con l'aiuto della posizione virgola ff (long) prende il valore di xx moltiplicato che significa
avere xx numero senza virgola e senza quei maledetti arrotondamenti che di solito fa il float ]:smiley:

ho aggiunto un "segnale " se il float è minore si uno (se è minore gli viene sommato uno e poi gli viene sottratto in "sede opportuna"

l'ho testato un po e sembra reggere anche con float 3,99999 scrive giusto 8) è ancora da testare a fondo però

String stringa ;
byte x; byte c; byte par;
char charBuf[9];
byte   posizione ;
float xx;
long ff;
byte segnalazero = 0;
void setup()
{
  Serial.begin(9600);
}

void loop(){ 
  
        xx =3.7;   //float da trattare
  
 
  if (xx<1) xx=xx+1, segnalazero = 1;
  
  
   char buffer[9];
char *result;
float number=xx;  //xx e il numero float che viene convertito instring con il nome result
result = dtostrf(number, 0, 5, buffer); 
//Serial.println(result);
//result = dtostrf(number, 4, 5, buffer); 
//Serial.println(result);
 
delay (1000);
  stringa = result;
  stringa.toCharArray(charBuf, 9);   
  char *p = charBuf;   
  while (*p != '\0') 
  {
    c++;
    if (*p == '.') { par=c; ++p; continue;}           
    ++p;
  }   	
 posizione=(c-par+1);
 
//----------------------------------debug-----------------------------------------------
   Serial.println("stringa esaminata " + stringa);
   
       Serial.print("posizione virgola    " ); 
          Serial.println(posizione);
         //Serial.println(millis()); 
    // c=0;
     if (posizione == 1 ) ff=xx*1;     
     if (posizione == 2 ) ff=xx*10;
     if (posizione == 3 ) ff=xx*100;
     if (posizione == 4 ) ff=xx*1000;
     if (posizione == 5 ) ff=xx*10000;
     if (posizione == 6 ) ff=xx*100000;
     
      Serial.print("NUMERO INTRERO    "  );
       Serial.println(ff);
       Serial.print("segnalazero   "  );
      
       Serial.println(segnalazero );
        Serial.println("     "  );
    }

anzichè fare

if (posizione == 1 ) ff=xx*1;

etc..
non puoi usare una formula?

ff=xx*Math.pow(10, posizione-1); //pow è l'elevazione a potenza (base, esponente). un numero alla 0 è = ad 1