PDA

View Full Version : Strugling without floating point



pjsmith
- 5th September 2004, 17:27
Hi,

I'm trying to build a pressure sensor (altimeter). I have a working circuit and a mpx pressure sensor. I have changed the ref voltages to get more resolution. I'm using a 16f877.

My problem is that I have worked out I get .002421875v per step (0 to 1024)+ the 2.47 ref. I'm currently measuring 671 from my a/d result. I've read about scalling up etc, but I'd exceed the limit of an integer with this?

I want to do

671 * 0.02421875

This must be possible, but maths is my stong point I am afraid! Could someone point me in the right direction?

Thanks.

Melanie
- 5th September 2004, 18:19
Your constant is 0.002421875... that's 10 significant figures... far too many for 16-bit math to cope with...

You've got the 0.002421875 value by taking your 2.48 VRef and dividing it by your 1024 bit resolution...

Let's forget all decimal places... and just stick to significant digits...

So now we have 2421875... that's down to 7 significant figures, but if you multiply this constant of yours by eight... you get 19375... five significant figures and an easy word variable to boot...

671 * 0.002421875 = 1.625078125

If now you take 671 and multiply it by our new constant of 19375 you get...

671 * 19375 = 13000625 (result)

But we are a factor of eight out... so use DIV32 to bring us back in line and simutaneously scale us back into the world of integers...

result / 800 = 16250 (a resultant easy 16-bit integer value).

so... by using this method, we end up with 1 and four decimal places (6250) which can be extracted with the DIG command.

At no time have we exceeded the limits for word integer math or the capabilities of PICBasic. Your best resolution with this method will be +/-0.0001 steps.

You can do a lot more math and get it better... but it's a first step on the path to enlightenment so to speak...

Melanie

Bruce
- 5th September 2004, 18:42
DEFINE LOADER_USED 1
DEFINE OSC 20
X VAR WORD
ADval VAR WORD
Quanta CON 6181 ' +Vref = 2.47V : Quanta=2.47V/1023*256=0.6181=6181

Begin:
FOR X = 1 TO 1023
ADval = X */ Quanta
HSEROUT ["Raw = ", DEC X, ": Result = ", dec ADval,13,10]
NEXT X
GOTO Begin

With +Vref at 2.47V, your resolution = 2.47V/1023 = 0.002414467

671 * 0.002414467 = 1.620V

If you run the above routine you'll see the values returned on any serial terminal while it simulates returned values with the dummy A/D input values.

Raw = 1: Result = 24
Raw = 2: Result = 48
Raw = 3: Result = 72
Raw = 4: Result = 96
Raw = 5: Result = 120
Raw = 6: Result = 144

144 represents 0.0144V

It's fairly close. 2.47V/1023*6=0.014486804. You loose some precision with the */ modifier returning only the middle 16-bits of the multiplication, but it's darn close for integer math.

<snip>

Raw = 668: Result = 16128
Raw = 669: Result = 16152
Raw = 670: Result = 16176
Raw = 671: Result = 16200
Raw = 672: Result = 16225
Raw = 673: Result = 16249
Raw = 674: Result = 16273
Raw = 675: Result = 16297
Raw = 676: Result = 16321
Raw = 677: Result = 16345
Raw = 678: Result = 16369
Raw = 679: Result = 16394
Raw = 680: Result = 16418

2.47V/1023*680=1.641837. Not too bad so far.

<snip>

Raw = 1020: Result = 24627
Raw = 1021: Result = 24651
Raw = 1022: Result = 24675
Raw = 1023: Result = 24699

2.47V/1023*1023=2.47V. 24699 is only 100uV off.

pjsmith
- 9th September 2004, 07:35
Thanks both of you for helpnig me with this. I've got it working (several versions!) and I think it's finally sinking in.

Glenn
- 19th April 2009, 02:29
Hmm.. borrowing this thread a bit..

I really hate math, especially when I constantly find myself struggling with float math when trying to do something in PBP.. It would be SOOOOO nice if this could be built into PBP, so I didnt have to use my brain for this kind of things.. this is what computers are supposed to be good at.

In my current program I would like to do:

calcpress = ((( pressure / Vs) - 0.04 ) / 0.00396 )

(Vs is the reference Voltage, 5v)

I really tried to understand what melanie wrote, knowing that it could solve this problem too, but nopes.. dont get it to work out..

I really would like to get a grip of this, coz when working with the ADC's I constantly get this kind of troubles when I want a "real" value calculated with the formula in the sensors datasheet, like in this case.

Please help :)

ScaleRobotics
- 19th April 2009, 09:18
In my current program I would like to do:

