Continue to Site

# [SOLVED]16F887 > Converting Long (and Double Long) to String

Status
Not open for further replies.

#### Eric_O

##### Member level 4
Bonjour,

I m looking for some code in order to display on an LCD a counting from :
- 1 000 000,00 to + 1 000 000,00

Eric

Solution
hello,

i extended the last function to _999999.99 up to +999999.99
Code:
void float_to_ASCII_with_2_decimal_v5(float fx, char *pt)
{
unsigned long e = 0; // 0 to more than 65535.
unsigned long d = 0; // 0 to more than 65535.
float f0, chiffre_decimal=0.0;
int k=0;
if (fx < 0)
{
*(pt) = '-';     //  0cx2D
chiffre_decimal=-fx;
}
else
{
*(pt) = '+'; // 0x2B signe +
chiffre_decimal=fx;
}
e =(unsigned long)  floor(chiffre_decimal); // Partie entière.
d =(chiffre_decimal - (float)e) * 100; // Partie décimale (2 chiffres);
// Partie entière de 99999 à 0 :
if (e/100000L >= 0) *(pt+1) =(unsigned char) (e/100000L) + 0x30;
e = e%100000L;
if (e/10000L >= 0) *(pt+2) =(unsigned char) (e/10000L) + 0x30;
e = e%10000L...

#### Aussie Susan

Which compiler are you using?
If you are using XC8 then you can use the 'ltoa' library function but it assumes a long value only. There is also the 'ftoa' function for floating point values.
I'm also confused by some aspects of your question. In the title you mention 'double long'; do you mean 'long long'? On the other hand, the values you give seem to imply 2 decimal places (using the European convention for the decimal point); are you using floating point values (hence the 'double' in the title perhaps) or are you using a scaled integer?
A 'long' (in XC8 at least) is 32 bits (as is 'long long') and the signed variant that will hold either the scaled version or the unscaled (excluding the decimal part) version easily (in fact you can use the 24-bit 'short long' and still get a domain of well over +/-1,000,000).
If you really are using floating point (and I would certainly recommend that you don't with these lower range MCUs as everything has to be done in software and that can be very slow) then you may run into problems with the precision you can get - you seem to imply that you want 7 (or perhaps 9) digits.
Susan

There is a C code example 2/3 the way down the page.

Regards, Dana.

#### Eric_O

##### Member level 4
Which compiler are you using?
If you are using XC8 then you can use the 'ltoa' library function but it assumes a long value only. There is also the 'ftoa' function for floating point values.
I'm also confused by some aspects of your question. In the title you mention 'double long'; do you mean 'long long'? On the other hand, the values you give seem to imply 2 decimal places (using the European convention for the decimal point); are you using floating point values (hence the 'double' in the title perhaps) or are you using a scaled integer?
A 'long' (in XC8 at least) is 32 bits (as is 'long long') and the signed variant that will hold either the scaled version or the unscaled (excluding the decimal part) version easily (in fact you can use the 24-bit 'short long' and still get a domain of well over +/-1,000,000).
If you really are using floating point (and I would certainly recommend that you don't with these lower range MCUs as everything has to be done in software and that can be very slow) then you may run into problems with the precision you can get - you seem to imply that you want 7 (or perhaps 9) digits.
Susan
Bonjour Susan,
I m using MikroC compiler. I do not want to use their library. In order to understand I would prefer to have an opensource routine.
Bonjour to South Australia, Melbourne, Perth. Beautiful places. 😎
Merci.
Éric

#### paulfjujo

hello,

i extended the last function to _999999.99 up to +999999.99
Code:
void float_to_ASCII_with_2_decimal_v5(float fx, char *pt)
{
unsigned long e = 0; // 0 to more than 65535.
unsigned long d = 0; // 0 to more than 65535.
float f0, chiffre_decimal=0.0;
int k=0;
if (fx < 0)
{
*(pt) = '-';     //  0cx2D
chiffre_decimal=-fx;
}
else
{
*(pt) = '+'; // 0x2B signe +
chiffre_decimal=fx;
}
e =(unsigned long)  floor(chiffre_decimal); // Partie entière.
d =(chiffre_decimal - (float)e) * 100; // Partie décimale (2 chiffres);
// Partie entière de 99999 à 0 :
if (e/100000L >= 0) *(pt+1) =(unsigned char) (e/100000L) + 0x30;
e = e%100000L;
if (e/10000L >= 0) *(pt+2) =(unsigned char) (e/10000L) + 0x30;
e = e%10000L;
if (e/1000 >= 0) *(pt+3) = (unsigned char) (e/1000) + 0x30 ;
e = e%1000L;
if (e/100L >= 0) *(pt+4) = (unsigned char) (e/100L) + 0x30;
e = e%100L;
if (e/10L >= 0) *(pt+5) =(unsigned char)  (e/10L) + 0x30;
*(pt+6) = (unsigned char) (e%10L) + 0x30;
*(pt+7) = 0x2C ; // Virgule au lieu d' un point.
*(pt+8)= (unsigned char) (d/10) + 0x30; // Partie décimale de 99 à 0 :
*(pt+9) = (unsigned char) (d%10) + 0x30;
*(pt+10)= 0;
// maintenant on arrange en supprimant les zeros inutiles
if (*(pt+1)=='0')
{
*(pt+1)=' ';
if (*(pt+2)=='0')
{
*(pt+2)=' ';
if (*(pt+3)=='0')
{
*(pt+3)=' ';
if (*(pt+4)=='0')
{
*(pt+4)=' ';
if (*(pt+5)=='0')
{
*(pt+5)=' ';
}
}
}
}
}
}

Test programme
Code:
//=== Zone de test =======================

f1=-999999.98;
pt=&TEXTE[0];
CPrint(" Test   float_to_ASCII_with_2_decimal_v5(f1,pt) gamme -999 999 à + 999 999;\r\n");
float_to_ASCII_with_2_decimal_v5(f1,pt) ;
CPrint("Valeur de depart = "); Print(pt);
CPrint(" Increment = 10000.01;\r\n");
CRLF1();
do
{
float_to_ASCII_with_2_decimal_v5(f1,pt) ;
Print(pt);CRLF1();
f1=f1+10000.01;
}
while(f1<999999.99);
CRLF1();
CRLF1();
f1=-10.00;
float_to_ASCII_with_2_decimal_v5(f1,pt) ;
CPrint("Valeur de depart = "); Print(pt);
CPrint(" Increment =0.01;\r\n");

CRLF1();
do
{
float_to_ASCII_with_2_decimal_v5(f1,pt) ;
Print(pt);CRLF1();
f1=f1+0.01;
}
while(f1<10.0);

while(1);

results
(16:03:59.982) Directory: C:\_MikroC\_MesProjets_MikroC\_18F26K22_LCD_2x16_Classic_mode4bits
(16:04:00.127) Projet : Base_18F26K22_for_Tests_UART1_LCD1602_4bits_2021-06.mcppi
(16:04:00.266) Alim. = >4.5V
(16:04:00.374) Config : P18F26K22_FOSC_interne_16Mhz.cfgsch
(16:04:00.501) FOSC interne 16MHz
(16:04:00.612) Port Hard UART1 19200,N,8,1 (RC6=TX RC7=RX)
(16:04:00.857) Source Base_18F26K22_for_Tests_UART_LCD1602_4bits_2021_0708.c
(16:04:00.990) LCD 2x16 car 4bits data + 2 cdes
(16:04:01.110) RA5 = choix mode ADC via lib MikroC ou simili ASM
(16:04:01.143)
(16:04:02.340) Test Toggle Led Rouge RA4
(16:04:06.355) -:00000,00 <--- ":" ?????
(16:04:06.379) -989999,93
.....
(16:04:07.328) -109996,00
(16:04:07.339) - 99995,98
....
(16:04:07.415) - 29995,89
(16:04:07.426) - 19995,88
(16:04:07.437) - 9995,87
(16:04:07.449) + 4,13
(16:04:07.459) + 10004,14
.....
(16:04:07.547) + 90004,21
(16:04:07.558) +100004,21
.......
(16:04:08.545) +980004,25
(16:04:08.545) +990004,25

Zoom autour de zero :

Valeur de depart = - 10,00 Increment =0.01;

- 10,00
- 9,98
- 9,97
- 9,96
- 9,95
- 9,94
.......
- 0,11
- 0,10
- 0,09
- 0,08
- 0,07
- 0,06
- 0,05
- 0,04
- 0,03
- 0,02
- 0,01
- 0,00 <---- les aleas du flottant et les problemes d'arrondi avec
+ 0,00 <---- des nombres NON FINIs ...
+ 0,01
+ 0,02
+ 0,03
+ 0,04
+ 0,05
+ 0,06
+ 0,07
+ 0,08
+ 0,09
+ 0,10
+ 0,11
+ 0,12

Eric_O

### Eric_O

Points: 2

#### Eric_O

##### Member level 4
hello,

i extended the last function to _999999.99 up to +999999.99
Code:
void float_to_ASCII_with_2_decimal_v5(float fx, char *pt)
{
unsigned long e = 0; // 0 to more than 65535.
unsigned long d = 0; // 0 to more than 65535.
float f0, chiffre_decimal=0.0;
int k=0;
if (fx < 0)
{
*(pt) = '-';     //  0cx2D
chiffre_decimal=-fx;
}
else
{
*(pt) = '+'; // 0x2B signe +
chiffre_decimal=fx;
}
e =(unsigned long)  floor(chiffre_decimal); // Partie entière.
d =(chiffre_decimal - (float)e) * 100; // Partie décimale (2 chiffres);
// Partie entière de 99999 à 0 :
if (e/100000L >= 0) *(pt+1) =(unsigned char) (e/100000L) + 0x30;
e = e%100000L;
if (e/10000L >= 0) *(pt+2) =(unsigned char) (e/10000L) + 0x30;
e = e%10000L;
if (e/1000 >= 0) *(pt+3) = (unsigned char) (e/1000) + 0x30 ;
e = e%1000L;
if (e/100L >= 0) *(pt+4) = (unsigned char) (e/100L) + 0x30;
e = e%100L;
if (e/10L >= 0) *(pt+5) =(unsigned char)  (e/10L) + 0x30;
*(pt+6) = (unsigned char) (e%10L) + 0x30;
*(pt+7) = 0x2C ; // Virgule au lieu d' un point.
*(pt+8)= (unsigned char) (d/10) + 0x30; // Partie décimale de 99 à 0 :
*(pt+9) = (unsigned char) (d%10) + 0x30;
*(pt+10)= 0;
// maintenant on arrange en supprimant les zeros inutiles
if (*(pt+1)=='0')
{
*(pt+1)=' ';
if (*(pt+2)=='0')
{
*(pt+2)=' ';
if (*(pt+3)=='0')
{
*(pt+3)=' ';
if (*(pt+4)=='0')
{
*(pt+4)=' ';
if (*(pt+5)=='0')
{
*(pt+5)=' ';
}
}
}
}
}
}

Test programme
Code:
//=== Zone de test =======================

f1=-999999.98;
pt=&TEXTE[0];
CPrint(" Test   float_to_ASCII_with_2_decimal_v5(f1,pt) gamme -999 999 à + 999 999;\r\n");
float_to_ASCII_with_2_decimal_v5(f1,pt) ;
CPrint("Valeur de depart = "); Print(pt);
CPrint(" Increment = 10000.01;\r\n");
CRLF1();
do
{
float_to_ASCII_with_2_decimal_v5(f1,pt) ;
Print(pt);CRLF1();
f1=f1+10000.01;
}
while(f1<999999.99);
CRLF1();
CRLF1();
f1=-10.00;
float_to_ASCII_with_2_decimal_v5(f1,pt) ;
CPrint("Valeur de depart = "); Print(pt);
CPrint(" Increment =0.01;\r\n");

CRLF1();
do
{
float_to_ASCII_with_2_decimal_v5(f1,pt) ;
Print(pt);CRLF1();
f1=f1+0.01;
}
while(f1<10.0);

while(1);

results
Merci Paul ! 👍
Wonderful !
Very interesting.
Thank you for your quick answer. Now will be busy. Want to understand each line.
Eric

#### Aussie Susan

If you don't want to use the MikroC library functions then a quick Google (other search engines are available!) of 'ltoa c' and 'ftoa c' produce a number of examples.
(I'm in Melbourne - as you say, a lovely place but 0C this morning as we are in the middle of winter; promises to be a sunny day but cool!)
Susan

#### Eric_O

##### Member level 4
Merci Paul,
It works better. But now, I tried, for curiosity to expand the range of counting, from - 9 000 000 to + 9 000 000, but the code doesn’t decount. The LCD freezes at -9000000,00. I’m shure you will enlighten me.

Code:
// LCD module connections :
// VSS (pin  1) -> GND
// VDD (pin  2) -> VCC
// VEE (pin  3) -> middle pin contrast potentiometer
sbit LCD_RS at RB4_bit;                 // RS  (pin  4) -> portB.b4 (pin 37)
// RW not used.                         // RW  (pin  5) -> GND
sbit LCD_EN at RB5_bit;                 // EN  (pin  6) -> portB.b5 (pin 38)
// D0  (pin  7) -> GND
// D1  (pin  8) -> GND
// D2  (pin  9) -> GND
// D3  (pin 10) -> GND
sbit LCD_D4 at RB0_bit;                 // D4  (pin 11) -> portB.b0 (pin 33)
sbit LCD_D5 at RB1_bit;                 // D5  (pin 12) -> portB.b1 (pin 34)
sbit LCD_D6 at RB2_bit;                 // D6  (pin 13) -> portB.b2 (pin 35)
sbit LCD_D7 at RB3_bit;                 // D7  (pin 14) -> portB.b3 (pin 36)
//     (pin 15) -> GND
//     (pin 16) -> GND

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

/******************************************************************************/

// Declaration of variables :

float chiffre_decimal, sec;                                       // - 1.5 x 10 puissance 45 to + 3.4 x 10 puissance 38
char texte[64], *pt;                                              // 0 to 255

/******************************************************************************/

// Routines :

void LCD_E_pulse(void)
{
LCD_EN = 1;
Delay_us(5);
LCD_EN = 0;
Delay_us(5);
}

void LCD_Write_Cmd(unsigned char octet)
{
LCD_RS = 0;                                                      // Select Command Register.
// Send upper nibble.
LCD_D4 = ((octet & 0x10) == 0x10) ? 1 : 0;                       // Si ((octet & 0x10) == 0x10) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x20) == 0x20) ? 1 : 0;                       // Si ((octet & 0x20) == 0x20) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x40) == 0x40) ? 1 : 0;                       // Si ((octet & 0x40) == 0x40) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x80) == 0x80) ? 1 : 0;                       // Si ((octet & 0x80) == 0x80) alors LCD_D7 = 1 sinon = 0.
LCD_E_Pulse();
// Send lower nibble.
LCD_D4 = ((octet & 0x01) == 0x01) ? 1 : 0;                       // Si ((octet & 0x01) == 0x01) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x02) == 0x02) ? 1 : 0;                       // Si ((octet & 0x02) == 0x02) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x04) == 0x04) ? 1 : 0;                       // Si ((octet & 0x04) == 0x04) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x08) == 0x08) ? 1 : 0;                       // Si ((octet & 0x08) == 0x08) alors LCD_D7 = 1 sinon = 0.
LCD_E_Pulse();
}

void LCD_Write_Data(char octet)
{
LCD_RS = 1;                                                      // Select Data Register.
// Send upper nibble.
LCD_D4 = ((octet & 0x10) == 0x10) ? 1 : 0;                       // Si ((octet & 0x10) == 0x10) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x20) == 0x20) ? 1 : 0;                       // Si ((octet & 0x20) == 0x20) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x40) == 0x40) ? 1 : 0;                       // Si ((octet & 0x40) == 0x40) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x80) == 0x80) ? 1 : 0;                       // Si ((octet & 0x80) == 0x80) alors LCD_D7 = 1 sinon = 0.
LCD_E_Pulse();
// Send lower nibble.
LCD_D4 = ((octet & 0x01) == 0x01) ? 1 : 0;                       // Si ((octet & 0x01) == 0x01) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x02) == 0x02) ? 1 : 0;                       // Si ((octet & 0x02) == 0x02) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x04) == 0x04) ? 1 : 0;                       // Si ((octet & 0x04) == 0x04) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x08) == 0x08) ? 1 : 0;                       // Si ((octet & 0x08) == 0x08) alors LCD_D7 = 1 sinon = 0.
LCD_E_Pulse();
}

void strConstRamCpy(unsigned char *dest, const code char *source) // Copie le texte de la FLASH ROM vers la RAM.
{
while (*source)*dest ++ = *source ++;
*dest = 0;                                                       // Terminateur "0" fin de chaine de caractère.
}

void LCD_Write_CString_v2(char *msg)                              // Variante avec pointeur msg non modifié.
{
int k;
k = 0;
//while(*(msg) > 0)                                              // FAIL.
while(*(msg + k) > 0)                                            // OK.
{
LCD_Write_Data(*(msg + k));                                     // Data pointée par (msg + k).
k++;
if (k > 15) break;                                              // Si k > 15 sortie de la boucle while ...
}
}

void LCD_CString_Position_v2(char row, char col, char *msg)       //
{
if (row == 1)
{
LCD_Write_Cmd((col & 0x0F)|0x80);                            // Print message on 1st row and desired location.
}
else if (row == 2)
{
LCD_Write_Cmd((col & 0x0F)|0xC0);                            // Print message on 2nd row and desired location.
}
LCD_Write_CString_v2(msg);                                       // OK.
}

void float_to_ASCII_with_2_decimal_v7(float fx, char *pt)
{
unsigned long e = 0;                                                 // 0 to 4294967295.
unsigned long d = 0;                                                 // 0 to 4294967295.
float chiffre_decimal = 0.0;

if (fx < 0)
{
*(pt) = '-';
chiffre_decimal = - fx;
}
else
{
*(pt) = ' ';
chiffre_decimal = fx;
}

e = (unsigned long) floor(chiffre_decimal);                          // Partie entière.
d = (chiffre_decimal - (float)e) * 100;                              // Partie décimale (2 chiffres).

*(pt + 1) = ' ';

if (e/1000000 >= 0) *(pt + 2) = (unsigned char) (e/1000000) + 0x30;  // Partie entière de 9999999 à 0.
e = e%1000000;
if (e/100000 >= 0) *(pt + 3) = (unsigned char) (e/100000) + 0x30;
e = e%100000;
if (e/10000 >= 0) *(pt + 4) = (unsigned char) (e/10000) + 0x30;
e = e%10000;
if (e/1000 >= 0) *(pt + 5) = (unsigned char) (e/1000) + 0x30;
e = e%1000;
if (e/100 >= 0) *(pt + 6) = (unsigned char) (e/100) + 0x30;
e = e%100;
if (e/10 >= 0) *(pt + 7) = (unsigned char) (e/10) + 0x30;
*(pt + 8) = (unsigned char) (e%10) + 0x30;
*(pt + 9) = 0x2C;                                                    // Virgule au lieu d'un point.
*(pt + 10) = (unsigned char) (d/10) + 0x30;                          // Partie décimale de 00 à 99.
*(pt + 11) = (unsigned char) (d%10) + 0x30;
*(pt + 12) = 0;

if (*(pt + 2) == '0')                                                // Suppression des zéros inutiles.
{
*(pt + 2) = ' ';
if (*(pt + 3) == '0')
{
*(pt + 3) = ' ';
if (*(pt + 4) == '0')
{
*(pt + 4) = ' ';
if (*(pt + 5) == '0')
{
*(pt + 5) = ' ';
if (*(pt + 6) == '0')
{
*(pt + 6) = ' ';
if (*(pt + 7) == '0')
{
*(pt + 7) = ' ';
}
}
}
}
}
}
}

void LCD_Init_v4 (void)                                           // OK.
{
Delay_ms(15);                                                    // LCD power ON initialization time >= 15 mS.
LCD_Write_Cmd(0x30);                                             // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).
LCD_Write_Cmd(0x02);                                             // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).
LCD_Write_Cmd(0x28);                                             // 4 datas bits > 2 lines display, 5 × 8 dot character font.
LCD_Write_Cmd(0x0C);                                             // 4 datas bits > Display ON. Cursor OFF.
LCD_Write_Cmd(0x06);                                             // 4 datas bits > Auto increment cursor.
LCD_Write_Cmd(0x01);                                             // 4 datas bits > Clear display.
Delay_ms(1);                                                     // Ajustable ...
}

/******************************************************************************/

// Main program :

void main()
{
ANSEL = 0;                                                // Configure AN pins as digital I/O.
ANSELH = 0;
C1ON_bit = 0;                                             // Disable Comparator 1.
C2ON_bit = 0;                                             // Disable Comparator 2.

PORTB = 0;
TRISB = 0;
PORTC = 0;
TRISC = 0;

// Essai 16.1 : ALMOST OK ...

Lcd_Init_v4();                                            // Initialize LCD.

while(1)                                                  // Endless loop.
{
unsigned char *pointeur_de_char;                         // Déclaration d'un pointeur (*) de char "pointeur_de_char".
//char texte[] = "Counting ...";                         // Déclaration d'un tableau "texte" de type char et initialisé avec la chaine de caractères "Counting ..." :
// En n'indiquant aucun chiffre entre les cochets [], le compilateur ajustera automatiquement la taille du
// tableau, et allouera en mémoire RAM, le bon nombre d'éléménts, soit 13 ...
char txt[13];
pointeur_de_char = &texte[0];                            // pointeur_de_char pointe sur le premier élément du tableau "texte", soit texte[0].
// Autrement dit, pointeur_de_char contient l'adresse (&) de texte[0].

//for(sec = -1000000; sec <= 1000000; sec = sec + 0.5)   // sec déclarée en float. OK.
//for(sec = -8000000; sec <= 8000000; sec = sec + 0.5)   // sec déclarée en float. OK.
//for(sec = -8379999; sec <= 8379999; sec = sec + 0.5)   // sec déclarée en float. OK (maxi).
for(sec = -9000000; sec <= 9000000; sec = sec + 0.5)     // sec déclarée en float. FAIL.
{
portc.b2 = 1;                                        // LED yellow ON.

strConstRamCpy(pointeur_de_char, "Counting ...");    // OK.
LCD_CString_Position_v2(1, 0, pointeur_de_char);     // OK. Voir dans void LCD_Write_CString_v2(char *msg), le while(*(msg + k) > 0).

float_to_ASCII_with_2_decimal_v7(sec, txt);

LCD_CString_Position_v2(2, 0, txt);                  // Write txt in 2nd row, starting at 1st digit.
LCD_CString_Position_v2(2, 13, "uS");                // Write "uS" in 2nd row, starting at 14th digit

Delay_us(1);
//Delay_ms(1000);
}

portc.b2 = 0;                                            // LED yellow OFF.
portc.b3 = 1;                                            // LED green ON.
portc.b4 = 1;                                            // BUZZER ON.
Delay_ms(5000);
portc.b3 = 0;                                            // LED green OFF.
portc.b4 = 0;                                            // BUZZER OFF.
}
}

Last edited by a moderator:

#### paulfjujo

hello,

i digit more needs to shift all the other calculus..

Code:
void float_to_ASCII_with_2_decimal_v5(float fx, char *pt)
{
unsigned long e = 0; // 0 to  <= 9 999 999
unsigned long d = 0;
float f0, chiffre_decimal=0.0;
int k=0;
if (fx < 0)
{
*(pt) = '-';     //  0cx2D
chiffre_decimal=-fx;
}
else
{
*(pt) = '+'; // 0x2B signe +
chiffre_decimal=fx;
}
e =(unsigned long)  floor(chiffre_decimal); // Partie entière.
d =(chiffre_decimal - (float)e) * 100; // Partie décimale (2 chiffres);
// Partie entière de 9 999 999 à 0 :
if (e/1000000L >= 0) *(pt+1) =(unsigned char) (e/1000000L) + 0x30;
e = e%1000000L;    // 1 000 000
if (e/100000L >= 0) *(pt+2) =(unsigned char) (e/100000L) + 0x30;
e = e%100000L;    // 100 000
if (e/10000 >= 0) *(pt+3) = (unsigned char) (e/10000) + 0x30 ;
e = e%10000L; // 10 000
if (e/1000L >= 0) *(pt+4) = (unsigned char) (e/1000L) + 0x30;
e = e%1000L;
if (e/100L >= 0) *(pt+5) =(unsigned char)  (e/100L) + 0x30;
e = e%100L;
if (e/10L >= 0) *(pt+6) =(unsigned char)  (e/10L) + 0x30;
*(pt+7) = (unsigned char) (e%10L) + 0x30;
*(pt+8) = 0x2C ; // Virgule au lieu d' un point.
*(pt+9)= (unsigned char) (d/10) + 0x30; // Partie décimale de 99 à 0 :
*(pt+10) = (unsigned char) (d%10) + 0x30;
*(pt+11)= 0;
// maintenant on arrange en supprimant les zeros inutiles
if (*(pt+1)=='0')
{
*(pt+1)=' ';
if (*(pt+2)=='0')
{
*(pt+2)=' ';
if (*(pt+3)=='0')
{
*(pt+3)=' ';
if (*(pt+4)=='0')
{
*(pt+4)=' ';
if (*(pt+5)=='0')
{
*(pt+5)=' ';
}
if (*(pt+6)=='0')
{
*(pt+6)=' ';
}
}
}
}
}
}

mistake was here, so after
*(pt + 1) = ' ';
if (e/1000000 >= 0) *(pt + 2) = (unsigned char) (e/1000000) + 0x30; // Partie entière de 9999999 à 0.

*(p+2); <-- bad must be *(p+1) .. and so on for other pointer value

### Eric_O

Points: 2

#### Eric_O

##### Member level 4
hello,

i digit more needs to shift all the other calculus..

Code:
void float_to_ASCII_with_2_decimal_v5(float fx, char *pt)
{
unsigned long e = 0; // 0 to  <= 9 999 999
unsigned long d = 0;
float f0, chiffre_decimal=0.0;
int k=0;
if (fx < 0)
{
*(pt) = '-';     //  0cx2D
chiffre_decimal=-fx;
}
else
{
*(pt) = '+'; // 0x2B signe +
chiffre_decimal=fx;
}
e =(unsigned long)  floor(chiffre_decimal); // Partie entière.
d =(chiffre_decimal - (float)e) * 100; // Partie décimale (2 chiffres);
// Partie entière de 9 999 999 à 0 :
if (e/1000000L >= 0) *(pt+1) =(unsigned char) (e/1000000L) + 0x30;
e = e%1000000L;    // 1 000 000
if (e/100000L >= 0) *(pt+2) =(unsigned char) (e/100000L) + 0x30;
e = e%100000L;    // 100 000
if (e/10000 >= 0) *(pt+3) = (unsigned char) (e/10000) + 0x30 ;
e = e%10000L; // 10 000
if (e/1000L >= 0) *(pt+4) = (unsigned char) (e/1000L) + 0x30;
e = e%1000L;
if (e/100L >= 0) *(pt+5) =(unsigned char)  (e/100L) + 0x30;
e = e%100L;
if (e/10L >= 0) *(pt+6) =(unsigned char)  (e/10L) + 0x30;
*(pt+7) = (unsigned char) (e%10L) + 0x30;
*(pt+8) = 0x2C ; // Virgule au lieu d' un point.
*(pt+9)= (unsigned char) (d/10) + 0x30; // Partie décimale de 99 à 0 :
*(pt+10) = (unsigned char) (d%10) + 0x30;
*(pt+11)= 0;
// maintenant on arrange en supprimant les zeros inutiles
if (*(pt+1)=='0')
{
*(pt+1)=' ';
if (*(pt+2)=='0')
{
*(pt+2)=' ';
if (*(pt+3)=='0')
{
*(pt+3)=' ';
if (*(pt+4)=='0')
{
*(pt+4)=' ';
if (*(pt+5)=='0')
{
*(pt+5)=' ';
}
if (*(pt+6)=='0')
{
*(pt+6)=' ';
}
}
}
}
}
}

mistake was here, so after
*(pt + 1) = ' ';
if (e/1000000 >= 0) *(pt + 2) = (unsigned char) (e/1000000) + 0x30; // Partie entière de 9999999 à 0.

*(p+2); <-- bad must be *(p+1) .. and so on for other pointer value

Bonsoir Paul !
“Mais c’est bien sûr !” 😁😁😁
So smart !
Merci beaucoup.
Your codes and explanations helps me very much.
🏆

#### Eric_O

##### Member level 4
Bonsoir Paul,

I tried your code today. Finally it doesn’t run as expected. The LCD still freezes at -9000000,00.
Aim of instruction *(pt + 1) = ' '; in my code was to keep one space between « - » and first digit.

What is aim of the « L » after zeros ?

Hope you will enlighten me again !

Merci !

Bonne nuit !

Eric

#### betwixt

##### Super Moderator
Staff member
What is aim of the « L » after zeros ?
It indicates the value should be interpreted as a 'long'. A hint to the compiler that even if the number is small, it should still reserve enough space for a 'long' sized number.

Brian.

#### FvM

##### Super Moderator
Staff member
No doubt that a hand written conversion code as presented can solve the problem. The code size will be probably considerably larger than a regular printf library call, and much larger than a specifically taylored double dabble algorithm.

#### Aussie Susan

@FvM - re your comment about the printf: I don't know about the MikroC computer the OP is using but the 'printf' library functions are typically very big as they need to do run-time parsing of the format string and then call any of the possible conversion routines. This can be a real problem for the PIC16F sized devices - the PIC16F887 only has 8192 words of FLASH. a hand-written function is generally the only way to go. (I know the XC8 compiler tries to get around this by parsing the format string - which are typically string literals! - and only including the required library functions; even so they can take up a lot of the very limited space.
The limited space on these devices is why floats are also discouraged - they must be handled by library functions as there is no hardware multiplier even for integers. Scaled integers are the best way to go.
Susan

#### betwixt

##### Super Moderator
Staff member
Like Susan, I 'm not sure about MikroC library flexibility or size, I don't think it even runs under my OS (Linux).
However, there may be a different approach to this, look at the link below, it converts a long to ASCII using just a few bytes in assembly code and does it in a smaller processor than the '887. The principle, if not the source code itself, should be adaptable for this need.

Brian.

#### Eric_O

##### Member level 4
It indicates the value should be interpreted as a 'long'. A hint to the compiler that even if the number is small, it should still reserve enough space for a 'long' sized number.

Brian.
Bonjour Brian,
Oh ! I see.
Merci beaucoup for explanation.
Eric

#### paulfjujo

hello,
if you want to add a space between '-' and first digit , you must shift all other pointers values
for the digits, and increase the size of buffer by 1 ...

#### Eric_O

##### Member level 4
hello,
if you want to add a space between '-' and first digit , you must shift all other pointers values
for the digits, and increase the size of buffer by 1 ...
Bonsoir Paul,

I did that in the code. All pointer values of *pt are increased by 1. Problem seems more difficult because counting runs for the following ranges in the code ... with a space between “-“ and first digit.
And buffer txt is set to 13.
- 9000000,00 with /0 for end of string makes 13 characters.
...
//for(sec = -1000000; sec <= 1000000; sec = sec + 0.5) // OK.
//for(sec = -8000000; sec <= 8000000; sec = sec + 0.5) // OK.
//for(sec = -8379999; sec <= 8379999; sec = sec + 0.5) // OK (maxi range).
for(sec = -9000000; sec <= 9000000; sec = sec + 0.5) // FAIL.
...

Eric

#### paulfjujo

If it was working without the additional space , no reason to fail .. except an additonnal bug
Are you also adding a space for positive number ?
between signe + and 1rst digit
nota : my tests were made with UART -> terminal , not with LCD..
post your code ... i will have a look ..

#### Eric_O

##### Member level 4
If it was working without the additional space , no reason to fail .. except an additonnal bug
Are you also adding a space for positive number ?
between signe + and 1rst digit
nota : my tests were made with UART -> terminal , not with LCD..
post your code ... i will have a look ..
Bonsoir Paul,

Here the code.

Merci beaucoup.

C:
// LCD module connections :LCD module connections :
// VSS (pin  1) -> GND
// VDD (pin  2) -> VCC
// VEE (pin  3) -> middle pin contrast potentiometer
sbit LCD_RS at RB4_bit;                 // RS  (pin  4) -> portB.b4 (pin 37)
// RW not used.                         // RW  (pin  5) -> GND
sbit LCD_EN at RB5_bit;                 // EN  (pin  6) -> portB.b5 (pin 38)
// D0  (pin  7) -> GND
// D1  (pin  8) -> GND
// D2  (pin  9) -> GND
// D3  (pin 10) -> GND
sbit LCD_D4 at RB0_bit;                 // D4  (pin 11) -> portB.b0 (pin 33)
sbit LCD_D5 at RB1_bit;                 // D5  (pin 12) -> portB.b1 (pin 34)
sbit LCD_D6 at RB2_bit;                 // D6  (pin 13) -> portB.b2 (pin 35)
sbit LCD_D7 at RB3_bit;                 // D7  (pin 14) -> portB.b3 (pin 36)
//     (pin 15) -> GND
//     (pin 16) -> GND

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

/******************************************************************************/

// Declaration of variables :

float chiffre_decimal, sec;                                       // - 1.5 x 10 puissance 45 to + 3.4 x 10 puissance 38
char texte[64], *pt;                                              // 0 to 255

/******************************************************************************/

// Routines :

void LCD_E_pulse(void)
{
LCD_EN = 1;
Delay_us(5);
LCD_EN = 0;
Delay_us(5);
}

void LCD_Write_Cmd(unsigned char octet)                           // Version 3 : OK.
{
LCD_RS = 0;                                                      // Select Command Register.
// Send upper nibble.
LCD_D4 = ((octet & 0x10) == 0x10) ? 1 : 0;                       // Si ((octet & 0x10) == 0x10) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x20) == 0x20) ? 1 : 0;                       // Si ((octet & 0x20) == 0x20) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x40) == 0x40) ? 1 : 0;                       // Si ((octet & 0x40) == 0x40) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x80) == 0x80) ? 1 : 0;                       // Si ((octet & 0x80) == 0x80) alors LCD_D7 = 1 sinon = 0.
LCD_E_Pulse();
// Send lower nibble.
LCD_D4 = ((octet & 0x01) == 0x01) ? 1 : 0;                       // Si ((octet & 0x01) == 0x01) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x02) == 0x02) ? 1 : 0;                       // Si ((octet & 0x02) == 0x02) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x04) == 0x04) ? 1 : 0;                       // Si ((octet & 0x04) == 0x04) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x08) == 0x08) ? 1 : 0;                       // Si ((octet & 0x08) == 0x08) alors LCD_D7 = 1 sinon = 0.
LCD_E_Pulse();
}

void LCD_Write_Data(char octet)                                   // Version 2 : OK.
{
LCD_RS = 1;                                                      // Select Data Register.
// Send upper nibble.
LCD_D4 = ((octet & 0x10) == 0x10) ? 1 : 0;                       // Si ((octet & 0x10) == 0x10) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x20) == 0x20) ? 1 : 0;                       // Si ((octet & 0x20) == 0x20) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x40) == 0x40) ? 1 : 0;                       // Si ((octet & 0x40) == 0x40) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x80) == 0x80) ? 1 : 0;                       // Si ((octet & 0x80) == 0x80) alors LCD_D7 = 1 sinon = 0.
LCD_E_Pulse();
// Send lower nibble.
LCD_D4 = ((octet & 0x01) == 0x01) ? 1 : 0;                       // Si ((octet & 0x01) == 0x01) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x02) == 0x02) ? 1 : 0;                       // Si ((octet & 0x02) == 0x02) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x04) == 0x04) ? 1 : 0;                       // Si ((octet & 0x04) == 0x04) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x08) == 0x08) ? 1 : 0;                       // Si ((octet & 0x08) == 0x08) alors LCD_D7 = 1 sinon = 0.
LCD_E_Pulse();
}

void strConstRamCpy(unsigned char *dest, const code char *source) // Copie le texte de la FLASH ROM vers la RAM.
{
while (*source)*dest ++ = *source ++;
*dest = 0;                                                       // Terminateur "0" fin de chaine de caractère.
}

void LCD_Write_CString_v2(char *msg)                              // Variante avec pointeur msg non modifié.
{
int k;
k = 0;
//while(*(msg) > 0)                                              // FAIL.
while(*(msg + k) > 0)                                            // OK.
{
LCD_Write_Data(*(msg + k));                                     // Data pointée par (msg + k).
k++;
if (k > 15) break;                                              // Si k > 15 sortie de la boucle while ...
}
}

void LCD_CString_Position_v2(char row, char col, char *msg)       //
{
if (row == 1)
{
LCD_Write_Cmd((col & 0x0F)|0x80);                            // Print message on 1st row and desired location.
}
else if (row == 2)
{
LCD_Write_Cmd((col & 0x0F)|0xC0);                            // Print message on 2nd row and desired location.
}
LCD_Write_CString_v2(msg);                                       // OK.
}

void float_to_ASCII_with_2_decimal_v7(float fx, char *pt)
{
unsigned long e = 0;                                                 // 0 to 4294967295.
unsigned long d = 0;                                                 // 0 to 4294967295.
float chiffre_decimal = 0.0;

if (fx < 0)
{
*(pt) = '-';
chiffre_decimal = - fx;
}
else
{
*(pt) = ' ';
chiffre_decimal = fx;
}

e = (unsigned long) floor(chiffre_decimal);                          // Partie entière.
d = (chiffre_decimal - (float)e) * 100;                              // Partie décimale (2 chiffres).

*(pt + 1) = ' ';              // Keep a space between sign and first digit.

if (e/1000000 >= 0) *(pt + 2) = (unsigned char) (e/1000000) + 0x30;  // Partie entière de 9999999 à 0.
e = e%1000000;
if (e/100000 >= 0) *(pt + 3) = (unsigned char) (e/100000) + 0x30;
e = e%100000;
if (e/10000 >= 0) *(pt + 4) = (unsigned char) (e/10000) + 0x30;
e = e%10000;
if (e/1000 >= 0) *(pt + 5) = (unsigned char) (e/1000) + 0x30;
e = e%1000;
if (e/100 >= 0) *(pt + 6) = (unsigned char) (e/100) + 0x30;
e = e%100;
if (e/10 >= 0) *(pt + 7) = (unsigned char) (e/10) + 0x30;
*(pt + 8) = (unsigned char) (e%10) + 0x30;
*(pt + 9) = 0x2C;                                                    // Virgule au lieu d'un point.
*(pt + 10) = (unsigned char) (d/10) + 0x30;                          // Partie décimale de 00 à 99.
*(pt + 11) = (unsigned char) (d%10) + 0x30;
*(pt + 12) = 0;

if (*(pt + 2) == '0')                                                // Suppression des zéros inutiles.
{
*(pt + 2) = ' ';
if (*(pt + 3) == '0')
{
*(pt + 3) = ' ';
if (*(pt + 4) == '0')
{
*(pt + 4) = ' ';
if (*(pt + 5) == '0')
{
*(pt + 5) = ' ';
if (*(pt + 6) == '0')
{
*(pt + 6) = ' ';
if (*(pt + 7) == '0')
{
*(pt + 7) = ' ';
}
}
}
}
}
}
}

void LCD_Init_v4 (void)                                           // OK.
{
Delay_sms(15);                                                    // LCD power ON initialization time >= 15 mS.
LCD_Write_Cmd(0x30);                                             // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).
LCD_Write_Cmd(0x02);                                             // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).
LCD_Write_Cmd(0x28);                                             // 4 datas bits > 2 lines display, 5 × 8 dot character font.
LCD_Write_Cmd(0x0C);                                             // 4 datas bits > Display ON. Cursor OFF.
LCD_Write_Cmd(0x06);                                             // 4 datas bits > Auto increment cursor.
LCD_Write_Cmd(0x01);                                             // 4 datas bits > Clear display.
Delay_ms(1);                                                     // Ajustable ...
}

/******************************************************************************/

// Main program :

void main()
{
ANSEL = 0;                                                // Configure AN pins as digital I/O.
ANSELH = 0;
C1ON_bit = 0;                                             // Disable Comparator 1.
C2ON_bit = 0;                                             // Disable Comparator 2.

PORTB = 0;
TRISB = 0;
PORTC = 0;
TRISC = 0;

// Essai 16.2 : DEBUGGING ...

Lcd_Init_v4();                                            // Initialize LCD.

while(1)                                                  // Endless loop.
{
unsigned char *pointeur_de_char;                         // Déclaration d'un pointeur (*) de char "pointeur_de_char".
//char texte[] = "Counting ...";                         // Déclaration d'un tableau "texte" de type char et initialisé avec la chaine de caractères "Counting ..." :
// En n'indiquant aucun chiffre entre les cochets [], le compilateur ajustera automatiquement la taille du
// tableau, et allouera en mémoire RAM, le bon nombre d'éléménts, soit 13 ...
char txt[13];
pointeur_de_char = &texte[0];                            // pointeur_de_char pointe sur le premier élément du tableau "texte", soit texte[0].
// Autrement dit, pointeur_de_char contient l'adresse (&) de texte[0].

//for(sec = -1000000; sec <= 1000000; sec = sec + 0.5)   // sec déclarée en float. OK.
//for(sec = -8000000; sec <= 8000000; sec = sec + 0.5)   // sec déclarée en float. OK.
//for(sec = -8379999; sec <= 8379999; sec = sec + 0.5)   // sec déclarée en float. OK (maxi).
for(sec = -9000000; sec <= 9000000; sec = sec + 0.5)     // sec déclarée en float. FAIL.
{
portc.b2 = 1;                                        // LED yellow ON.

strConstRamCpy(pointeur_de_char, "Counting ...");    // OK.
LCD_CString_Position_v2(1, 0, pointeur_de_char);     // OK. Voir dans void LCD_Write_CString_v2(char *msg), le while(*(msg + k) > 0).

float_to_ASCII_with_2_decimal_v7(sec, txt);

LCD_CString_Position_v2(2, 0, txt);                  // Write txt in 2nd row, starting at 1st digit.
LCD_CString_Position_v2(2, 13, "uS");                // Write "uS" in 2nd row, starting at 14th digit

Delay_us(1);
//Delay_ms(1000);
}

portc.b2 = 0;                                            // LED yellow OFF.
portc.b3 = 1;                                            // LED green ON.
portc.b4 = 1;                                            // BUZZER ON.
Delay_ms(5000);
portc.b3 = 0;                                            // LED green OFF.
portc.b4 = 0;                                            // BUZZER OFF.
}

}

Last edited by a moderator:

Status
Not open for further replies.