Please help with multiplying irrational numbers. volt meter project!
I am using an eight bit a/d converter to check the voltage on a circuit. I am very close my calculations are just a little off and I do not know why. I am pretty sure that the problem is in line 56 of my code.
The a/d converter has 255 steps between ground and 5v, so to obtain the proper voltage I must divide 5 by 255 this gives me the amount of voltage that each step is worth. Now if I take the number coming from the a/d converter and multiply it by (5/255) then it should in theory give me the correct voltage reading. But I just can't get it to work this way.
If anyone has any suggestions for how I can fix this problem please help me out.
The a/d converter has 255 steps between ground and 5v, so to obtain the proper voltage I must divide 5 by 255 this gives me the amount of voltage that each step is worth. Now if I take the number coming from the a/d converter and multiply it by (5/255) then it should in theory give me the correct voltage reading. But I just can't get it to work this way.
If anyone has any suggestions for how I can fix this problem please help me out.

Comments
the ADC reading has a range of 0 to 255 (correct)
The volt_ calc should be the voltage reading it is off by + 2
How far are you off? do you have a voltage divider on the front of the ADC or anything else that might affect the result?
EDIT: Beau also touched on 256 and 255. Although 255 is the max count, and .0195 * 255 != 5 volts
So, even if the number has no fractionals you should call it with 5.0, 255.0 ....
I'm also not sure wheather your binaryToDecimal is correct. I'd expect that the float objects provide some functions to convert an integer to a float.
I don't see where the value "ADC_value" is every converted to a floating point number.
What program is "ADC_Driver"?
I don't see why you need the method "BinaryToDecimal"?
Binary and decimal numbers are just to make it easier for us humans to read them. Normally they are stored the same in the uC's memory.
I bet you don't need a floating point object at all. I think all your math could be done as pseudoreal (you might want to try "pseudo-real" and "pseudo real" with your search).
this is much closer but still off now at ADC_value 255 the Volt_calc is 5.6
Most ADC have a inaccuracy - for example 1 or 2 LSBs. This means that with 5V and 255 steps you have an inaccuracy of
0,01960784313725490196078431372549 which means that it's worthless to show more than 3 digits.
By simply using 500 as an equivalent of 5V you can use simple integer math to calculate your voltages.
I am new to programming most of the stuff you see in this code is copy, paste, modify. I only want to see 2 decimal places i just don't know how to do that yet.
What is a floating point decimal? sorry I don't mean to ask dumb questions I am new to programming.
Post #4 is a method I wrote to output an integer with a decimal point to make it look like a floating point number had been used.
-Phil
-Phil
If you use 50,000 / 255 you'll get 196 with the Prop. This should be a usable number.
You know 196 is really 0.0196 and you keep this in mind when you write the rest of your program.
If 196 was stored in the variable "value", you could display it with a decimal point using the method (linked to earlier) "DecPoint" by calling it like this:
You'd use the number "10000" since that what you multiplied "5" by to get "50000".
There's more discussion about pseudo real numbers in that thread.
Floating point numbers are stored differently in the Propeller's memory than the way normal integers are stored. You can't mix the two with math functions. You also can't use normal Spin math and comparisons with floating point numbers (if you want the answers to be meaningful).
Edit: codeviper's calculator is a good example of using floating point numbers. He made the common mistake of mixing integer math operators with floating point operators in his expoent function "^". The rest of the functions work correctly.
The problem has to be in line 57 or 61!
Keep in mind volt_calc:= ACD_value*volt_step
table of output:
ADC_value volt_step volt calc
0 0.01960784 0
20 0.01960784 0
40 0.01960784 0
.................................................. .........
50 0.01960784 0
51 0.01960784 1.40
.................................................. ............
101 0.01960784 1.40
102 0.01960784 2.8
.................................................. ..........
152 0.01960784 2.8
143 0.01960784 4.2
.................................................. .........
203 0.01960784 4.2
204 0.01960784 5.6
...........................................
255 0.01960784 7.0
I have tried 3 times to space the numbers out and it keeps pushing them to the left in the table sorry!
This is my problem this only puts out an integer I need a number with 2 decimal places.
how do i fix this?
Floating point numbers are stored differently the integers.
While all numbers are stored as one and zeros, floating point numbers use the 32 bits differently (I don't really worry about it myself, I just know I can't mix integers and floating point numbers without converting one to the other first).
Different Topic:
Binary, hexadecimal and decimal numbers are just ways of displaying numbers for us humans. The Propeller stores them the same way (excluding floating point numbers).
The method "BinaryToDecimal" copies a number one bit at a time and returns the copied number. Since it only copies eight bits, the only numbers it will change are numbers larger than 255.
You could do the same thing with.
The above code will zero out all but the lowest 8 bits.
Just to be sure I wrote a quick demo of "BinaryToDecimal".
CON _CLKMODE = XTAL1 + PLL16X _CLKFREQ = 80_000_000 _DebugBaud = 57_600 OBJ Debug : "Parallax Serial Terminal" PUB Main | localIndex waitcnt(clkfreq * 3 + cnt) ' time to open terminal window. Debug.Start(_DebugBaud) Debug.Clear repeat localIndex from 0 to 255 Debug.Str(string(13, "localIndex before conversion = ")) Debug.dec(localIndex) result := BinaryToDecimal(localIndex) Debug.Str(string(13, "localIndex after BinaryToDecimal conversion = ")) Debug.dec(result) repeat PUB BinaryToDecimal(aBinVal) : rVal | multiplier, bitMask rVal := 0 'empty returned val multiplier := 1 'start with multiplier of 1 bitMask := 1 'start with bitMask of 1 (LSB) repeat 8 'repeat for all 8 bits if aBinVal & bitMask > 0 'if bit at position of bitMask is 1 rVal += multiplier 'add multiplier to aVal multiplier *= 2 'double value of multiplier bitMask := bitMask << 1 'move bit in bitMask to left return rValHere's a portion of the output.
So you don't need the method. I don't think you need to "and" the value either.
The main problem you're having is not keeping floating point numbers and integer numbers separate. One has to be converted to the other before you can do math with them.
Thanks this takes out a lot of stuff that i do not understand how to use and it works great! I have not figured out how to get a decimal point yet but i am still working on it.
This is awesome!!
I don't think you need it though.
I don't have an LCD setup nor do I have the LCD object you're using (in the right place for the Prop Tool to find it) so I couldn't even compile the code below.
I think the "Char" method is a private method in the LCD object you're using. You need to make it public by changing PRI to PUB.
Here's the code:
CON _clkmode = xtal1 + pll16x ' use crystal x 16 _xinfreq = 5_000_000 ' 5 MHz cyrstal (sys clock = 80 MHz) adcCS_Pin = 13 'pins used for ADC chip adcCLK_Pin = 15 adcDO_Pin = 14 INIT_OK = 0 OBJ lcd : "LCD_16X2_8BIT" ADC : "ADC_Driver" VAR byte ADC_value '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>adc value in dec can range from 1 to 255 long volt_calc '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>adc value multiplied by volt_step (volt step should = 5/255) long volt_step '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>should be equal to 5/255 this number repersents the voltage per 1 step of adc PUB ini lcd.start 'start junk lcd.move(1,1) lcd.str(string("kWH PROJECT")) lcd.move(1,2) lcd.str(string("WKU")) waitcnt(clkfreq*2 + cnt) volt_step := 50000 / 255 main pub main | rcLCD, rcADC lcd.clear lcd.move(1,1) lcd.str(string("volts")) rcADC := ADC.Init(adcCS_Pin, adcCLK_Pin, adcDO_Pin) if rcADC <> INIT_OK LCD.Str(string("ADC chip init err")) return repeat lcd.str(string(" ")) LCD.move(10, 1) ADC_value := ADC.GetConvertedVal 'get value from ADC (binary) volt_Calc := ADC_value * volt_step DecPoint(volt_Calc, 100000) waitcnt(clkfreq/2 + cnt) 'wait for 500ms PUB DecPoint(value, denominator) if value < 0 LCD.CHAR("-") -value if value => denominator result := value / denominator LCD.dec(result) value //= denominator else LCD.CHAR("0") LCD.CHAR(".") repeat while denominator > 1 denominator /= 10 if value => denominator result := value / denominator LCD.dec(result) value //= denominator else LCD.CHAR("0")Let me know if if works.
Edit: I see some of the comments wrapped around. You'll need to fix that. I'm editing this post to attach the Spin file. The file should now be attached. If the code doesn't work, use File\Achive\Project to zip all the objects together and post the zip file. This way I can be sure I'm using the same objects you're using.
Edit (July 12, 2012): I fixed a bug the DecPoint method above. I did not fix the bug in the attached version of the code. Thank you Gunstar1 for pointing it out.
This code displays 7 where it should display 5.