calcpress = ((( pressure / Vs) - 0.04 ) / 0.00396 )

There was a really nice program that someone, (Bruce I think) linked to somewhere in this forum. Ive been searching for it for about half an hour now, but I can't seem to re-find it. Anyway, it was very useful because it could change a fraction into numbers that the PIC can handle. For instance, if you entered .00396 it would show you a couple options like, 2/505, with some options being more accurate than others. Hopefully someone will chime in here and show us the light.

What you have to do (without the fraction calculator tool) is try to convert your decimal into a fraction. What I did was take 1 and divide it by .00396. The result was 252.52525. So, if you multiply both side by 2, you get 505.0505/2 or pretty close to 505/2. So 2/505 = .00396

Since you need to divide by .00396, that is the same as multiplying by 505/2

The left side of your equation is a little harder. I am going to assume you have a 10 bit a/d converter. So I am going to say your 5v = 1024. So your Pressure will be somewhere between 0 and 1024.

((Pressure * 1024) - 0.04) * (505/2)

now that .04 sure would be nice to get rid of. So we can multiply that by 25, but we will also have to divide it by 25, so we keep the number the same. We will also have to multiply Pressure by 25, since it too will be divided by 25.

http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3342&stc=1&d=1240128801

Acetronics2
- 19th April 2009, 09:31
Hi,

May be this one ??? ...

http://www.miscel.dk/MiscEl/miscel.html

Alain

ScaleRobotics
- 19th April 2009, 09:43
Hi,

May be this one ??? ...

http://www.miscel.dk/MiscEl/miscel.html

Alain

Exactly what I was looking for! Thanks Alain

Glenn
- 19th April 2009, 14:32
[ x8 Alot of interesting stuff cutted 8x ]

Since you need to divide by .00396, that is the same as multiplying by 505/2


Forgive me for being stupid, but how do I do that ? ( value * (505 /2 )) ?



The left side of your equation is a little harder. I am going to assume you have a 10 bit a/d converter. So I am going to say your 5v = 1024. So your Pressure will be somewhere between 0 and 1024.


Yes, the input is a pressure sensor and the vref for it is 5v, I also use a 10bit AD, so 5v = 1024 and 0v is 0.

My idea was to first convert this value to voltage, and put that value into the next step.

However this is a bit strange, coz if 5v == 1024, each step is 0.0048828125 . then a reading of 40 == 0.1953125, BUT, if I measure the output pin with a multimeter I get 0.205v ?

Ah, maybe its not really 5v I thought ? ..measured it, and ok, 4.97, that makes each step 0,004853515625, and then the value is 0,194140625 ? Hmm Hmm..

I also tried another multimeter, and that showed 0.20 (at the sensors output pin), so I guess thats not the problem.

But as I understand you I dont have to convert it first at all ?



((Pressure * 1024) - 0.04) * (505/2)

now that .04 sure would be nice to get rid of. So we can multiply that by 25, but we will also have to divide it by 25, so we keep the number the same. We will also have to multiply Pressure by 25, since it too will be divided by 25.


Hmm, ok, sounds logical..

To be sure that everything is clear here I'll try to describe what I'm tryiong to do in detail.

Basically I want to read a pressure sensor (Freescale MPX4250D) with my pic (PIC16F877A) using a analog pin (AN5) with a 10bit AD-converter. I want the value in kPa or Bar.

Reading the Pressure sensors datsheet I found:

Vout = Vs* (0.00369*P + 0.04) ± Error

..Wich I thought would be the same as

calcpress = ((( pressure / Vs ) - 0.04 ) / 0.00396 )

..I can be wrong here, I'm not very fond of math, and it was many years ago I used my (nearly not existing) mathskills..

Also, if I understand what you wrote before, I really dont have to convert the output to voltage first ?


..Another thing, its very hard to test this stuff.. how do I create a known pressure ? ..I know that the car repairers have a little thing that they use to create pressure or vaccuum witha meter on it, but I guess they are expensive.

Acetronics2
- 19th April 2009, 15:27
Hi,

At First :



Vout = Vs* (0.00369*P + 0.04) ± Error

..Wich I thought would be the same as

calcpress = ((( pressure / Vs ) - 0.04 ) / 0.00396 )


Don't you see something strange ??? ...




I want the value in kPa or Bar.


You will display Bars or KPa ... but certainly not calculate with Bars or KPa ...

May be calculate with Pa ... will give a decent result.

BUT ... wouldn't it be best to work with ADC Units ( 0 -1023 ...) and ONLY convert to Pressure for display purposes.


Alain

ScaleRobotics
- 19th April 2009, 18:58
how do I do that ? ( value * (505 /2 )) ?

