Go Down

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

#### HULK

##### Oct 22, 2008, 09:34 pm
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

#1
##### Oct 22, 2008, 09:53 pm
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

#2
##### Oct 22, 2008, 09:59 pm
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

#3
##### Oct 22, 2008, 10:01 pm
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;

#### mikalhart

#4
##### Oct 22, 2008, 10:07 pm
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

#5
##### Oct 22, 2008, 11:27 pm
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 pmLast Edit: Oct 23, 2008, 12:01 am by mem Reason: 1

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

#7
##### Oct 23, 2008, 06:19 pm
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

#8
##### Oct 23, 2008, 06:28 pm
I will include the fix in the next version of the library

Go Up