- Messaggi: 362
- Ringraziamenti ricevuti 39
Subroutine per la stampa di un floating point
- firstcolle
-
- Platino Utente
-
Less
Di più
8 Anni 4 Mesi fa #21
da firstcolle
Risposta da firstcolle al topic Subroutine per la stampa di un floating point
Molto interessante la tua soluzione!!!
posto anche la mia. praticamente do in input il float e quanti decimagli voglio scrivere sul display. La funzione converte in intero la parte intera e in stringa la parte decimale ed approssima l'ultimo decimale per eccesso.
poi scrive su LCD l'intero come signed int la virgola e la stringa dei decimali.
Purtroppo in questo modo ci sono dei casi ambigui con valori compresi tra -1 e 0 che mi ha costretto ad inserire una forzatura di stampa del - se il float iniziale è compreso tra -1 e 0. (questo succede perchè, prendendo per esempio -0.5, estraggo l'intero ed è 0 e quindi perdo il segno -)
posto anche la mia. praticamente do in input il float e quanti decimagli voglio scrivere sul display. La funzione converte in intero la parte intera e in stringa la parte decimale ed approssima l'ultimo decimale per eccesso.
poi scrive su LCD l'intero come signed int la virgola e la stringa dei decimali.
Purtroppo in questo modo ci sono dei casi ambigui con valori compresi tra -1 e 0 che mi ha costretto ad inserire una forzatura di stampa del - se il float iniziale è compreso tra -1 e 0. (questo succede perchè, prendendo per esempio -0.5, estraggo l'intero ed è 0 e quindi perdo il segno -)
Code:
void LCD_send_float (float _float, unsigned char _digits) {
signed int _int = 0;
float _part = 0;
unsigned char _string[11];
unsigned char _i = 0;
unsigned char _force_negative = 0;
if (_digits > 10) // valore massimo di decimali = 10
_digits = 10;
_int = (int) _float; // estraggo la parte intera
_part = _float - (float)_int; // lascio solo la parte decimale
if (_part<0){ // se decimali minore di 0
_part = _part * -1; // porto positiva
if (_int == 0) // valore compreso tra -1 e 0
_force_negative = 1; // forzo valore negativo
}
for (_i = 0; _i < _digits +1; _i++ ){ // per ogni decimale richiesto +1
_part = _part *10; // moltiplico per 10
_string[_i] = (unsigned char)_part; // salvo nella stringa
_part = _part - (float) _string[_i]; // dalla parte decimale sottraggo la nuova intera
}
// calcoli per l'approssimazione
if (_digits == 0) { // 0 cifre decimali
if (_string[0] > 4){ // se la prima decimale è maggiore di 4 aggiungo 1 agli interi
if (_int >= 0) // se positivo
_int++;
else // altrimenti sottraggo 1
_int--;
}
} else { // se ho più cifre decimali
if (_string[_digits] > 4){ // se l'ultima decimale (aggiunta solo per l'arrotondamento) è maggiore di 4
_string[_digits - 1]++; // aggiungo uno alla decimale precedente
}
for (_i = 0; _i < _digits -1; _i++ ){ // controlla dalla penultima decimale alla prima
if (_string[_digits - 1 - _i] > 9){ // se maggiore di 9
_string[_digits - 1 - _i] = 0; // la porto a 0
_string[_digits - 2 - _i]++; // e aggiungo uno alla precedente
}
}
if (_string[0] > 9){ // se la prima decimale è maggiore di 9
_string[0] = 0; // la azzero e incremento o decremento gli interi
if (_int >= 0)
_int++;
else
_int--;
}
}
for (_i = 0; _i < _digits +1; _i++ ){
_string[_i] = _string[_i] + 0b00110000; // formo array di caratteri char con i numeri decimali
}
_string[_digits] = '\0'; // aggiungo carattere di fine stringa (array da 0 a _digit-1 contiene i numeri decimali richiesti)
if (_force_negative) // valore compreso tra -1 e 0
LCD_send_char('-'); // forzo segno -, altrimenti verrebbe mostrato 0 senza segno
LCD_send_sint(_int); // scrivo la parte intera
if (_digits > 0) { // se sono richieste cifre decimali
LCD_send_char(','); // scrivo ',' e decimali
LCD_send_string(_string);
}
}
Si prega Accesso o Crea un account a partecipare alla conversazione.
- paoletto
-
Autore della discussione
- Elit Utente
-
Less
Di più
- Messaggi: 186
- Ringraziamenti ricevuti 3
8 Anni 4 Mesi fa #22
da paoletto
Risposta da paoletto al topic Subroutine per la stampa di un floating point
Alt, c'è un errore mostruoso nel codice :S , non funziona un bel niente :silly: .
E' sbagliata la mia soluzione dal momento che è inutile ripulire tutta la stringa finale con spazi bianchi: la stringa finale occorrente avrà il suo bel terminatore di fine stringa e la funzione di Mauro write_string_LCD() si fermerà non appena troverà la prima occorrenza del suddetto terminatore, ma la nuova stringa potrebbe essere più corta della precedente e quindi il suo terminatore sarà più giù e questo significa che i caratteri rimasti della stringa precedente non verranno mai ripuliti.
La soluzione è concatenare alla stringa occorrente(TempString)semplicemente una stringa di spazi bianchi di lunghezza pari a N-strlen(TempString) dove N è la profondità del display.
Posto il codice
La funzione concatena 3 token: la grandezza da misurare, il suo valore e la sua unità di misura.
Bisogna fare attenzione a non esagerare con la lunghezza dei token, devono essere i più identificativi possibile altrimenti non funziona, cioè bisogna farsi due conti e cercare di restare entro i 16 0 20 caratteri complessivi.
Per adesso funziona molto bene e non ho visto anomalie.
Il codice è sempre fatto per il C2000 ma è general purpose.
Per favore, chi abbia tempo usi la funzione e mi dia un feedback.
Grazie
Paolo.
E' sbagliata la mia soluzione dal momento che è inutile ripulire tutta la stringa finale con spazi bianchi: la stringa finale occorrente avrà il suo bel terminatore di fine stringa e la funzione di Mauro write_string_LCD() si fermerà non appena troverà la prima occorrenza del suddetto terminatore, ma la nuova stringa potrebbe essere più corta della precedente e quindi il suo terminatore sarà più giù e questo significa che i caratteri rimasti della stringa precedente non verranno mai ripuliti.
La soluzione è concatenare alla stringa occorrente(TempString)semplicemente una stringa di spazi bianchi di lunghezza pari a N-strlen(TempString) dove N è la profondità del display.
Posto il codice
Code:
//Numero caratteri del display(20 0 16)
#define SizeCharDisplay 20
//Prototipo
void PrintFloatOnString(const char *Token1, float measure, char SizeMeasure, const char *Token2);
//corpo
void PrintFloatOnString(const char *Token1, float measure, char SizeMeasure, const char *Token2)
{
size_t i;
char String_Empty_Spaces[SizeCharDisplay+1] = "";
char measure_float[SizeCharDisplay+1]= "";
char StrToken1[SizeCharDisplay+1] = "";
char StrToken2[SizeCharDisplay+1] = "";
char TempString[SizeCharDisplay+1] = "";
char EndString[SizeCharDisplay+1] = "";
strcpy(StrToken1,Token1);
strcpy(StrToken2,Token2);
strcpy(TempString, StrToken1);
FloatToString(measure_float, measure, SizeMeasure);
strcat(TempString, measure_float);
strcat(TempString, StrToken2);
for(i = 0; i < SizeCharDisplay-strlen(TempString); i++)
{
String_Empty_Spaces[i] = ' '; //spazi bianchi
}
String_Empty_Spaces[++i] = '\0'; //terminatore di fine stringa
strcat(TempString, String_Empty_Spaces);
strcpy(EndString, TempString);
write_string_LCD(EndString);//stringa finale
}
//uso
main()
{
while(1)
{
PrintFloatOnString("Vrms: ", RMS_Value, 3, " V"); //3 è il numero di cifre decimali
}
}
La funzione concatena 3 token: la grandezza da misurare, il suo valore e la sua unità di misura.
Bisogna fare attenzione a non esagerare con la lunghezza dei token, devono essere i più identificativi possibile altrimenti non funziona, cioè bisogna farsi due conti e cercare di restare entro i 16 0 20 caratteri complessivi.
Per adesso funziona molto bene e non ho visto anomalie.
Il codice è sempre fatto per il C2000 ma è general purpose.
Per favore, chi abbia tempo usi la funzione e mi dia un feedback.
Grazie
Paolo.
Si prega Accesso o Crea un account a partecipare alla conversazione.
Moderatori: Mauro Laurenti, StefA
Registrati al sito
Accedi a tutte le risorse e articoli non visibili pubblicamente, puoi registrarti con pochi passi.
Forum - Ultimi messaggi
-
- Freedom III e compilazioni fallite
- da Black
-
- MODULO GSM SIM900A
- da FABRIZIO
-
- LTerminal - nuove funzioni
- da Mauro Laurenti
-
- Aggiornamento sito completato
- da Mauro Laurenti
-
- registro a scorrimento PIPO in cascata
- da Mauro Laurenti