PIC16F > LCD locked at - 9000000,00 ...

Status
Not open for further replies.

kawauso

New Member
Dear coders,

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.

Thanks.

Here under is the code :

Code:
Code :

// 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.
}

}
 
What compiler is is?

I'm guessing the "float" data type does not have sufficient resolution to handle that size of number to integer resolution.
Remember a float can only store a limited number of digits, with a shift either way from the decimal point.

eg. If the float format used a mantissa with 23 bits plus sign & no implied 1 bit, the highest positive value to integer resolution would be 8,388,607

If you are only counting integers, an unsigned long would probably be more appropriate? That would give you 31 bits integer, plus sign.
Either that or a double.
 
Thanks for your reply.
Interesting. I almost understood all.
The compiler is MikroC.
I learnt that with 16F I can not use printf ...
And would prefer to write my one routines first instead of using first the MikroC Library for my understanding.
 
A float is a number stored in the binary version of scientific notation, like 2.4 x 10^12
For a common 32 bit form, it typically stores somewhere from six to nine digits of the number accurately, plus an offset from the decimal point (or binary point).

A long is just a simple 32 bit binary number. Using signed form, it can store any value from −2,147,483,647 to +2,147,483,647

If you are working with integers rather than fractions, it's a much better type to use for your application.

More info:
 
I learnt that with 16F I can not use printf ...

You certainly can, but as with every processor it's heavy on resources - likewise using floating point is heavy on resources - I rarely use either, and integer maths is much lighter on resources, vastly faster and more accurate as well.

Essentially, if you were doing maths on money - use pennies and not pounds and pennies (so instead of £5.23 use 523 pence instead, and add the decimal point back in your display routine.
 
I too would use a long integer. You can display it using itoa(), first divide by 2, itoa() it, print it and if the integer has bit 0 set then add .5 to the display - you could also add .0 if not set if you wanted.

Mike.
Edit, is there a 32 bit equivalent of itoa() on that compiler?
 
Last edited:
I was bored so thought I'd have a go at this and realised where your problem is,
The line,
for(sec = -9000000; sec <= 9000000; sec = sec + 0.5)
is the problem as -900000 is less than 9000000.

I had an Arduino hooked up and did the following,
Code:
void setup(){
}

int32_t count;

void loop(){
  Serial.begin(115200);
  while(1){
    for(count=-18000000;count!=18000001;count++){
      Serial.print("Count = ");
      Serial.print(count/2,DEC);
      if(count&1){
        Serial.print(".5");
      }else{
        Serial.print(".0");
      }
      Serial.println();
    }
    Serial.println("Done!");
  }
}

Note the for loop end condition.
Obviously the above will only work if your compiler will print a signed 32 bit integer.

Mike.
 
The middle condition is "while", in effect; think of a commoner range, eg.

for(sec = 0; sec <= 10; sec = sec + 1){}

It's a limitation of the float resolution, the 0.5 increment is smaller than the float can hold with a number of that magnitude; it needs more than 24+sign once the values exceed eight millions and something.

The OP says the code works in the eight million range, but not when increased to nine million.

Yours works as it's using a 32 bit long, which has 31 bit plus sign.
 
for(sec = -9000000; sec <= 9000000; sec = sec + 0.5)
is the problem as -900000 is less than 9000000.
That is the correct syntax.... for( sec = -900000; while sec <= to 900000 ; add0.5 to sec)... Yep.. That's how its done.
I still don't think some micros can use floats on for loops...
 
Yup, not sure what I was thinking there.
Still surprised at the difference in length of float -v- integer code.

Mike.
 
Merci for clear explanation.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…