Well, that is the easy part:

result = (value * 505)/2

or

result = value * 505
result = result / 2



Reading the Pressure sensors datsheet I found:

Vout = Vs* (0.00369*P + 0.04) ± Error

..Wich I thought would be the same as

calcpress = ((( pressure / Vs ) - 0.04 ) / 0.00396 )


That does not quite work. Here is the way to test it:
Look at the data sheet where it says 2.5 volts, and check out how much pressure it takes to get it there. Looking down, it shows 130 kPa. Using Vs as 5 for 5v we can multiply it out.

top equation result is 2.5985v
your equation result is 7,035.23v (wear some good personal protective equipment for that)

Also, if I understand what you wrote before, I really dont have to convert the output to voltage first ?

Voltage is voltage. If we change both side of the equation to mv, v, or a/d steps, we are good.

I will have to think a while how to convert the equation to something easier. But, if I use the handy dandy program that Alain linked above, we can find that 1/271 = .00369

So if I do some math (must be done to the .04 as well as the .00369*P) I eventually (after a few mistakes of course.....)

Result = vs * (((25*Pressure) + 271)/6775)

This comes about by solving for 1/271*P + 1/25

First I multiply by 271 .... so....

(271/271*p + 271/25)/271

Then I multiply all by 25 to get rid of the fraction

since 271/271 = 1
(25*P + 271)/(25 * 271)

or
(25 *P +271)/6775

We can test this using the same method as I tested yours. I caught about 5 of my errors this way, before I go the right answer....

ScaleRobotics
- 19th April 2009, 20:44
Ok, I needed an intermission for this one.

So we are left with the equation:
____________________________________
definitions:
result (analog result from A/D conversion)
P (pressure in kPa)
VS (voltage supply ie 1024)
____________________________________

result = VS * (((25 * P) + 271) / 6775)

So to start solving for P .....

result * 6775 = VS * ((25 * P) + 271)

(result * 6775) / VS = 25 * P + 271

((result * 6775) / VS) - 271 = 25 * P

(((result * 6775) / VS) - 271) / 25 = P

Or P = (((result * 6775) / VS) - 271) / 25

It only hurts a little when I try to figure these things out. I suppose the more you do it, the less it hurts. Or if you are a math guru, maybe this is fun. You guys are sick!

ScaleRobotics
- 20th April 2009, 00:53
Darrel pointed out that I could further reduce the equation, and I had the following error:

The range for A/D conversion is only from 0 to 1023, not 1024 like I had stated. Alain caught that too, but I missed that.

So to further simplify the equation (notice how complicated it is to simplify things?)

We start with the same thing we ended with in the last post.

P = (((result * 6775) / VS) - 271) / 25

Put in the known high range value for VS

P = (((result * 6775) / 1023) - 271) / 25

Don't be afraid of the decimals here ....

Dividing by 25 we get:

P = (((result * 271) / 1023) - 10.84)

271/1023 = .2649

P = (result * .2649) - 10.84

We can get there by .... (Thanks again Darrel!)


ADCIN 0, result
Pressure = result * 2649
Pressure = DIV32 1000
Pressure = Pressure - 108

LCDOUT DEC Pressure/10,".",DEC Pressure//10
The above code converts the .2649 to 2.649 by multiplying result * 2649, then dividing by 1000. It subtracts 10 x the 10.84 which averages out to 108. so the division by 10, and the remainder from the division by 10 can give accurate results.

And we can do all this without using slow, bloated, floating point code, available here:

<A Href="http://www.melabs.com/resources/fp.htm">Using Microchip's <b>Floating</b> Point routines with PicBasic Pro Compiler</a>

ScaleRobotics
- 20th April 2009, 02:31
Ok, that was pretty bassackwards. If anyone followed all that, I don't know whether to feel sorry for you, or commend you. Sorry to wast all that space. Wish I could edit, or even better delete...

Here is the "simple" way.....

Known equation from the data sheet:
Vout = Vs* (0.00369*P + 0.04)

using 1/271 = .00369, and dividing both sides by .00369

Vout * 271 = VS * (P + (.04/.00369))
or Vout * 271 = VS * (P + 10.84)

Vout * 271 / VS = P +10.84

(Vout * 271 / VS) - 10.84 = P

(Vout * (271 / 1023)) - 10.84 = P

(Vout * .2649) - 10.84 = P

But, again, the program that Alain pointed to in one of the above posts is useful to find a fraction to represent .00369.

Hopefully this is much cleaner to follow. It still yields the same result, just possibly less excedrin.

Darrel Taylor
- 20th April 2009, 03:13
Since you arrived at the same conclusion.

