Go Down

Topic: Arithmetic Operator question (Read 999 times) previous topic - next topic

HULK

Code: [Select]

int Z;

float GZ = analogRead(Z)*0.0048828125 - 1.66;


Hope somebody can help me to understand what is wrong with the above piece of code.
As you know an analog reading is a number between 0-1023.
So let us assume that analogRead(Z) is at a given time 250, that in multiplication with 0.0048828125 will return 1.220703125.
Then 1.220703125 - 1.66 should return -0.439296875.
But it does return a positive number of 0.439296875.
The intresting part to me is that if we go below -1.000 then the value return from the same code will return the correct negativ value of
-1.000.  :-?

This is a part of a bigger code that calculates a analog g-sensor value in to volts and then to g force. Therfore 5/1024 = 0.0048828125 for volt calculation.

mikalhart

hulk,

Assuming Z is an uninitialized automatic (stack) variable and you are reading from pin Z, you are (potentially) reading from an undefined pin.  Therefore the return from analogRead is unpredictable.

The expression assigned to GZ works fine as long as analogRead() is indeed returning a number between 0 and 1023.

Mikal


mem

Hi Hulk, I suspect the problem is elsewhere in your code if the only problem is the sign.

Not sure it will help in your app, but wherever possible I like to convert floating point values to longs by multiplying the value by the number of decimal places necessary to give you the precision you need. This allows the code to be smaller and faster.

The following gives GZ that is the actual value times 10,000.  

long GZ = analogRead(Z)*488 - 166000;

HULK

mikalhart,

You are correct, in my case it is defined so the value is being 0-1023, i can see the value of let us say 250 just by doing a simple serial print command.
In my case the pin is: int Z = 5;
Any other thoughts or did i missunderstand your reply ?

mikalhart

Why do you suspect that the sign is wrong?  I did a local test and it worked fine for all possible values 0-1023.  Like mem, I suspect the problem is elsewhere.

Mikal

HULK

m & m

I have tested and edited my code to get some good results, but...
I did try the long command and it was returning me negative numbers all the time. Could it be the printDouble function i am using or just me as usuall  :) .
One code below that can be used with serial.print and one with the KS0108 library.

This one will run to 0.3 and then just jump to -1
Code: [Select]


 int X = 5;

//////////////////////////////////////////////////////////////////////////
void printDouble( double val, unsigned int precision){

   Serial.print (int(val));  //prints the int part
   Serial.print("."); // print the decimal point
   unsigned int frac;
   if(val >= 0)
     frac = (val - int(val)) * precision;
   else
      frac = (int(val)- val ) * precision;
   int frac1 = frac;
   while( frac1 /= 10 )
       precision /= 10;
   precision /= 10;
   while(  precision /= 10)
       Serial.print("0");
   Serial.println(frac,DEC) ;
}
//////////////////////////////////////////////////////////////////////////


void setup(){

Serial.begin(9600);

}


void loop(){

 float GX = analogRead(X)*0.0048828125 - 1.66;
 GX = GX / 0.333;
 printDouble(GX, 4);
 delay(100);
 
 }


This one will go all the way from 0-0.99 and then suddenly go to correct negativ value of -1.0.....
Code: [Select]


#include <Arial14.h>
#include <ks0108.h>

 int X = 5;
 
///////////////////////////////////////////////////////////////////////////////////// printDouble
void printDouble( double val, byte precision){
 // prints val with number of decimal places determine by precision
 // precision is a number from 0 to 6 indicating the desired decimial places
 // example: printDouble( 3.1415, 2); // prints 3.14 (two decimal places)

 GLCD.PrintNumber( (long)val);  //prints the int part
 if( precision > 0) {
   GLCD.PutChar('.');
   unsigned long frac;
   unsigned long mult = 1;
   byte padding = precision -1;
   while(precision--)
      mult *=10;
     
   if(val >= 0)
     frac = (val - int(val)) * mult;
   else
     frac = (int(val)- val ) * mult;
   unsigned long frac1 = frac;
   while( frac1 /= 10 )
     padding--;
   while(  padding--)
     GLCD.PutChar('0');
   GLCD.PrintNumber(frac) ;
 }
}

float drawSine(int angle){
 float sine;
//    if(angle <= 0)  
       sine = sin(PI / 180 * angle);
 return sine;              
}
//////////////////////////////////////////////////////////////////////////


void setup(){
 
GLCD.Init(NON_INVERTED);
GLCD.SelectFont(Arial_14);
Serial.begin(9600);

}


void loop(){

 float GX = analogRead(X)*0.0048828125 - 1.66;
 GX = GX / 0.333;
 GLCD.FillRect(04, 45, 100, 15, WHITE);
 GLCD.GotoXY(05, 45);
 printDouble(GX, 2);
 delay(100);
 
 }



Good to have you back mem and thanks for the fast reply mikalhart!

mem

#6
Oct 22, 2008, 11:40 pm Last Edit: Oct 23, 2008, 12:01 am by mem Reason: 1
For your serial output, try the code in reply #6: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1207226548

The GLCD version is due to a 'feature' in the library. The PrintNumber integer print routine does not put a sign if the value is 0, which it will be when value is less than 1. But the fractional part of the print routine assumes the sign has been printed.

A temporary hack is to add the following before the call to GLCD.PrintNumber
[font=Courier New]if ( val > -1.0 && val < 0)
   GLCD.PutChar('-'); [/font]

A better fix is to always print a minus sign on negative values and pass the abs value to PrintNumber

I am not quite back, I return to the UK on the weekend

HULK

Mem,

I see, thanks.
Will there possibly be a change of the KS0108 library in the future or the temporary solution is here to stay ?

mem

I will include the fix in the next version of the library

Go Up