Problems with decimal values and displaying them. Please help!
RussM
Posts: 27
I am new to SPIN so I am sorry if this problem seems trivial to you all. I am working a project that using a rotary encoder to measure distance in thousands of an inch. What I want to do is each time the encoder value gets incremented, to add 0.000983 to my overall distance. When the encoder value gets decremented, i want to subtract 0.000983 from my overall distance. My problem is that I can't represent decimal values at all. I tried just writing the value 0.000983 to the screen and it printed out 981522434 instead. I tried utilizing the f32 object but to no avail. Any help would be greatly appreciated!
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 '_xinfreq = 6_250_000 TX_PIN = 0 BAUD = 19_200 'MS_001 = CLK_FREQ / 1_000 'CLK_FREQ = ((_clkmode-xtal1)>>6)*_xinfreq LCD_PIN = 27 LCD_BAUD = 19_200 LCD_LINES = 4 LCD_COLS = 20 ENCODER_PIN = 4 OBJ quad : "QuadDecoder" LCD : "FullDuplexSerial" f32 : "F32" f32_orig : "Float32Full" fs : "FloatString" VAR long offset ' example variable that will be accumulated to long distance long temp long distance_tick long f1 long fA PUB main LCD.start(TX_PIN, TX_PIN, 00, 19_200) 'Initialize FullDuplexSerial.spin f32.start f32_orig.start offset := 0 ' initialize the accumulator ' You can set it to any desired value LCD.tx($0C) quad.start(ENCODER_PIN, @offset) ' start the encoder reader LCD.str(string("Value = ")) LCD.tx($0D) LCD.str(string("Distance = ")) distance_tick := 0.000983 distance := 0 temp := 25 repeat if offset > temp distance := distance + distance_tick if offset < temp distance := distance - distance_tick LCD.tx($89) LCD.dec(offset) 'Encoder always initializes at 25 for some reason LCD.tx(32) LCD.tx($9F) LCD.dec(distance_tick) temp := distance waitcnt(clkfreq/10 + cnt)
Comments
You initialize some variables like distance to zero. It just so happens that a floating point zero is the same as the integer zero. It would be better from a documentation standpoint if you used 0.0 when you want to initialize a variable to zero for floating point use. There's a similar issue with temp and offset. You either need to convert distance to an integer using .FTrunc or .FRound to assign it to temp or you need to treat offset and temp as floating point throughout your program. That includes calling the floating point compare routine to compare the two values in your if statements.
If you don't want to use encoder pulses as the base unit, you use millionths of an inch as the unit instead of inches. Then your math could still be done with integers.
If using kwinn's method, you could do the conversion when needed (for display purposes) using millionths of inches in the calculation and then use the method "DecPoint" to place the decimal point in the desired position.
Here's the DecPoint method.
An example of how to use it can be found in post #4 of this thread.
( http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems )
An 32 bit integer can have the values ranging from 0 to 4,294,967,295 (unsigned). So, in your case you can use the least significant digits for the fraction and still have a range of 0-4,294. (I don't really understand how the offset and temp variables should work in your code. The offset is changed by the encoder and the code probably works fine when the encoder is turned slow and/or the code to calculate the new distance is fast enough. But in any other case the offset might have changed by a value that is equivalent to more than just one single distance_tick!)
The only thing you have to adapt is the dec-method which needs to insert a "." at the fixed position and start printing the number at least with 7 zeros (0.000000)!
If the range is not enough it's easy to add another long and do keep the fractional part in one long, the integer part in another.
I would calculate the distance in the encoder-code directly! The encoder code already has a loop to read the encoder and increment/decrement an offset. So, why add another loop (which wastes a COG) to convert the encoder ticks into a distance?
The "DecPoint" method I posted above does this for you.