Does it really matter how you got there?

Factoring polynomials is more of an Art.
There's almost always more than one way to get there.

Nice work Walter!
<br>

thronborg
- 27th March 2011, 06:29
Hello
Thanks for all the good tips and trick here it has helped me a lot. I think this is the right tread to put this.

I am making an analogue Amp Instrument with a Servo with an arrow that shows the +10 to -10 Amp. Its for an old style motorbike.

I have an Allegro Current Sensor, represented by Pot ASC714. The ASC714 Zero IN current give an output of 2.5V. I want the span to be between +10 Amps to -10 Amps. Each Amp out of the sensor =66mV. The output is:
+10A=3.16V=255
0A=2.5V=127
-10A=1.84V=0

I use only 8bit A/D and a PIC16F887.
I have set Vref+ to 3.16V and Vref- to 1.84V
At first sight it look that its working fine. But after some jogging with the pot it sometimes count up instead of down and vice versa. I think it has something with the Div32 to do and that i overflow it but cant figure out how to correct this.

Thankful for all solutions
Ole Thronborg


'************************************************* ***************
'* Name : Amp887.BAS *
'* Date : 17/3/2011 *
'* Notes : Read ASC714, Out LCD +-10A and move Servo *
'* Show value in bit and Amp on LCD display
'* For PIC16F887 *
'* For standard servo settings 1-2mS set LOW_servo con 100 *
'* and HIGH_servo CON 200 *
'************************************************* ***************
'Define OSC and ADC
DEFINE OSC 4 ' Set internal Oschillator to 4Mhz
DEFINE ADC_BITS 8 ' Set number of bits in result
DEFINE ADC_CLOCK 2 ' Set clock source (3=rc)
DEFINE ADC_SAMPLEUS 50 ' Set sampling time in uS

' Define LCD pins
Define LCD_DREG PORTD 'LCD data port
Define LCD_DBIT 0 'LCD data starting bit 0 or 4
Define LCD_RSREG PORTD 'LCD register select port
Define LCD_RSBIT 4 'LCD register select bit
Define LCD_EREG PORTD 'LCD enable port
Define LCD_EBIT 5 'LCD enable bit

TRISA = %00001101 ' RA0 = A/D input
ADCON1.7 = 0 ' RA.1 = +Vref, Set PORTA analog and left justify result
ADCON1.5=1 ' Set Vref- to pin 5
ADCON1.4=1 ' Set Vref+ to pin 4
PORTb.6 =0 ' Prepare RB0 for high-going pulseout

ANSEL = %00001101 ' Set PORTA.2 analog, rest digital
'ANSELH = %00000000

' Variables
outpuls VAR byte ' Variable for the calculated puls out in mS
POT_POS VAR BYTE ' Pot position CC=0, CCW=255
ampdum VAR Word ' A dummy to canculate big values
amp var word ' Calculating Ampere
LEFT CON 90 ' Left Stop position 0.70mS
RIGHT CON 163 ' Right Stop position 2.1mS

'Pause 700 ' Wait for LCD to start

MainLoop: ' The Loop start here!
ADCIN 0,POT_POS ' Read A/D channel 0 to variable SVO_POS
IF POT_POS>127 then ' Check if positive
ampdum=(7874* (POT_POS-128)) ' Then calculate the dummy
amp= div32 100 ' Let amp get the dummy value
else
ampdum=(7874 * (127-POT_POS)) ' Now it must be negative Amp so calculate
amp= div32 100 ' Let amp get the dummy value
endif ' End of test if Amp negative

'Output to LCD
Lcdout $fe, 1, "POT_POS= ", #POT_POS ' Display POT Valu between 0-255 on line 1
IF POT_POS>=127 then ' Check if + Ampere Else goto - Ampere
LCDOut $fe,$C0, "AMP= ",DEC (amp/1000),".", DEC1 amp' Display pulswith in mS on line 2
else
LCDOut $fe,$C0, "AMP= -",DEC (amp/1000),".", DEC1 amp' Display pulswith in mS on line 2
endif

'outpuls =100+(POT_POS *100/255) 'Calculate the outpuls in mS
'IF outpuls < LEFT THEN outpuls = LEFT ' Stop if puls shorter than constant LEFT
'IF outpuls > RIGHT THEN outpuls = RIGHT ' Stop if puls shorter than constant RIGHT
' Span 100 gives 100+100 = 200=2mS 150 is center
'PULSOUT portb.6 ,outpuls ' Move servo on pin
'PAUSE 20 ' Constant 20mS pulses(low) between outpuls
'GOTO MainLoop ' Forever
End

5307